1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.am; 18 19 import static android.app.ActivityManager.RESIZE_MODE_FORCED; 20 import static android.app.ActivityManager.RESIZE_MODE_SYSTEM; 21 import static android.app.ActivityManager.StackId.INVALID_STACK_ID; 22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 23 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 24 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 25 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 26 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 27 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 28 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 29 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; 30 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 31 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; 32 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; 33 import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; 34 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; 35 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; 36 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; 37 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; 38 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; 39 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; 40 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; 41 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; 42 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 43 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED; 44 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 45 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; 46 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; 47 import static android.view.Display.DEFAULT_DISPLAY; 48 49 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE; 50 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK; 51 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS; 52 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS; 53 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE; 54 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK; 55 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS; 56 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS; 57 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 58 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; 59 import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN; 60 import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING; 61 import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP; 62 import static com.android.server.am.ActivityStackSupervisor.ON_TOP; 63 import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY; 64 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; 65 import static com.android.server.am.TaskRecordProto.ACTIVITIES; 66 import static com.android.server.am.TaskRecordProto.BOUNDS; 67 import static com.android.server.am.TaskRecordProto.CONFIGURATION_CONTAINER; 68 import static com.android.server.am.TaskRecordProto.FULLSCREEN; 69 import static com.android.server.am.TaskRecordProto.ID; 70 import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS; 71 import static com.android.server.am.TaskRecordProto.MIN_HEIGHT; 72 import static com.android.server.am.TaskRecordProto.MIN_WIDTH; 73 import static com.android.server.am.TaskRecordProto.ORIG_ACTIVITY; 74 import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY; 75 import static com.android.server.am.TaskRecordProto.RESIZE_MODE; 76 import static com.android.server.am.TaskRecordProto.STACK_ID; 77 import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE; 78 79 import static java.lang.Integer.MAX_VALUE; 80 81 import android.annotation.IntDef; 82 import android.annotation.Nullable; 83 import android.app.Activity; 84 import android.app.ActivityManager; 85 import android.app.ActivityManager.TaskDescription; 86 import android.app.ActivityManager.TaskSnapshot; 87 import android.app.ActivityOptions; 88 import android.app.AppGlobals; 89 import android.app.IActivityManager; 90 import android.content.ComponentName; 91 import android.content.Intent; 92 import android.content.pm.ActivityInfo; 93 import android.content.pm.ApplicationInfo; 94 import android.content.pm.IPackageManager; 95 import android.content.pm.PackageManager; 96 import android.content.res.Configuration; 97 import android.graphics.Rect; 98 import android.os.Debug; 99 import android.os.RemoteException; 100 import android.os.SystemClock; 101 import android.os.Trace; 102 import android.os.UserHandle; 103 import android.provider.Settings; 104 import android.service.voice.IVoiceInteractionSession; 105 import android.util.DisplayMetrics; 106 import android.util.Slog; 107 import android.util.proto.ProtoOutputStream; 108 109 import com.android.internal.annotations.VisibleForTesting; 110 import com.android.internal.app.IVoiceInteractor; 111 import com.android.internal.util.XmlUtils; 112 import com.android.server.am.ActivityStack.ActivityState; 113 import com.android.server.wm.AppWindowContainerController; 114 import com.android.server.wm.ConfigurationContainer; 115 import com.android.server.wm.StackWindowController; 116 import com.android.server.wm.TaskWindowContainerController; 117 import com.android.server.wm.TaskWindowContainerListener; 118 import com.android.server.wm.WindowManagerService; 119 120 import org.xmlpull.v1.XmlPullParser; 121 import org.xmlpull.v1.XmlPullParserException; 122 import org.xmlpull.v1.XmlSerializer; 123 124 import java.io.IOException; 125 import java.io.PrintWriter; 126 import java.lang.annotation.Retention; 127 import java.lang.annotation.RetentionPolicy; 128 import java.util.ArrayList; 129 import java.util.Objects; 130 131 class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener { 132 private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM; 133 private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; 134 private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; 135 private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK; 136 private static final String TAG_TASKS = TAG + POSTFIX_TASKS; 137 138 private static final String ATTR_TASKID = "task_id"; 139 private static final String TAG_INTENT = "intent"; 140 private static final String TAG_AFFINITYINTENT = "affinity_intent"; 141 private static final String ATTR_REALACTIVITY = "real_activity"; 142 private static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended"; 143 private static final String ATTR_ORIGACTIVITY = "orig_activity"; 144 private static final String TAG_ACTIVITY = "activity"; 145 private static final String ATTR_AFFINITY = "affinity"; 146 private static final String ATTR_ROOT_AFFINITY = "root_affinity"; 147 private static final String ATTR_ROOTHASRESET = "root_has_reset"; 148 private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents"; 149 private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode"; 150 private static final String ATTR_USERID = "user_id"; 151 private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete"; 152 private static final String ATTR_EFFECTIVE_UID = "effective_uid"; 153 @Deprecated 154 private static final String ATTR_TASKTYPE = "task_type"; 155 private static final String ATTR_LASTDESCRIPTION = "last_description"; 156 private static final String ATTR_LASTTIMEMOVED = "last_time_moved"; 157 private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity"; 158 private static final String ATTR_TASK_AFFILIATION = "task_affiliation"; 159 private static final String ATTR_PREV_AFFILIATION = "prev_affiliation"; 160 private static final String ATTR_NEXT_AFFILIATION = "next_affiliation"; 161 private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color"; 162 private static final String ATTR_CALLING_UID = "calling_uid"; 163 private static final String ATTR_CALLING_PACKAGE = "calling_package"; 164 private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture"; 165 private static final String ATTR_RESIZE_MODE = "resize_mode"; 166 private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds"; 167 private static final String ATTR_MIN_WIDTH = "min_width"; 168 private static final String ATTR_MIN_HEIGHT = "min_height"; 169 private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version"; 170 171 // Current version of the task record we persist. Used to check if we need to run any upgrade 172 // code. 173 private static final int PERSIST_TASK_VERSION = 1; 174 175 static final int INVALID_TASK_ID = -1; 176 private static final int INVALID_MIN_SIZE = -1; 177 178 /** 179 * The modes to control how the stack is moved to the front when calling 180 * {@link TaskRecord#reparent}. 181 */ 182 @Retention(RetentionPolicy.SOURCE) 183 @IntDef({ 184 REPARENT_MOVE_STACK_TO_FRONT, 185 REPARENT_KEEP_STACK_AT_FRONT, 186 REPARENT_LEAVE_STACK_IN_PLACE 187 }) 188 @interface ReparentMoveStackMode {} 189 // Moves the stack to the front if it was not at the front 190 static final int REPARENT_MOVE_STACK_TO_FRONT = 0; 191 // Only moves the stack to the front if it was focused or front most already 192 static final int REPARENT_KEEP_STACK_AT_FRONT = 1; 193 // Do not move the stack as a part of reparenting 194 static final int REPARENT_LEAVE_STACK_IN_PLACE = 2; 195 196 /** 197 * The factory used to create {@link TaskRecord}. This allows OEM subclass {@link TaskRecord}. 198 */ 199 private static TaskRecordFactory sTaskRecordFactory; 200 201 final int taskId; // Unique identifier for this task. 202 String affinity; // The affinity name for this task, or null; may change identity. 203 String rootAffinity; // Initial base affinity, or null; does not change from initial root. 204 final IVoiceInteractionSession voiceSession; // Voice interaction session driving task 205 final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app 206 Intent intent; // The original intent that started the task. Note that this value can 207 // be null. 208 Intent affinityIntent; // Intent of affinity-moved activity that started this task. 209 int effectiveUid; // The current effective uid of the identity of this task. 210 ComponentName origActivity; // The non-alias activity component of the intent. 211 ComponentName realActivity; // The actual activity component that started the task. 212 boolean realActivitySuspended; // True if the actual activity component that started the 213 // task is suspended. 214 boolean inRecents; // Actually in the recents list? 215 long lastActiveTime; // Last time this task was active in the current device session, 216 // including sleep. This time is initialized to the elapsed time when 217 // restored from disk. 218 boolean isAvailable; // Is the activity available to be launched? 219 boolean rootWasReset; // True if the intent at the root of the task had 220 // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag. 221 boolean autoRemoveRecents; // If true, we should automatically remove the task from 222 // recents when activity finishes 223 boolean askedCompatMode;// Have asked the user about compat mode for this task. 224 boolean hasBeenVisible; // Set if any activities in the task have been visible to the user. 225 226 String stringName; // caching of toString() result. 227 int userId; // user for which this task was created 228 boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity 229 // was changed. 230 231 int numFullscreen; // Number of fullscreen activities. 232 233 int mResizeMode; // The resize mode of this task and its activities. 234 // Based on the {@link ActivityInfo#resizeMode} of the root activity. 235 private boolean mSupportsPictureInPicture; // Whether or not this task and its activities 236 // support PiP. Based on the {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag 237 // of the root activity. 238 /** Can't be put in lockTask mode. */ 239 final static int LOCK_TASK_AUTH_DONT_LOCK = 0; 240 /** Can enter app pinning with user approval. Can never start over existing lockTask task. */ 241 final static int LOCK_TASK_AUTH_PINNABLE = 1; 242 /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */ 243 final static int LOCK_TASK_AUTH_LAUNCHABLE = 2; 244 /** Can enter lockTask without user approval. Can start over existing lockTask task. */ 245 final static int LOCK_TASK_AUTH_WHITELISTED = 3; 246 /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing 247 * lockTask task. */ 248 final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4; 249 int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE; 250 251 int mLockTaskUid = -1; // The uid of the application that called startLockTask(). 252 253 // This represents the last resolved activity values for this task 254 // NOTE: This value needs to be persisted with each task 255 TaskDescription lastTaskDescription = new TaskDescription(); 256 257 /** List of all activities in the task arranged in history order */ 258 final ArrayList<ActivityRecord> mActivities; 259 260 /** Current stack. Setter must always be used to update the value. */ 261 private ActivityStack mStack; 262 263 /** The process that had previously hosted the root activity of this task. 264 * Used to know that we should try harder to keep this process around, in case the 265 * user wants to return to it. */ 266 private ProcessRecord mRootProcess; 267 268 /** Takes on same value as first root activity */ 269 boolean isPersistable = false; 270 int maxRecents; 271 272 /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for 273 * determining the order when restoring. Sign indicates whether last task movement was to front 274 * (positive) or back (negative). Absolute value indicates time. */ 275 long mLastTimeMoved = System.currentTimeMillis(); 276 277 /** If original intent did not allow relinquishing task identity, save that information */ 278 private boolean mNeverRelinquishIdentity = true; 279 280 // Used in the unique case where we are clearing the task in order to reuse it. In that case we 281 // do not want to delete the stack when the task goes empty. 282 private boolean mReuseTask = false; 283 284 CharSequence lastDescription; // Last description captured for this item. 285 286 int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent. 287 int mAffiliatedTaskColor; // color of the parent task affiliation. 288 TaskRecord mPrevAffiliate; // previous task in affiliated chain. 289 int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence. 290 TaskRecord mNextAffiliate; // next task in affiliated chain. 291 int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence. 292 293 // For relaunching the task from recents as though it was launched by the original launcher. 294 int mCallingUid; 295 String mCallingPackage; 296 297 final ActivityManagerService mService; 298 299 private final Rect mTmpStableBounds = new Rect(); 300 private final Rect mTmpNonDecorBounds = new Rect(); 301 private final Rect mTmpRect = new Rect(); 302 303 // Last non-fullscreen bounds the task was launched in or resized to. 304 // The information is persisted and used to determine the appropriate stack to launch the 305 // task into on restore. 306 Rect mLastNonFullscreenBounds = null; 307 // Minimal width and height of this task when it's resizeable. -1 means it should use the 308 // default minimal width/height. 309 int mMinWidth; 310 int mMinHeight; 311 312 // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible) 313 // This number will be assigned when we evaluate OOM scores for all visible tasks. 314 int mLayerRank = -1; 315 316 /** Helper object used for updating override configuration. */ 317 private Configuration mTmpConfig = new Configuration(); 318 319 private TaskWindowContainerController mWindowContainerController; 320 321 /** 322 * Don't use constructor directly. Use {@link #create(ActivityManagerService, int, ActivityInfo, 323 * Intent, TaskDescription)} instead. 324 */ TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor)325 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, 326 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) { 327 mService = service; 328 userId = UserHandle.getUserId(info.applicationInfo.uid); 329 taskId = _taskId; 330 lastActiveTime = SystemClock.elapsedRealtime(); 331 mAffiliatedTaskId = _taskId; 332 voiceSession = _voiceSession; 333 voiceInteractor = _voiceInteractor; 334 isAvailable = true; 335 mActivities = new ArrayList<>(); 336 mCallingUid = info.applicationInfo.uid; 337 mCallingPackage = info.packageName; 338 setIntent(_intent, info); 339 setMinDimensions(info); 340 touchActiveTime(); 341 mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity); 342 } 343 344 /** 345 * Don't use constructor directly. Use {@link #create(ActivityManagerService, int, ActivityInfo, 346 * Intent, IVoiceInteractionSession, IVoiceInteractor)} instead. 347 */ TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, TaskDescription _taskDescription)348 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, 349 TaskDescription _taskDescription) { 350 mService = service; 351 userId = UserHandle.getUserId(info.applicationInfo.uid); 352 taskId = _taskId; 353 lastActiveTime = SystemClock.elapsedRealtime(); 354 mAffiliatedTaskId = _taskId; 355 voiceSession = null; 356 voiceInteractor = null; 357 isAvailable = true; 358 mActivities = new ArrayList<>(); 359 mCallingUid = info.applicationInfo.uid; 360 mCallingPackage = info.packageName; 361 setIntent(_intent, info); 362 setMinDimensions(info); 363 364 isPersistable = true; 365 // Clamp to [1, max]. 366 maxRecents = Math.min(Math.max(info.maxRecents, 1), 367 ActivityManager.getMaxAppRecentsLimitStatic()); 368 369 lastTaskDescription = _taskDescription; 370 touchActiveTime(); 371 mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity); 372 } 373 374 /** 375 * Don't use constructor directly. This is only used by XML parser. 376 */ TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, Intent _affinityIntent, String _affinity, String _rootAffinity, ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities, long lastTimeMoved, boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight)377 TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, 378 Intent _affinityIntent, String _affinity, String _rootAffinity, 379 ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, 380 boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, 381 int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities, 382 long lastTimeMoved, boolean neverRelinquishIdentity, 383 TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId, 384 int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, 385 int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended, 386 boolean userSetupComplete, int minWidth, int minHeight) { 387 mService = service; 388 taskId = _taskId; 389 intent = _intent; 390 affinityIntent = _affinityIntent; 391 affinity = _affinity; 392 rootAffinity = _rootAffinity; 393 voiceSession = null; 394 voiceInteractor = null; 395 realActivity = _realActivity; 396 realActivitySuspended = _realActivitySuspended; 397 origActivity = _origActivity; 398 rootWasReset = _rootWasReset; 399 isAvailable = true; 400 autoRemoveRecents = _autoRemoveRecents; 401 askedCompatMode = _askedCompatMode; 402 userId = _userId; 403 mUserSetupComplete = userSetupComplete; 404 effectiveUid = _effectiveUid; 405 lastActiveTime = SystemClock.elapsedRealtime(); 406 lastDescription = _lastDescription; 407 mActivities = activities; 408 mLastTimeMoved = lastTimeMoved; 409 mNeverRelinquishIdentity = neverRelinquishIdentity; 410 lastTaskDescription = _lastTaskDescription; 411 mAffiliatedTaskId = taskAffiliation; 412 mAffiliatedTaskColor = taskAffiliationColor; 413 mPrevAffiliateTaskId = prevTaskId; 414 mNextAffiliateTaskId = nextTaskId; 415 mCallingUid = callingUid; 416 mCallingPackage = callingPackage; 417 mResizeMode = resizeMode; 418 mSupportsPictureInPicture = supportsPictureInPicture; 419 mMinWidth = minWidth; 420 mMinHeight = minHeight; 421 mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity); 422 } 423 getWindowContainerController()424 TaskWindowContainerController getWindowContainerController() { 425 return mWindowContainerController; 426 } 427 createWindowContainer(boolean onTop, boolean showForAllUsers)428 void createWindowContainer(boolean onTop, boolean showForAllUsers) { 429 if (mWindowContainerController != null) { 430 throw new IllegalArgumentException("Window container=" + mWindowContainerController 431 + " already created for task=" + this); 432 } 433 434 final Rect bounds = updateOverrideConfigurationFromLaunchBounds(); 435 setWindowContainerController(new TaskWindowContainerController(taskId, this, 436 getStack().getWindowContainerController(), userId, bounds, 437 mResizeMode, mSupportsPictureInPicture, onTop, 438 showForAllUsers, lastTaskDescription)); 439 } 440 441 /** 442 * Should only be invoked from {@link #createWindowContainer(boolean, boolean)}. 443 */ 444 @VisibleForTesting setWindowContainerController(TaskWindowContainerController controller)445 protected void setWindowContainerController(TaskWindowContainerController controller) { 446 if (mWindowContainerController != null) { 447 throw new IllegalArgumentException("Window container=" + mWindowContainerController 448 + " already created for task=" + this); 449 } 450 451 mWindowContainerController = controller; 452 } 453 removeWindowContainer()454 void removeWindowContainer() { 455 mService.getLockTaskController().clearLockedTask(this); 456 mWindowContainerController.removeContainer(); 457 if (!getWindowConfiguration().persistTaskBounds()) { 458 // Reset current bounds for task whose bounds shouldn't be persisted so it uses 459 // default configuration the next time it launches. 460 updateOverrideConfiguration(null); 461 } 462 mService.mTaskChangeNotificationController.notifyTaskRemoved(taskId); 463 mWindowContainerController = null; 464 } 465 466 @Override onSnapshotChanged(TaskSnapshot snapshot)467 public void onSnapshotChanged(TaskSnapshot snapshot) { 468 mService.mTaskChangeNotificationController.notifyTaskSnapshotChanged(taskId, snapshot); 469 } 470 setResizeMode(int resizeMode)471 void setResizeMode(int resizeMode) { 472 if (mResizeMode == resizeMode) { 473 return; 474 } 475 mResizeMode = resizeMode; 476 mWindowContainerController.setResizeable(resizeMode); 477 mService.mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); 478 mService.mStackSupervisor.resumeFocusedStackTopActivityLocked(); 479 } 480 setTaskDockedResizing(boolean resizing)481 void setTaskDockedResizing(boolean resizing) { 482 mWindowContainerController.setTaskDockedResizing(resizing); 483 } 484 485 // TODO: Consolidate this with the resize() method below. 486 @Override requestResize(Rect bounds, int resizeMode)487 public void requestResize(Rect bounds, int resizeMode) { 488 mService.resizeTask(taskId, bounds, resizeMode); 489 } 490 resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume)491 boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) { 492 mService.mWindowManager.deferSurfaceLayout(); 493 494 try { 495 if (!isResizeable()) { 496 Slog.w(TAG, "resizeTask: task " + this + " not resizeable."); 497 return true; 498 } 499 500 // If this is a forced resize, let it go through even if the bounds is not changing, 501 // as we might need a relayout due to surface size change (to/from fullscreen). 502 final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0; 503 if (equivalentOverrideBounds(bounds) && !forced) { 504 // Nothing to do here... 505 return true; 506 } 507 508 if (mWindowContainerController == null) { 509 // Task doesn't exist in window manager yet (e.g. was restored from recents). 510 // All we can do for now is update the bounds so it can be used when the task is 511 // added to window manager. 512 updateOverrideConfiguration(bounds); 513 if (!inFreeformWindowingMode()) { 514 // re-restore the task so it can have the proper stack association. 515 mService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP); 516 } 517 return true; 518 } 519 520 if (!canResizeToBounds(bounds)) { 521 throw new IllegalArgumentException("resizeTask: Can not resize task=" + this 522 + " to bounds=" + bounds + " resizeMode=" + mResizeMode); 523 } 524 525 // Do not move the task to another stack here. 526 // This method assumes that the task is already placed in the right stack. 527 // we do not mess with that decision and we only do the resize! 528 529 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + taskId); 530 531 final boolean updatedConfig = updateOverrideConfiguration(bounds); 532 // This variable holds information whether the configuration didn't change in a significant 533 534 // way and the activity was kept the way it was. If it's false, it means the activity 535 // had 536 // to be relaunched due to configuration change. 537 boolean kept = true; 538 if (updatedConfig) { 539 final ActivityRecord r = topRunningActivityLocked(); 540 if (r != null && !deferResume) { 541 kept = r.ensureActivityConfiguration(0 /* globalChanges */, 542 preserveWindow); 543 mService.mStackSupervisor.ensureActivitiesVisibleLocked(r, 0, 544 !PRESERVE_WINDOWS); 545 if (!kept) { 546 mService.mStackSupervisor.resumeFocusedStackTopActivityLocked(); 547 } 548 } 549 } 550 mWindowContainerController.resize(kept, forced); 551 552 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); 553 return kept; 554 } finally { 555 mService.mWindowManager.continueSurfaceLayout(); 556 } 557 } 558 559 // TODO: Investigate combining with the resize() method above. resizeWindowContainer()560 void resizeWindowContainer() { 561 mWindowContainerController.resize(false /* relayout */, false /* forced */); 562 } 563 getWindowContainerBounds(Rect bounds)564 void getWindowContainerBounds(Rect bounds) { 565 mWindowContainerController.getBounds(bounds); 566 } 567 568 /** 569 * Convenience method to reparent a task to the top or bottom position of the stack. 570 */ reparent(ActivityStack preferredStack, boolean toTop, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, String reason)571 boolean reparent(ActivityStack preferredStack, boolean toTop, 572 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, 573 String reason) { 574 return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume, 575 true /* schedulePictureInPictureModeChange */, reason); 576 } 577 578 /** 579 * Convenience method to reparent a task to the top or bottom position of the stack, with 580 * an option to skip scheduling the picture-in-picture mode change. 581 */ reparent(ActivityStack preferredStack, boolean toTop, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, String reason)582 boolean reparent(ActivityStack preferredStack, boolean toTop, 583 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, 584 boolean schedulePictureInPictureModeChange, String reason) { 585 return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, 586 deferResume, schedulePictureInPictureModeChange, reason); 587 } 588 589 /** Convenience method to reparent a task to a specific position of the stack. */ reparent(ActivityStack preferredStack, int position, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, String reason)590 boolean reparent(ActivityStack preferredStack, int position, 591 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, 592 String reason) { 593 return reparent(preferredStack, position, moveStackMode, animate, deferResume, 594 true /* schedulePictureInPictureModeChange */, reason); 595 } 596 597 /** 598 * Reparents the task into a preferred stack, creating it if necessary. 599 * 600 * @param preferredStack the target stack to move this task 601 * @param position the position to place this task in the new stack 602 * @param animate whether or not we should wait for the new window created as a part of the 603 * reparenting to be drawn and animated in 604 * @param moveStackMode whether or not to move the stack to the front always, only if it was 605 * previously focused & in front, or never 606 * @param deferResume whether or not to update the visibility of other tasks and stacks that may 607 * have changed as a result of this reparenting 608 * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode 609 * change. Callers may set this to false if they are explicitly scheduling PiP mode 610 * changes themselves, like during the PiP animation 611 * @param reason the caller of this reparenting 612 * @return whether the task was reparented 613 */ 614 // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs. 615 // re-parenting the task. Can only be done when we are no longer using static stack Ids. reparent(ActivityStack preferredStack, int position, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, String reason)616 boolean reparent(ActivityStack preferredStack, int position, 617 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, 618 boolean schedulePictureInPictureModeChange, String reason) { 619 final ActivityStackSupervisor supervisor = mService.mStackSupervisor; 620 final WindowManagerService windowManager = mService.mWindowManager; 621 final ActivityStack sourceStack = getStack(); 622 final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack, 623 position == MAX_VALUE); 624 if (toStack == sourceStack) { 625 return false; 626 } 627 if (!canBeLaunchedOnDisplay(toStack.mDisplayId)) { 628 return false; 629 } 630 631 final int toStackWindowingMode = toStack.getWindowingMode(); 632 final ActivityRecord topActivity = getTopActivity(); 633 634 final boolean mightReplaceWindow = topActivity != null 635 && replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode); 636 if (mightReplaceWindow) { 637 // We are about to relaunch the activity because its configuration changed due to 638 // being maximized, i.e. size change. The activity will first remove the old window 639 // and then add a new one. This call will tell window manager about this, so it can 640 // preserve the old window until the new one is drawn. This prevents having a gap 641 // between the removal and addition, in which no window is visible. We also want the 642 // entrance of the new window to be properly animated. 643 // Note here we always set the replacing window first, as the flags might be needed 644 // during the relaunch. If we end up not doing any relaunch, we clear the flags later. 645 windowManager.setWillReplaceWindow(topActivity.appToken, animate); 646 } 647 648 windowManager.deferSurfaceLayout(); 649 boolean kept = true; 650 try { 651 final ActivityRecord r = topRunningActivityLocked(); 652 final boolean wasFocused = r != null && supervisor.isFocusedStack(sourceStack) 653 && (topRunningActivityLocked() == r); 654 final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r; 655 final boolean wasPaused = r != null && sourceStack.mPausingActivity == r; 656 657 // In some cases the focused stack isn't the front stack. E.g. pinned stack. 658 // Whenever we are moving the top activity from the front stack we want to make sure to 659 // move the stack to the front. 660 final boolean wasFront = r != null && sourceStack.isTopStackOnDisplay() 661 && (sourceStack.topRunningActivityLocked() == r); 662 663 // Adjust the position for the new parent stack as needed. 664 position = toStack.getAdjustedPositionForTask(this, position, null /* starting */); 665 666 // Must reparent first in window manager to avoid a situation where AM can delete the 667 // we are coming from in WM before we reparent because it became empty. 668 mWindowContainerController.reparent(toStack.getWindowContainerController(), position, 669 moveStackMode == REPARENT_MOVE_STACK_TO_FRONT); 670 671 final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT 672 || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront)); 673 // Move the task 674 sourceStack.removeTask(this, reason, moveStackToFront 675 ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING); 676 toStack.addTask(this, position, false /* schedulePictureInPictureModeChange */, reason); 677 678 if (schedulePictureInPictureModeChange) { 679 // Notify of picture-in-picture mode changes 680 supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack); 681 } 682 683 // TODO: Ensure that this is actually necessary here 684 // Notify the voice session if required 685 if (voiceSession != null) { 686 try { 687 voiceSession.taskStarted(intent, taskId); 688 } catch (RemoteException e) { 689 } 690 } 691 692 // If the task had focus before (or we're requested to move focus), move focus to the 693 // new stack by moving the stack to the front. 694 if (r != null) { 695 toStack.moveToFrontAndResumeStateIfNeeded(r, moveStackToFront, wasResumed, 696 wasPaused, reason); 697 } 698 if (!animate) { 699 mService.mStackSupervisor.mNoAnimActivities.add(topActivity); 700 } 701 702 // We might trigger a configuration change. Save the current task bounds for freezing. 703 // TODO: Should this call be moved inside the resize method in WM? 704 toStack.prepareFreezingTaskBounds(); 705 706 // Make sure the task has the appropriate bounds/size for the stack it is in. 707 final boolean toStackSplitScreenPrimary = 708 toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 709 final Rect configBounds = getOverrideBounds(); 710 if ((toStackWindowingMode == WINDOWING_MODE_FULLSCREEN 711 || toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) 712 && !Objects.equals(configBounds, toStack.getOverrideBounds())) { 713 kept = resize(toStack.getOverrideBounds(), RESIZE_MODE_SYSTEM, !mightReplaceWindow, 714 deferResume); 715 } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) { 716 Rect bounds = getLaunchBounds(); 717 if (bounds == null) { 718 mService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null); 719 bounds = configBounds; 720 } 721 kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume); 722 } else if (toStackSplitScreenPrimary || toStackWindowingMode == WINDOWING_MODE_PINNED) { 723 if (toStackSplitScreenPrimary && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) { 724 // Move recents to front so it is not behind home stack when going into docked 725 // mode 726 mService.mStackSupervisor.moveRecentsStackToFront(reason); 727 } 728 kept = resize(toStack.getOverrideBounds(), RESIZE_MODE_SYSTEM, !mightReplaceWindow, 729 deferResume); 730 } 731 } finally { 732 windowManager.continueSurfaceLayout(); 733 } 734 735 if (mightReplaceWindow) { 736 // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old 737 // window), we need to clear the replace window settings. Otherwise, we schedule a 738 // timeout to remove the old window if the replacing window is not coming in time. 739 windowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept); 740 } 741 742 if (!deferResume) { 743 // The task might have already been running and its visibility needs to be synchronized 744 // with the visibility of the stack / windows. 745 supervisor.ensureActivitiesVisibleLocked(null, 0, !mightReplaceWindow); 746 supervisor.resumeFocusedStackTopActivityLocked(); 747 } 748 749 // TODO: Handle incorrect request to move before the actual move, not after. 750 supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(), 751 DEFAULT_DISPLAY, toStack); 752 753 return (preferredStack == toStack); 754 } 755 756 /** 757 * @return True if the windows of tasks being moved to the target stack from the source stack 758 * should be replaced, meaning that window manager will keep the old window around until the new 759 * is ready. 760 */ replaceWindowsOnTaskMove( int sourceWindowingMode, int targetWindowingMode)761 private static boolean replaceWindowsOnTaskMove( 762 int sourceWindowingMode, int targetWindowingMode) { 763 return sourceWindowingMode == WINDOWING_MODE_FREEFORM 764 || targetWindowingMode == WINDOWING_MODE_FREEFORM; 765 } 766 cancelWindowTransition()767 void cancelWindowTransition() { 768 mWindowContainerController.cancelWindowTransition(); 769 } 770 771 /** 772 * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD! 773 */ getSnapshot(boolean reducedResolution)774 TaskSnapshot getSnapshot(boolean reducedResolution) { 775 776 // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more 777 // synchronized between AM and WM. 778 return mService.mWindowManager.getTaskSnapshot(taskId, userId, reducedResolution); 779 } 780 touchActiveTime()781 void touchActiveTime() { 782 lastActiveTime = SystemClock.elapsedRealtime(); 783 } 784 getInactiveDuration()785 long getInactiveDuration() { 786 return SystemClock.elapsedRealtime() - lastActiveTime; 787 } 788 789 /** Sets the original intent, and the calling uid and package. */ setIntent(ActivityRecord r)790 void setIntent(ActivityRecord r) { 791 mCallingUid = r.launchedFromUid; 792 mCallingPackage = r.launchedFromPackage; 793 setIntent(r.intent, r.info); 794 setLockTaskAuth(r); 795 } 796 797 /** Sets the original intent, _without_ updating the calling uid or package. */ setIntent(Intent _intent, ActivityInfo info)798 private void setIntent(Intent _intent, ActivityInfo info) { 799 if (intent == null) { 800 mNeverRelinquishIdentity = 801 (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0; 802 } else if (mNeverRelinquishIdentity) { 803 return; 804 } 805 806 affinity = info.taskAffinity; 807 if (intent == null) { 808 // If this task already has an intent associated with it, don't set the root 809 // affinity -- we don't want it changing after initially set, but the initially 810 // set value may be null. 811 rootAffinity = affinity; 812 } 813 effectiveUid = info.applicationInfo.uid; 814 stringName = null; 815 816 if (info.targetActivity == null) { 817 if (_intent != null) { 818 // If this Intent has a selector, we want to clear it for the 819 // recent task since it is not relevant if the user later wants 820 // to re-launch the app. 821 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) { 822 _intent = new Intent(_intent); 823 _intent.setSelector(null); 824 _intent.setSourceBounds(null); 825 } 826 } 827 if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent); 828 intent = _intent; 829 realActivity = _intent != null ? _intent.getComponent() : null; 830 origActivity = null; 831 } else { 832 ComponentName targetComponent = new ComponentName( 833 info.packageName, info.targetActivity); 834 if (_intent != null) { 835 Intent targetIntent = new Intent(_intent); 836 targetIntent.setComponent(targetComponent); 837 targetIntent.setSelector(null); 838 targetIntent.setSourceBounds(null); 839 if (DEBUG_TASKS) Slog.v(TAG_TASKS, 840 "Setting Intent of " + this + " to target " + targetIntent); 841 intent = targetIntent; 842 realActivity = targetComponent; 843 origActivity = _intent.getComponent(); 844 } else { 845 intent = null; 846 realActivity = targetComponent; 847 origActivity = new ComponentName(info.packageName, info.name); 848 } 849 } 850 851 final int intentFlags = intent == null ? 0 : intent.getFlags(); 852 if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { 853 // Once we are set to an Intent with this flag, we count this 854 // task as having a true root activity. 855 rootWasReset = true; 856 } 857 userId = UserHandle.getUserId(info.applicationInfo.uid); 858 mUserSetupComplete = Settings.Secure.getIntForUser(mService.mContext.getContentResolver(), 859 USER_SETUP_COMPLETE, 0, userId) != 0; 860 if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) { 861 // If the activity itself has requested auto-remove, then just always do it. 862 autoRemoveRecents = true; 863 } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS)) 864 == FLAG_ACTIVITY_NEW_DOCUMENT) { 865 // If the caller has not asked for the document to be retained, then we may 866 // want to turn on auto-remove, depending on whether the target has set its 867 // own document launch mode. 868 if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) { 869 autoRemoveRecents = false; 870 } else { 871 autoRemoveRecents = true; 872 } 873 } else { 874 autoRemoveRecents = false; 875 } 876 mResizeMode = info.resizeMode; 877 mSupportsPictureInPicture = info.supportsPictureInPicture(); 878 } 879 880 /** Sets the original minimal width and height. */ setMinDimensions(ActivityInfo info)881 private void setMinDimensions(ActivityInfo info) { 882 if (info != null && info.windowLayout != null) { 883 mMinWidth = info.windowLayout.minWidth; 884 mMinHeight = info.windowLayout.minHeight; 885 } else { 886 mMinWidth = INVALID_MIN_SIZE; 887 mMinHeight = INVALID_MIN_SIZE; 888 } 889 } 890 891 /** 892 * Return true if the input activity has the same intent filter as the intent this task 893 * record is based on (normally the root activity intent). 894 */ isSameIntentFilter(ActivityRecord r)895 boolean isSameIntentFilter(ActivityRecord r) { 896 final Intent intent = new Intent(r.intent); 897 // Correct the activity intent for aliasing. The task record intent will always be based on 898 // the real activity that will be launched not the alias, so we need to use an intent with 899 // the component name pointing to the real activity not the alias in the activity record. 900 intent.setComponent(r.realActivity); 901 return intent.filterEquals(this.intent); 902 } 903 returnsToHomeStack()904 boolean returnsToHomeStack() { 905 final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME; 906 return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags; 907 } 908 setPrevAffiliate(TaskRecord prevAffiliate)909 void setPrevAffiliate(TaskRecord prevAffiliate) { 910 mPrevAffiliate = prevAffiliate; 911 mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.taskId; 912 } 913 setNextAffiliate(TaskRecord nextAffiliate)914 void setNextAffiliate(TaskRecord nextAffiliate) { 915 mNextAffiliate = nextAffiliate; 916 mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.taskId; 917 } 918 getStack()919 <T extends ActivityStack> T getStack() { 920 return (T) mStack; 921 } 922 923 /** 924 * Must be used for setting parent stack because it performs configuration updates. 925 * Must be called after adding task as a child to the stack. 926 */ setStack(ActivityStack stack)927 void setStack(ActivityStack stack) { 928 if (stack != null && !stack.isInStackLocked(this)) { 929 throw new IllegalStateException("Task must be added as a Stack child first."); 930 } 931 final ActivityStack oldStack = mStack; 932 mStack = stack; 933 934 // If the new {@link TaskRecord} is from a different {@link ActivityStack}, remove this 935 // {@link ActivityRecord} from its current {@link ActivityStack}. 936 937 if (oldStack != mStack) { 938 for (int i = getChildCount() - 1; i >= 0; --i) { 939 final ActivityRecord activity = getChildAt(i); 940 941 if (oldStack != null) { 942 oldStack.onActivityRemovedFromStack(activity); 943 } 944 945 if (mStack != null) { 946 stack.onActivityAddedToStack(activity); 947 } 948 } 949 } 950 951 onParentChanged(); 952 } 953 954 /** 955 * @return Id of current stack, {@link INVALID_STACK_ID} if no stack is set. 956 */ getStackId()957 int getStackId() { 958 return mStack != null ? mStack.mStackId : INVALID_STACK_ID; 959 } 960 961 @Override getChildCount()962 protected int getChildCount() { 963 return mActivities.size(); 964 } 965 966 @Override getChildAt(int index)967 protected ActivityRecord getChildAt(int index) { 968 return mActivities.get(index); 969 } 970 971 @Override getParent()972 protected ConfigurationContainer getParent() { 973 return mStack; 974 } 975 976 @Override onParentChanged()977 protected void onParentChanged() { 978 super.onParentChanged(); 979 mService.mStackSupervisor.updateUIDsPresentOnDisplay(); 980 } 981 982 // Close up recents linked list. closeRecentsChain()983 private void closeRecentsChain() { 984 if (mPrevAffiliate != null) { 985 mPrevAffiliate.setNextAffiliate(mNextAffiliate); 986 } 987 if (mNextAffiliate != null) { 988 mNextAffiliate.setPrevAffiliate(mPrevAffiliate); 989 } 990 setPrevAffiliate(null); 991 setNextAffiliate(null); 992 } 993 removedFromRecents()994 void removedFromRecents() { 995 closeRecentsChain(); 996 if (inRecents) { 997 inRecents = false; 998 mService.notifyTaskPersisterLocked(this, false); 999 } 1000 1001 clearRootProcess(); 1002 1003 // TODO: Use window container controller once tasks are better synced between AM and WM 1004 mService.mWindowManager.notifyTaskRemovedFromRecents(taskId, userId); 1005 } 1006 setTaskToAffiliateWith(TaskRecord taskToAffiliateWith)1007 void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) { 1008 closeRecentsChain(); 1009 mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId; 1010 mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor; 1011 // Find the end 1012 while (taskToAffiliateWith.mNextAffiliate != null) { 1013 final TaskRecord nextRecents = taskToAffiliateWith.mNextAffiliate; 1014 if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) { 1015 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId=" 1016 + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId); 1017 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) { 1018 nextRecents.setPrevAffiliate(null); 1019 } 1020 taskToAffiliateWith.setNextAffiliate(null); 1021 break; 1022 } 1023 taskToAffiliateWith = nextRecents; 1024 } 1025 taskToAffiliateWith.setNextAffiliate(this); 1026 setPrevAffiliate(taskToAffiliateWith); 1027 setNextAffiliate(null); 1028 } 1029 1030 /** Returns the intent for the root activity for this task */ getBaseIntent()1031 Intent getBaseIntent() { 1032 return intent != null ? intent : affinityIntent; 1033 } 1034 1035 /** Returns the first non-finishing activity from the root. */ getRootActivity()1036 ActivityRecord getRootActivity() { 1037 for (int i = 0; i < mActivities.size(); i++) { 1038 final ActivityRecord r = mActivities.get(i); 1039 if (r.finishing) { 1040 continue; 1041 } 1042 return r; 1043 } 1044 return null; 1045 } 1046 getTopActivity()1047 ActivityRecord getTopActivity() { 1048 return getTopActivity(true /* includeOverlays */); 1049 } 1050 getTopActivity(boolean includeOverlays)1051 ActivityRecord getTopActivity(boolean includeOverlays) { 1052 for (int i = mActivities.size() - 1; i >= 0; --i) { 1053 final ActivityRecord r = mActivities.get(i); 1054 if (r.finishing || (!includeOverlays && r.mTaskOverlay)) { 1055 continue; 1056 } 1057 return r; 1058 } 1059 return null; 1060 } 1061 topRunningActivityLocked()1062 ActivityRecord topRunningActivityLocked() { 1063 if (mStack != null) { 1064 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { 1065 ActivityRecord r = mActivities.get(activityNdx); 1066 if (!r.finishing && r.okToShowLocked()) { 1067 return r; 1068 } 1069 } 1070 } 1071 return null; 1072 } 1073 isVisible()1074 boolean isVisible() { 1075 for (int i = mActivities.size() - 1; i >= 0; --i) { 1076 final ActivityRecord r = mActivities.get(i); 1077 if (r.visible) { 1078 return true; 1079 } 1080 } 1081 return false; 1082 } 1083 getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities)1084 void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) { 1085 if (mStack != null) { 1086 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { 1087 ActivityRecord r = mActivities.get(activityNdx); 1088 if (!r.finishing && r.okToShowLocked() && r.visibleIgnoringKeyguard) { 1089 outActivities.add(r); 1090 } 1091 } 1092 } 1093 } 1094 topRunningActivityWithStartingWindowLocked()1095 ActivityRecord topRunningActivityWithStartingWindowLocked() { 1096 if (mStack != null) { 1097 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { 1098 ActivityRecord r = mActivities.get(activityNdx); 1099 if (r.mStartingWindowState != STARTING_WINDOW_SHOWN 1100 || r.finishing || !r.okToShowLocked()) { 1101 continue; 1102 } 1103 return r; 1104 } 1105 } 1106 return null; 1107 } 1108 1109 /** 1110 * Return the number of running activities, and the number of non-finishing/initializing 1111 * activities in the provided {@param reportOut} respectively. 1112 */ getNumRunningActivities(TaskActivitiesReport reportOut)1113 void getNumRunningActivities(TaskActivitiesReport reportOut) { 1114 reportOut.reset(); 1115 for (int i = mActivities.size() - 1; i >= 0; --i) { 1116 final ActivityRecord r = mActivities.get(i); 1117 if (r.finishing) { 1118 continue; 1119 } 1120 1121 reportOut.base = r; 1122 1123 // Increment the total number of non-finishing activities 1124 reportOut.numActivities++; 1125 1126 if (reportOut.top == null || (reportOut.top.isState(ActivityState.INITIALIZING))) { 1127 reportOut.top = r; 1128 // Reset the number of running activities until we hit the first non-initializing 1129 // activity 1130 reportOut.numRunning = 0; 1131 } 1132 if (r.app != null && r.app.thread != null) { 1133 // Increment the number of actually running activities 1134 reportOut.numRunning++; 1135 } 1136 } 1137 } 1138 okToShowLocked()1139 boolean okToShowLocked() { 1140 // NOTE: If {@link TaskRecord#topRunningActivityLocked} return is not null then it is 1141 // okay to show the activity when locked. 1142 return mService.mStackSupervisor.isCurrentProfileLocked(userId) 1143 || topRunningActivityLocked() != null; 1144 } 1145 1146 /** Call after activity movement or finish to make sure that frontOfTask is set correctly */ setFrontOfTask()1147 final void setFrontOfTask() { 1148 boolean foundFront = false; 1149 final int numActivities = mActivities.size(); 1150 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { 1151 final ActivityRecord r = mActivities.get(activityNdx); 1152 if (foundFront || r.finishing) { 1153 r.frontOfTask = false; 1154 } else { 1155 r.frontOfTask = true; 1156 // Set frontOfTask false for every following activity. 1157 foundFront = true; 1158 } 1159 } 1160 if (!foundFront && numActivities > 0) { 1161 // All activities of this task are finishing. As we ought to have a frontOfTask 1162 // activity, make the bottom activity front. 1163 mActivities.get(0).frontOfTask = true; 1164 } 1165 } 1166 1167 /** 1168 * Reorder the history stack so that the passed activity is brought to the front. 1169 */ moveActivityToFrontLocked(ActivityRecord newTop)1170 final void moveActivityToFrontLocked(ActivityRecord newTop) { 1171 if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, 1172 "Removing and adding activity " + newTop 1173 + " to stack at top callers=" + Debug.getCallers(4)); 1174 1175 mActivities.remove(newTop); 1176 mActivities.add(newTop); 1177 1178 // Make sure window manager is aware of the position change. 1179 mWindowContainerController.positionChildAtTop(newTop.mWindowContainerController); 1180 updateEffectiveIntent(); 1181 1182 setFrontOfTask(); 1183 } 1184 addActivityAtBottom(ActivityRecord r)1185 void addActivityAtBottom(ActivityRecord r) { 1186 addActivityAtIndex(0, r); 1187 } 1188 addActivityToTop(ActivityRecord r)1189 void addActivityToTop(ActivityRecord r) { 1190 addActivityAtIndex(mActivities.size(), r); 1191 } 1192 1193 @Override 1194 /*@WindowConfiguration.ActivityType*/ getActivityType()1195 public int getActivityType() { 1196 final int applicationType = super.getActivityType(); 1197 if (applicationType != ACTIVITY_TYPE_UNDEFINED || mActivities.isEmpty()) { 1198 return applicationType; 1199 } 1200 return mActivities.get(0).getActivityType(); 1201 } 1202 1203 /** 1204 * Adds an activity {@param r} at the given {@param index}. The activity {@param r} must either 1205 * be in the current task or unparented to any task. 1206 */ addActivityAtIndex(int index, ActivityRecord r)1207 void addActivityAtIndex(int index, ActivityRecord r) { 1208 TaskRecord task = r.getTask(); 1209 if (task != null && task != this) { 1210 throw new IllegalArgumentException("Can not add r=" + " to task=" + this 1211 + " current parent=" + task); 1212 } 1213 1214 r.setTask(this); 1215 1216 // Remove r first, and if it wasn't already in the list and it's fullscreen, count it. 1217 if (!mActivities.remove(r) && r.fullscreen) { 1218 // Was not previously in list. 1219 numFullscreen++; 1220 } 1221 // Only set this based on the first activity 1222 if (mActivities.isEmpty()) { 1223 if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) { 1224 // Normally non-standard activity type for the activity record will be set when the 1225 // object is created, however we delay setting the standard application type until 1226 // this point so that the task can set the type for additional activities added in 1227 // the else condition below. 1228 r.setActivityType(ACTIVITY_TYPE_STANDARD); 1229 } 1230 setActivityType(r.getActivityType()); 1231 isPersistable = r.isPersistable(); 1232 mCallingUid = r.launchedFromUid; 1233 mCallingPackage = r.launchedFromPackage; 1234 // Clamp to [1, max]. 1235 maxRecents = Math.min(Math.max(r.info.maxRecents, 1), 1236 ActivityManager.getMaxAppRecentsLimitStatic()); 1237 } else { 1238 // Otherwise make all added activities match this one. 1239 r.setActivityType(getActivityType()); 1240 } 1241 1242 final int size = mActivities.size(); 1243 1244 if (index == size && size > 0) { 1245 final ActivityRecord top = mActivities.get(size - 1); 1246 if (top.mTaskOverlay) { 1247 // Place below the task overlay activity since the overlay activity should always 1248 // be on top. 1249 index--; 1250 } 1251 } 1252 1253 index = Math.min(size, index); 1254 mActivities.add(index, r); 1255 1256 updateEffectiveIntent(); 1257 if (r.isPersistable()) { 1258 mService.notifyTaskPersisterLocked(this, false); 1259 } 1260 1261 // Sync. with window manager 1262 updateOverrideConfigurationFromLaunchBounds(); 1263 final AppWindowContainerController appController = r.getWindowContainerController(); 1264 if (appController != null) { 1265 // Only attempt to move in WM if the child has a controller. It is possible we haven't 1266 // created controller for the activity we are starting yet. 1267 mWindowContainerController.positionChildAt(appController, index); 1268 } 1269 1270 // Make sure the list of display UID whitelists is updated 1271 // now that this record is in a new task. 1272 mService.mStackSupervisor.updateUIDsPresentOnDisplay(); 1273 } 1274 1275 /** 1276 * Removes the specified activity from this task. 1277 * @param r The {@link ActivityRecord} to remove. 1278 * @return true if this was the last activity in the task. 1279 */ removeActivity(ActivityRecord r)1280 boolean removeActivity(ActivityRecord r) { 1281 return removeActivity(r, false /* reparenting */); 1282 } 1283 removeActivity(ActivityRecord r, boolean reparenting)1284 boolean removeActivity(ActivityRecord r, boolean reparenting) { 1285 if (r.getTask() != this) { 1286 throw new IllegalArgumentException( 1287 "Activity=" + r + " does not belong to task=" + this); 1288 } 1289 1290 r.setTask(null /* task */, reparenting /* reparenting */); 1291 1292 if (mActivities.remove(r) && r.fullscreen) { 1293 // Was previously in list. 1294 numFullscreen--; 1295 } 1296 if (r.isPersistable()) { 1297 mService.notifyTaskPersisterLocked(this, false); 1298 } 1299 1300 if (inPinnedWindowingMode()) { 1301 // We normally notify listeners of task stack changes on pause, however pinned stack 1302 // activities are normally in the paused state so no notification will be sent there 1303 // before the activity is removed. We send it here so instead. 1304 mService.mTaskChangeNotificationController.notifyTaskStackChanged(); 1305 } 1306 1307 if (mActivities.isEmpty()) { 1308 return !mReuseTask; 1309 } 1310 updateEffectiveIntent(); 1311 return false; 1312 } 1313 1314 /** 1315 * @return whether or not there are ONLY task overlay activities in the stack. 1316 * If {@param excludeFinishing} is set, then ignore finishing activities in the check. 1317 * If there are no task overlay activities, this call returns false. 1318 */ onlyHasTaskOverlayActivities(boolean excludeFinishing)1319 boolean onlyHasTaskOverlayActivities(boolean excludeFinishing) { 1320 int count = 0; 1321 for (int i = mActivities.size() - 1; i >= 0; i--) { 1322 final ActivityRecord r = mActivities.get(i); 1323 if (excludeFinishing && r.finishing) { 1324 continue; 1325 } 1326 if (!r.mTaskOverlay) { 1327 return false; 1328 } 1329 count++; 1330 } 1331 return count > 0; 1332 } 1333 autoRemoveFromRecents()1334 boolean autoRemoveFromRecents() { 1335 // We will automatically remove the task either if it has explicitly asked for 1336 // this, or it is empty and has never contained an activity that got shown to 1337 // the user. 1338 return autoRemoveRecents || (mActivities.isEmpty() && !hasBeenVisible); 1339 } 1340 1341 /** 1342 * Completely remove all activities associated with an existing 1343 * task starting at a specified index. 1344 */ performClearTaskAtIndexLocked(int activityNdx, boolean pauseImmediately, String reason)1345 final void performClearTaskAtIndexLocked(int activityNdx, boolean pauseImmediately, 1346 String reason) { 1347 int numActivities = mActivities.size(); 1348 for ( ; activityNdx < numActivities; ++activityNdx) { 1349 final ActivityRecord r = mActivities.get(activityNdx); 1350 if (r.finishing) { 1351 continue; 1352 } 1353 if (mStack == null) { 1354 // Task was restored from persistent storage. 1355 r.takeFromHistory(); 1356 mActivities.remove(activityNdx); 1357 --activityNdx; 1358 --numActivities; 1359 } else if (mStack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, 1360 reason, false, pauseImmediately)) { 1361 --activityNdx; 1362 --numActivities; 1363 } 1364 } 1365 } 1366 1367 /** 1368 * Completely remove all activities associated with an existing task. 1369 */ performClearTaskLocked()1370 void performClearTaskLocked() { 1371 mReuseTask = true; 1372 performClearTaskAtIndexLocked(0, !PAUSE_IMMEDIATELY, "clear-task-all"); 1373 mReuseTask = false; 1374 } 1375 performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags)1376 ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) { 1377 mReuseTask = true; 1378 final ActivityRecord result = performClearTaskLocked(newR, launchFlags); 1379 mReuseTask = false; 1380 return result; 1381 } 1382 1383 /** 1384 * Perform clear operation as requested by 1385 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the 1386 * stack to the given task, then look for 1387 * an instance of that activity in the stack and, if found, finish all 1388 * activities on top of it and return the instance. 1389 * 1390 * @param newR Description of the new activity being started. 1391 * @return Returns the old activity that should be continued to be used, 1392 * or null if none was found. 1393 */ performClearTaskLocked(ActivityRecord newR, int launchFlags)1394 final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) { 1395 int numActivities = mActivities.size(); 1396 for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) { 1397 ActivityRecord r = mActivities.get(activityNdx); 1398 if (r.finishing) { 1399 continue; 1400 } 1401 if (r.realActivity.equals(newR.realActivity)) { 1402 // Here it is! Now finish everything in front... 1403 final ActivityRecord ret = r; 1404 1405 for (++activityNdx; activityNdx < numActivities; ++activityNdx) { 1406 r = mActivities.get(activityNdx); 1407 if (r.finishing) { 1408 continue; 1409 } 1410 ActivityOptions opts = r.takeOptionsLocked(); 1411 if (opts != null) { 1412 ret.updateOptionsLocked(opts); 1413 } 1414 if (mStack != null && mStack.finishActivityLocked( 1415 r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) { 1416 --activityNdx; 1417 --numActivities; 1418 } 1419 } 1420 1421 // Finally, if this is a normal launch mode (that is, not 1422 // expecting onNewIntent()), then we will finish the current 1423 // instance of the activity so a new fresh one can be started. 1424 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE 1425 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0 1426 && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) { 1427 if (!ret.finishing) { 1428 if (mStack != null) { 1429 mStack.finishActivityLocked( 1430 ret, Activity.RESULT_CANCELED, null, "clear-task-top", false); 1431 } 1432 return null; 1433 } 1434 } 1435 1436 return ret; 1437 } 1438 } 1439 1440 return null; 1441 } 1442 removeTaskActivitiesLocked(boolean pauseImmediately, String reason)1443 void removeTaskActivitiesLocked(boolean pauseImmediately, String reason) { 1444 // Just remove the entire task. 1445 performClearTaskAtIndexLocked(0, pauseImmediately, reason); 1446 } 1447 lockTaskAuthToString()1448 String lockTaskAuthToString() { 1449 switch (mLockTaskAuth) { 1450 case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK"; 1451 case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE"; 1452 case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE"; 1453 case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED"; 1454 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV"; 1455 default: return "unknown=" + mLockTaskAuth; 1456 } 1457 } 1458 setLockTaskAuth()1459 void setLockTaskAuth() { 1460 setLockTaskAuth(getRootActivity()); 1461 } 1462 setLockTaskAuth(@ullable ActivityRecord r)1463 private void setLockTaskAuth(@Nullable ActivityRecord r) { 1464 if (r == null) { 1465 mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE; 1466 return; 1467 } 1468 1469 final String pkg = (realActivity != null) ? realActivity.getPackageName() : null; 1470 final LockTaskController lockTaskController = mService.getLockTaskController(); 1471 switch (r.lockTaskLaunchMode) { 1472 case LOCK_TASK_LAUNCH_MODE_DEFAULT: 1473 mLockTaskAuth = lockTaskController.isPackageWhitelisted(userId, pkg) 1474 ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE; 1475 break; 1476 1477 case LOCK_TASK_LAUNCH_MODE_NEVER: 1478 mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK; 1479 break; 1480 1481 case LOCK_TASK_LAUNCH_MODE_ALWAYS: 1482 mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV; 1483 break; 1484 1485 case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED: 1486 mLockTaskAuth = lockTaskController.isPackageWhitelisted(userId, pkg) 1487 ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE; 1488 break; 1489 } 1490 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this + 1491 " mLockTaskAuth=" + lockTaskAuthToString()); 1492 } 1493 isResizeable(boolean checkSupportsPip)1494 private boolean isResizeable(boolean checkSupportsPip) { 1495 return (mService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode) 1496 || (checkSupportsPip && mSupportsPictureInPicture)); 1497 } 1498 isResizeable()1499 boolean isResizeable() { 1500 return isResizeable(true /* checkSupportsPip */); 1501 } 1502 1503 @Override supportsSplitScreenWindowingMode()1504 public boolean supportsSplitScreenWindowingMode() { 1505 // A task can not be docked even if it is considered resizeable because it only supports 1506 // picture-in-picture mode but has a non-resizeable resizeMode 1507 return super.supportsSplitScreenWindowingMode() 1508 && mService.mSupportsSplitScreenMultiWindow 1509 && (mService.mForceResizableActivities 1510 || (isResizeable(false /* checkSupportsPip */) 1511 && !ActivityInfo.isPreserveOrientationMode(mResizeMode))); 1512 } 1513 1514 /** 1515 * Check whether this task can be launched on the specified display. 1516 * @param displayId Target display id. 1517 * @return {@code true} if either it is the default display or this activity is resizeable and 1518 * can be put a secondary screen. 1519 */ canBeLaunchedOnDisplay(int displayId)1520 boolean canBeLaunchedOnDisplay(int displayId) { 1521 return mService.mStackSupervisor.canPlaceEntityOnDisplay(displayId, 1522 isResizeable(false /* checkSupportsPip */), -1 /* don't check PID */, 1523 -1 /* don't check UID */, null /* activityInfo */); 1524 } 1525 1526 /** 1527 * Check that a given bounds matches the application requested orientation. 1528 * 1529 * @param bounds The bounds to be tested. 1530 * @return True if the requested bounds are okay for a resizing request. 1531 */ canResizeToBounds(Rect bounds)1532 private boolean canResizeToBounds(Rect bounds) { 1533 if (bounds == null || !inFreeformWindowingMode()) { 1534 // Note: If not on the freeform workspace, we ignore the bounds. 1535 return true; 1536 } 1537 final boolean landscape = bounds.width() > bounds.height(); 1538 final Rect configBounds = getOverrideBounds(); 1539 if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) { 1540 return configBounds.isEmpty() 1541 || landscape == (configBounds.width() > configBounds.height()); 1542 } 1543 return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape) 1544 && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape); 1545 } 1546 1547 /** 1548 * @return {@code true} if the task is being cleared for the purposes of being reused. 1549 */ isClearingToReuseTask()1550 boolean isClearingToReuseTask() { 1551 return mReuseTask; 1552 } 1553 1554 /** 1555 * Find the activity in the history stack within the given task. Returns 1556 * the index within the history at which it's found, or < 0 if not found. 1557 */ findActivityInHistoryLocked(ActivityRecord r)1558 final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) { 1559 final ComponentName realActivity = r.realActivity; 1560 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { 1561 ActivityRecord candidate = mActivities.get(activityNdx); 1562 if (candidate.finishing) { 1563 continue; 1564 } 1565 if (candidate.realActivity.equals(realActivity)) { 1566 return candidate; 1567 } 1568 } 1569 return null; 1570 } 1571 1572 /** Updates the last task description values. */ updateTaskDescription()1573 void updateTaskDescription() { 1574 // Traverse upwards looking for any break between main task activities and 1575 // utility activities. 1576 int activityNdx; 1577 final int numActivities = mActivities.size(); 1578 final boolean relinquish = numActivities != 0 && 1579 (mActivities.get(0).info.flags & FLAG_RELINQUISH_TASK_IDENTITY) != 0; 1580 for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities; 1581 ++activityNdx) { 1582 final ActivityRecord r = mActivities.get(activityNdx); 1583 if (relinquish && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) { 1584 // This will be the top activity for determining taskDescription. Pre-inc to 1585 // overcome initial decrement below. 1586 ++activityNdx; 1587 break; 1588 } 1589 if (r.intent != null && 1590 (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) { 1591 break; 1592 } 1593 } 1594 if (activityNdx > 0) { 1595 // Traverse downwards starting below break looking for set label, icon. 1596 // Note that if there are activities in the task but none of them set the 1597 // recent activity values, then we do not fall back to the last set 1598 // values in the TaskRecord. 1599 String label = null; 1600 String iconFilename = null; 1601 int iconResource = -1; 1602 int colorPrimary = 0; 1603 int colorBackground = 0; 1604 int statusBarColor = 0; 1605 int navigationBarColor = 0; 1606 boolean topActivity = true; 1607 for (--activityNdx; activityNdx >= 0; --activityNdx) { 1608 final ActivityRecord r = mActivities.get(activityNdx); 1609 if (r.mTaskOverlay) { 1610 continue; 1611 } 1612 if (r.taskDescription != null) { 1613 if (label == null) { 1614 label = r.taskDescription.getLabel(); 1615 } 1616 if (iconResource == -1) { 1617 iconResource = r.taskDescription.getIconResource(); 1618 } 1619 if (iconFilename == null) { 1620 iconFilename = r.taskDescription.getIconFilename(); 1621 } 1622 if (colorPrimary == 0) { 1623 colorPrimary = r.taskDescription.getPrimaryColor(); 1624 } 1625 if (topActivity) { 1626 colorBackground = r.taskDescription.getBackgroundColor(); 1627 statusBarColor = r.taskDescription.getStatusBarColor(); 1628 navigationBarColor = r.taskDescription.getNavigationBarColor(); 1629 } 1630 } 1631 topActivity = false; 1632 } 1633 lastTaskDescription = new TaskDescription(label, null, iconResource, iconFilename, 1634 colorPrimary, colorBackground, statusBarColor, navigationBarColor); 1635 if (mWindowContainerController != null) { 1636 mWindowContainerController.setTaskDescription(lastTaskDescription); 1637 } 1638 // Update the task affiliation color if we are the parent of the group 1639 if (taskId == mAffiliatedTaskId) { 1640 mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor(); 1641 } 1642 } 1643 } 1644 findEffectiveRootIndex()1645 int findEffectiveRootIndex() { 1646 int effectiveNdx = 0; 1647 final int topActivityNdx = mActivities.size() - 1; 1648 for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) { 1649 final ActivityRecord r = mActivities.get(activityNdx); 1650 if (r.finishing) { 1651 continue; 1652 } 1653 effectiveNdx = activityNdx; 1654 if ((r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) { 1655 break; 1656 } 1657 } 1658 return effectiveNdx; 1659 } 1660 updateEffectiveIntent()1661 void updateEffectiveIntent() { 1662 final int effectiveRootIndex = findEffectiveRootIndex(); 1663 final ActivityRecord r = mActivities.get(effectiveRootIndex); 1664 setIntent(r); 1665 1666 // Update the task description when the activities change 1667 updateTaskDescription(); 1668 } 1669 adjustForMinimalTaskDimensions(Rect bounds)1670 private void adjustForMinimalTaskDimensions(Rect bounds) { 1671 if (bounds == null) { 1672 return; 1673 } 1674 int minWidth = mMinWidth; 1675 int minHeight = mMinHeight; 1676 // If the task has no requested minimal size, we'd like to enforce a minimal size 1677 // so that the user can not render the task too small to manipulate. We don't need 1678 // to do this for the pinned stack as the bounds are controlled by the system. 1679 if (!inPinnedWindowingMode()) { 1680 if (minWidth == INVALID_MIN_SIZE) { 1681 minWidth = mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask; 1682 } 1683 if (minHeight == INVALID_MIN_SIZE) { 1684 minHeight = mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask; 1685 } 1686 } 1687 final boolean adjustWidth = minWidth > bounds.width(); 1688 final boolean adjustHeight = minHeight > bounds.height(); 1689 if (!(adjustWidth || adjustHeight)) { 1690 return; 1691 } 1692 1693 final Rect configBounds = getOverrideBounds(); 1694 if (adjustWidth) { 1695 if (!configBounds.isEmpty() && bounds.right == configBounds.right) { 1696 bounds.left = bounds.right - minWidth; 1697 } else { 1698 // Either left bounds match, or neither match, or the previous bounds were 1699 // fullscreen and we default to keeping left. 1700 bounds.right = bounds.left + minWidth; 1701 } 1702 } 1703 if (adjustHeight) { 1704 if (!configBounds.isEmpty() && bounds.bottom == configBounds.bottom) { 1705 bounds.top = bounds.bottom - minHeight; 1706 } else { 1707 // Either top bounds match, or neither match, or the previous bounds were 1708 // fullscreen and we default to keeping top. 1709 bounds.bottom = bounds.top + minHeight; 1710 } 1711 } 1712 } 1713 1714 /** 1715 * @return a new Configuration for this Task, given the provided {@param bounds} and 1716 * {@param insetBounds}. 1717 */ computeNewOverrideConfigurationForBounds(Rect bounds, Rect insetBounds)1718 Configuration computeNewOverrideConfigurationForBounds(Rect bounds, Rect insetBounds) { 1719 // Compute a new override configuration for the given bounds, if fullscreen bounds 1720 // (bounds == null), then leave the override config unset 1721 final Configuration newOverrideConfig = new Configuration(); 1722 if (bounds != null) { 1723 newOverrideConfig.setTo(getOverrideConfiguration()); 1724 mTmpRect.set(bounds); 1725 adjustForMinimalTaskDimensions(mTmpRect); 1726 computeOverrideConfiguration(newOverrideConfig, mTmpRect, insetBounds, 1727 mTmpRect.right != bounds.right, mTmpRect.bottom != bounds.bottom); 1728 } 1729 1730 return newOverrideConfig; 1731 } 1732 1733 /** 1734 * Update task's override configuration based on the bounds. 1735 * @param bounds The bounds of the task. 1736 * @return True if the override configuration was updated. 1737 */ updateOverrideConfiguration(Rect bounds)1738 boolean updateOverrideConfiguration(Rect bounds) { 1739 return updateOverrideConfiguration(bounds, null /* insetBounds */); 1740 } 1741 1742 /** 1743 * Update task's override configuration based on the bounds. 1744 * @param bounds The bounds of the task. 1745 * @param insetBounds The bounds used to calculate the system insets, which is used here to 1746 * subtract the navigation bar/status bar size from the screen size reported 1747 * to the application. See {@link IActivityManager#resizeDockedStack}. 1748 * @return True if the override configuration was updated. 1749 */ updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds)1750 boolean updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) { 1751 if (equivalentOverrideBounds(bounds)) { 1752 return false; 1753 } 1754 final Rect currentBounds = getOverrideBounds(); 1755 1756 mTmpConfig.setTo(getOverrideConfiguration()); 1757 final Configuration newConfig = getOverrideConfiguration(); 1758 1759 final boolean matchParentBounds = bounds == null || bounds.isEmpty(); 1760 final boolean persistBounds = getWindowConfiguration().persistTaskBounds(); 1761 if (matchParentBounds) { 1762 if (!currentBounds.isEmpty() && persistBounds) { 1763 mLastNonFullscreenBounds = currentBounds; 1764 } 1765 setBounds(null); 1766 newConfig.unset(); 1767 } else { 1768 mTmpRect.set(bounds); 1769 adjustForMinimalTaskDimensions(mTmpRect); 1770 setBounds(mTmpRect); 1771 1772 if (mStack == null || persistBounds) { 1773 mLastNonFullscreenBounds = getOverrideBounds(); 1774 } 1775 computeOverrideConfiguration(newConfig, mTmpRect, insetBounds, 1776 mTmpRect.right != bounds.right, mTmpRect.bottom != bounds.bottom); 1777 } 1778 onOverrideConfigurationChanged(newConfig); 1779 return !mTmpConfig.equals(newConfig); 1780 } 1781 1782 /** 1783 * This should be called when an child activity changes state. This should only 1784 * be called from 1785 * {@link ActivityRecord#setState(ActivityState, String)} . 1786 * @param record The {@link ActivityRecord} whose state has changed. 1787 * @param state The new state. 1788 * @param reason The reason for the change. 1789 */ onActivityStateChanged(ActivityRecord record, ActivityState state, String reason)1790 void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) { 1791 final ActivityStack parent = getStack(); 1792 1793 if (parent != null) { 1794 parent.onActivityStateChanged(record, state, reason); 1795 } 1796 } 1797 1798 @Override onConfigurationChanged(Configuration newParentConfig)1799 public void onConfigurationChanged(Configuration newParentConfig) { 1800 final boolean wasInMultiWindowMode = inMultiWindowMode(); 1801 super.onConfigurationChanged(newParentConfig); 1802 if (wasInMultiWindowMode != inMultiWindowMode()) { 1803 mService.mStackSupervisor.scheduleUpdateMultiWindowMode(this); 1804 } 1805 // TODO: Should also take care of Pip mode changes here. 1806 } 1807 1808 /** Clears passed config and fills it with new override values. */ 1809 // TODO(b/36505427): TaskRecord.computeOverrideConfiguration() is a utility method that doesn't 1810 // depend on task or stacks, but uses those object to get the display to base the calculation 1811 // on. Probably best to centralize calculations like this in ConfigurationContainer. computeOverrideConfiguration(Configuration config, Rect bounds, Rect insetBounds, boolean overrideWidth, boolean overrideHeight)1812 void computeOverrideConfiguration(Configuration config, Rect bounds, Rect insetBounds, 1813 boolean overrideWidth, boolean overrideHeight) { 1814 mTmpNonDecorBounds.set(bounds); 1815 mTmpStableBounds.set(bounds); 1816 1817 config.unset(); 1818 final Configuration parentConfig = getParent().getConfiguration(); 1819 1820 final float density = parentConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; 1821 1822 if (mStack != null) { 1823 final StackWindowController stackController = mStack.getWindowContainerController(); 1824 stackController.adjustConfigurationForBounds(bounds, insetBounds, 1825 mTmpNonDecorBounds, mTmpStableBounds, overrideWidth, overrideHeight, density, 1826 config, parentConfig, getWindowingMode()); 1827 } else { 1828 throw new IllegalArgumentException("Expected stack when calculating override config"); 1829 } 1830 1831 config.orientation = (config.screenWidthDp <= config.screenHeightDp) 1832 ? Configuration.ORIENTATION_PORTRAIT 1833 : Configuration.ORIENTATION_LANDSCAPE; 1834 1835 // For calculating screen layout, we need to use the non-decor inset screen area for the 1836 // calculation for compatibility reasons, i.e. screen area without system bars that could 1837 // never go away in Honeycomb. 1838 final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density); 1839 final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density); 1840 // We're only overriding LONG, SIZE and COMPAT parts of screenLayout, so we start override 1841 // calculation with partial default. 1842 final int sl = Configuration.SCREENLAYOUT_LONG_YES | Configuration.SCREENLAYOUT_SIZE_XLARGE; 1843 final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp); 1844 final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp); 1845 config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize); 1846 } 1847 updateOverrideConfigurationFromLaunchBounds()1848 Rect updateOverrideConfigurationFromLaunchBounds() { 1849 final Rect bounds = getLaunchBounds(); 1850 updateOverrideConfiguration(bounds); 1851 if (bounds != null && !bounds.isEmpty()) { 1852 // TODO: Review if we actually want to do this - we are setting the launch bounds 1853 // directly here. 1854 bounds.set(getOverrideBounds()); 1855 } 1856 return bounds; 1857 } 1858 1859 /** Updates the task's bounds and override configuration to match what is expected for the 1860 * input stack. */ updateOverrideConfigurationForStack(ActivityStack inStack)1861 void updateOverrideConfigurationForStack(ActivityStack inStack) { 1862 if (mStack != null && mStack == inStack) { 1863 return; 1864 } 1865 1866 if (inStack.inFreeformWindowingMode()) { 1867 if (!isResizeable()) { 1868 throw new IllegalArgumentException("Can not position non-resizeable task=" 1869 + this + " in stack=" + inStack); 1870 } 1871 if (!matchParentBounds()) { 1872 return; 1873 } 1874 if (mLastNonFullscreenBounds != null) { 1875 updateOverrideConfiguration(mLastNonFullscreenBounds); 1876 } else { 1877 mService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null); 1878 } 1879 } else { 1880 updateOverrideConfiguration(inStack.getOverrideBounds()); 1881 } 1882 } 1883 1884 /** Returns the bounds that should be used to launch this task. */ getLaunchBounds()1885 Rect getLaunchBounds() { 1886 if (mStack == null) { 1887 return null; 1888 } 1889 1890 final int windowingMode = getWindowingMode(); 1891 if (!isActivityTypeStandardOrUndefined() 1892 || windowingMode == WINDOWING_MODE_FULLSCREEN 1893 || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) { 1894 return isResizeable() ? mStack.getOverrideBounds() : null; 1895 } else if (!getWindowConfiguration().persistTaskBounds()) { 1896 return mStack.getOverrideBounds(); 1897 } 1898 return mLastNonFullscreenBounds; 1899 } 1900 addStartingWindowsForVisibleActivities(boolean taskSwitch)1901 void addStartingWindowsForVisibleActivities(boolean taskSwitch) { 1902 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { 1903 final ActivityRecord r = mActivities.get(activityNdx); 1904 if (r.visible) { 1905 r.showStartingWindow(null /* prev */, false /* newTask */, taskSwitch); 1906 } 1907 } 1908 } 1909 setRootProcess(ProcessRecord proc)1910 void setRootProcess(ProcessRecord proc) { 1911 clearRootProcess(); 1912 if (intent != null && 1913 (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) { 1914 mRootProcess = proc; 1915 proc.recentTasks.add(this); 1916 } 1917 } 1918 clearRootProcess()1919 void clearRootProcess() { 1920 if (mRootProcess != null) { 1921 mRootProcess.recentTasks.remove(this); 1922 mRootProcess = null; 1923 } 1924 } 1925 clearAllPendingOptions()1926 void clearAllPendingOptions() { 1927 for (int i = getChildCount() - 1; i >= 0; i--) { 1928 getChildAt(i).clearOptionsLocked(false /* withAbort */); 1929 } 1930 } 1931 dump(PrintWriter pw, String prefix)1932 void dump(PrintWriter pw, String prefix) { 1933 pw.print(prefix); pw.print("userId="); pw.print(userId); 1934 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid); 1935 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid); 1936 pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete); 1937 pw.print(" mCallingPackage="); pw.println(mCallingPackage); 1938 if (affinity != null || rootAffinity != null) { 1939 pw.print(prefix); pw.print("affinity="); pw.print(affinity); 1940 if (affinity == null || !affinity.equals(rootAffinity)) { 1941 pw.print(" root="); pw.println(rootAffinity); 1942 } else { 1943 pw.println(); 1944 } 1945 } 1946 if (voiceSession != null || voiceInteractor != null) { 1947 pw.print(prefix); pw.print("VOICE: session=0x"); 1948 pw.print(Integer.toHexString(System.identityHashCode(voiceSession))); 1949 pw.print(" interactor=0x"); 1950 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor))); 1951 } 1952 if (intent != null) { 1953 StringBuilder sb = new StringBuilder(128); 1954 sb.append(prefix); sb.append("intent={"); 1955 intent.toShortString(sb, false, true, false, true); 1956 sb.append('}'); 1957 pw.println(sb.toString()); 1958 } 1959 if (affinityIntent != null) { 1960 StringBuilder sb = new StringBuilder(128); 1961 sb.append(prefix); sb.append("affinityIntent={"); 1962 affinityIntent.toShortString(sb, false, true, false, true); 1963 sb.append('}'); 1964 pw.println(sb.toString()); 1965 } 1966 if (origActivity != null) { 1967 pw.print(prefix); pw.print("origActivity="); 1968 pw.println(origActivity.flattenToShortString()); 1969 } 1970 if (realActivity != null) { 1971 pw.print(prefix); pw.print("realActivity="); 1972 pw.println(realActivity.flattenToShortString()); 1973 } 1974 if (autoRemoveRecents || isPersistable || !isActivityTypeStandard() || numFullscreen != 0) { 1975 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents); 1976 pw.print(" isPersistable="); pw.print(isPersistable); 1977 pw.print(" numFullscreen="); pw.print(numFullscreen); 1978 pw.print(" activityType="); pw.println(getActivityType()); 1979 } 1980 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask 1981 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) { 1982 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset); 1983 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity); 1984 pw.print(" mReuseTask="); pw.print(mReuseTask); 1985 pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString()); 1986 } 1987 if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != INVALID_TASK_ID 1988 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID 1989 || mNextAffiliate != null) { 1990 pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId); 1991 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId); 1992 pw.print(" ("); 1993 if (mPrevAffiliate == null) { 1994 pw.print("null"); 1995 } else { 1996 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate))); 1997 } 1998 pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId); 1999 pw.print(" ("); 2000 if (mNextAffiliate == null) { 2001 pw.print("null"); 2002 } else { 2003 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate))); 2004 } 2005 pw.println(")"); 2006 } 2007 pw.print(prefix); pw.print("Activities="); pw.println(mActivities); 2008 if (!askedCompatMode || !inRecents || !isAvailable) { 2009 pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode); 2010 pw.print(" inRecents="); pw.print(inRecents); 2011 pw.print(" isAvailable="); pw.println(isAvailable); 2012 } 2013 if (lastDescription != null) { 2014 pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription); 2015 } 2016 if (mRootProcess != null) { 2017 pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess); 2018 } 2019 pw.print(prefix); pw.print("stackId="); pw.println(getStackId()); 2020 pw.print(prefix + "hasBeenVisible=" + hasBeenVisible); 2021 pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode)); 2022 pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture); 2023 pw.print(" isResizeable=" + isResizeable()); 2024 pw.print(" lastActiveTime=" + lastActiveTime); 2025 pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)"); 2026 } 2027 2028 @Override toString()2029 public String toString() { 2030 StringBuilder sb = new StringBuilder(128); 2031 if (stringName != null) { 2032 sb.append(stringName); 2033 sb.append(" U="); 2034 sb.append(userId); 2035 sb.append(" StackId="); 2036 sb.append(getStackId()); 2037 sb.append(" sz="); 2038 sb.append(mActivities.size()); 2039 sb.append('}'); 2040 return sb.toString(); 2041 } 2042 sb.append("TaskRecord{"); 2043 sb.append(Integer.toHexString(System.identityHashCode(this))); 2044 sb.append(" #"); 2045 sb.append(taskId); 2046 if (affinity != null) { 2047 sb.append(" A="); 2048 sb.append(affinity); 2049 } else if (intent != null) { 2050 sb.append(" I="); 2051 sb.append(intent.getComponent().flattenToShortString()); 2052 } else if (affinityIntent != null && affinityIntent.getComponent() != null) { 2053 sb.append(" aI="); 2054 sb.append(affinityIntent.getComponent().flattenToShortString()); 2055 } else { 2056 sb.append(" ??"); 2057 } 2058 stringName = sb.toString(); 2059 return toString(); 2060 } 2061 writeToProto(ProtoOutputStream proto, long fieldId)2062 public void writeToProto(ProtoOutputStream proto, long fieldId) { 2063 final long token = proto.start(fieldId); 2064 super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */); 2065 proto.write(ID, taskId); 2066 for (int i = mActivities.size() - 1; i >= 0; i--) { 2067 ActivityRecord activity = mActivities.get(i); 2068 activity.writeToProto(proto, ACTIVITIES); 2069 } 2070 proto.write(STACK_ID, mStack.mStackId); 2071 if (mLastNonFullscreenBounds != null) { 2072 mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS); 2073 } 2074 if (realActivity != null) { 2075 proto.write(REAL_ACTIVITY, realActivity.flattenToShortString()); 2076 } 2077 if (origActivity != null) { 2078 proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString()); 2079 } 2080 proto.write(ACTIVITY_TYPE, getActivityType()); 2081 proto.write(RESIZE_MODE, mResizeMode); 2082 // TODO: Remove, no longer needed with windowingMode. 2083 proto.write(FULLSCREEN, matchParentBounds()); 2084 2085 if (!matchParentBounds()) { 2086 final Rect bounds = getOverrideBounds(); 2087 bounds.writeToProto(proto, BOUNDS); 2088 } 2089 proto.write(MIN_WIDTH, mMinWidth); 2090 proto.write(MIN_HEIGHT, mMinHeight); 2091 proto.end(token); 2092 } 2093 2094 /** 2095 * See {@link #getNumRunningActivities(TaskActivitiesReport)}. 2096 */ 2097 static class TaskActivitiesReport { 2098 int numRunning; 2099 int numActivities; 2100 ActivityRecord top; 2101 ActivityRecord base; 2102 reset()2103 void reset() { 2104 numRunning = numActivities = 0; 2105 top = base = null; 2106 } 2107 } 2108 2109 /** 2110 * Saves this {@link TaskRecord} to XML using given serializer. 2111 */ saveToXml(XmlSerializer out)2112 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { 2113 if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this); 2114 2115 out.attribute(null, ATTR_TASKID, String.valueOf(taskId)); 2116 if (realActivity != null) { 2117 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString()); 2118 } 2119 out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended)); 2120 if (origActivity != null) { 2121 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString()); 2122 } 2123 // Write affinity, and root affinity if it is different from affinity. 2124 // We use the special string "@" for a null root affinity, so we can identify 2125 // later whether we were given a root affinity or should just make it the 2126 // same as the affinity. 2127 if (affinity != null) { 2128 out.attribute(null, ATTR_AFFINITY, affinity); 2129 if (!affinity.equals(rootAffinity)) { 2130 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 2131 } 2132 } else if (rootAffinity != null) { 2133 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 2134 } 2135 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset)); 2136 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents)); 2137 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode)); 2138 out.attribute(null, ATTR_USERID, String.valueOf(userId)); 2139 out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete)); 2140 out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid)); 2141 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved)); 2142 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity)); 2143 if (lastDescription != null) { 2144 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); 2145 } 2146 if (lastTaskDescription != null) { 2147 lastTaskDescription.saveToXml(out); 2148 } 2149 out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); 2150 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); 2151 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId)); 2152 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId)); 2153 out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid)); 2154 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage); 2155 out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode)); 2156 out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE, 2157 String.valueOf(mSupportsPictureInPicture)); 2158 if (mLastNonFullscreenBounds != null) { 2159 out.attribute( 2160 null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString()); 2161 } 2162 out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth)); 2163 out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight)); 2164 out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION)); 2165 2166 if (affinityIntent != null) { 2167 out.startTag(null, TAG_AFFINITYINTENT); 2168 affinityIntent.saveToXml(out); 2169 out.endTag(null, TAG_AFFINITYINTENT); 2170 } 2171 2172 if (intent != null) { 2173 out.startTag(null, TAG_INTENT); 2174 intent.saveToXml(out); 2175 out.endTag(null, TAG_INTENT); 2176 } 2177 2178 final ArrayList<ActivityRecord> activities = mActivities; 2179 final int numActivities = activities.size(); 2180 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { 2181 final ActivityRecord r = activities.get(activityNdx); 2182 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() || 2183 ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT 2184 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) && 2185 activityNdx > 0) { 2186 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET). 2187 break; 2188 } 2189 out.startTag(null, TAG_ACTIVITY); 2190 r.saveToXml(out); 2191 out.endTag(null, TAG_ACTIVITY); 2192 } 2193 } 2194 2195 @VisibleForTesting getTaskRecordFactory()2196 static TaskRecordFactory getTaskRecordFactory() { 2197 if (sTaskRecordFactory == null) { 2198 setTaskRecordFactory(new TaskRecordFactory()); 2199 } 2200 return sTaskRecordFactory; 2201 } 2202 setTaskRecordFactory(TaskRecordFactory factory)2203 static void setTaskRecordFactory(TaskRecordFactory factory) { 2204 sTaskRecordFactory = factory; 2205 } 2206 create(ActivityManagerService service, int taskId, ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor)2207 static TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info, 2208 Intent intent, IVoiceInteractionSession voiceSession, 2209 IVoiceInteractor voiceInteractor) { 2210 return getTaskRecordFactory().create( 2211 service, taskId, info, intent, voiceSession, voiceInteractor); 2212 } 2213 create(ActivityManagerService service, int taskId, ActivityInfo info, Intent intent, TaskDescription taskDescription)2214 static TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info, 2215 Intent intent, TaskDescription taskDescription) { 2216 return getTaskRecordFactory().create(service, taskId, info, intent, taskDescription); 2217 } 2218 restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)2219 static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) 2220 throws IOException, XmlPullParserException { 2221 return getTaskRecordFactory().restoreFromXml(in, stackSupervisor); 2222 } 2223 2224 /** 2225 * A factory class used to create {@link TaskRecord} or its subclass if any. This can be 2226 * specified when system boots by setting it with 2227 * {@link #setTaskRecordFactory(TaskRecordFactory)}. 2228 */ 2229 static class TaskRecordFactory { 2230 create(ActivityManagerService service, int taskId, ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor)2231 TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info, 2232 Intent intent, IVoiceInteractionSession voiceSession, 2233 IVoiceInteractor voiceInteractor) { 2234 return new TaskRecord( 2235 service, taskId, info, intent, voiceSession, voiceInteractor); 2236 } 2237 create(ActivityManagerService service, int taskId, ActivityInfo info, Intent intent, TaskDescription taskDescription)2238 TaskRecord create(ActivityManagerService service, int taskId, ActivityInfo info, 2239 Intent intent, TaskDescription taskDescription) { 2240 return new TaskRecord(service, taskId, info, intent, taskDescription); 2241 } 2242 2243 /** 2244 * Should only be used when we're restoring {@link TaskRecord} from storage. 2245 */ create(ActivityManagerService service, int taskId, Intent intent, Intent affinityIntent, String affinity, String rootAffinity, ComponentName realActivity, ComponentName origActivity, boolean rootWasReset, boolean autoRemoveRecents, boolean askedCompatMode, int userId, int effectiveUid, String lastDescription, ArrayList<ActivityRecord> activities, long lastTimeMoved, boolean neverRelinquishIdentity, TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight)2246 TaskRecord create(ActivityManagerService service, int taskId, Intent intent, 2247 Intent affinityIntent, String affinity, String rootAffinity, 2248 ComponentName realActivity, ComponentName origActivity, boolean rootWasReset, 2249 boolean autoRemoveRecents, boolean askedCompatMode, int userId, 2250 int effectiveUid, String lastDescription, ArrayList<ActivityRecord> activities, 2251 long lastTimeMoved, boolean neverRelinquishIdentity, 2252 TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId, 2253 int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, 2254 int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended, 2255 boolean userSetupComplete, int minWidth, int minHeight) { 2256 return new TaskRecord(service, taskId, intent, affinityIntent, affinity, 2257 rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents, 2258 askedCompatMode, userId, effectiveUid, lastDescription, activities, 2259 lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation, 2260 prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage, 2261 resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete, 2262 minWidth, minHeight); 2263 } 2264 restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)2265 TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) 2266 throws IOException, XmlPullParserException { 2267 Intent intent = null; 2268 Intent affinityIntent = null; 2269 ArrayList<ActivityRecord> activities = new ArrayList<>(); 2270 ComponentName realActivity = null; 2271 boolean realActivitySuspended = false; 2272 ComponentName origActivity = null; 2273 String affinity = null; 2274 String rootAffinity = null; 2275 boolean hasRootAffinity = false; 2276 boolean rootHasReset = false; 2277 boolean autoRemoveRecents = false; 2278 boolean askedCompatMode = false; 2279 int taskType = 0; 2280 int userId = 0; 2281 boolean userSetupComplete = true; 2282 int effectiveUid = -1; 2283 String lastDescription = null; 2284 long lastTimeOnTop = 0; 2285 boolean neverRelinquishIdentity = true; 2286 int taskId = INVALID_TASK_ID; 2287 final int outerDepth = in.getDepth(); 2288 TaskDescription taskDescription = new TaskDescription(); 2289 int taskAffiliation = INVALID_TASK_ID; 2290 int taskAffiliationColor = 0; 2291 int prevTaskId = INVALID_TASK_ID; 2292 int nextTaskId = INVALID_TASK_ID; 2293 int callingUid = -1; 2294 String callingPackage = ""; 2295 int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; 2296 boolean supportsPictureInPicture = false; 2297 Rect lastNonFullscreenBounds = null; 2298 int minWidth = INVALID_MIN_SIZE; 2299 int minHeight = INVALID_MIN_SIZE; 2300 int persistTaskVersion = 0; 2301 2302 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { 2303 final String attrName = in.getAttributeName(attrNdx); 2304 final String attrValue = in.getAttributeValue(attrNdx); 2305 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" + 2306 attrName + " value=" + attrValue); 2307 switch (attrName) { 2308 case ATTR_TASKID: 2309 if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue); 2310 break; 2311 case ATTR_REALACTIVITY: 2312 realActivity = ComponentName.unflattenFromString(attrValue); 2313 break; 2314 case ATTR_REALACTIVITY_SUSPENDED: 2315 realActivitySuspended = Boolean.valueOf(attrValue); 2316 break; 2317 case ATTR_ORIGACTIVITY: 2318 origActivity = ComponentName.unflattenFromString(attrValue); 2319 break; 2320 case ATTR_AFFINITY: 2321 affinity = attrValue; 2322 break; 2323 case ATTR_ROOT_AFFINITY: 2324 rootAffinity = attrValue; 2325 hasRootAffinity = true; 2326 break; 2327 case ATTR_ROOTHASRESET: 2328 rootHasReset = Boolean.parseBoolean(attrValue); 2329 break; 2330 case ATTR_AUTOREMOVERECENTS: 2331 autoRemoveRecents = Boolean.parseBoolean(attrValue); 2332 break; 2333 case ATTR_ASKEDCOMPATMODE: 2334 askedCompatMode = Boolean.parseBoolean(attrValue); 2335 break; 2336 case ATTR_USERID: 2337 userId = Integer.parseInt(attrValue); 2338 break; 2339 case ATTR_USER_SETUP_COMPLETE: 2340 userSetupComplete = Boolean.parseBoolean(attrValue); 2341 break; 2342 case ATTR_EFFECTIVE_UID: 2343 effectiveUid = Integer.parseInt(attrValue); 2344 break; 2345 case ATTR_TASKTYPE: 2346 taskType = Integer.parseInt(attrValue); 2347 break; 2348 case ATTR_LASTDESCRIPTION: 2349 lastDescription = attrValue; 2350 break; 2351 case ATTR_LASTTIMEMOVED: 2352 lastTimeOnTop = Long.parseLong(attrValue); 2353 break; 2354 case ATTR_NEVERRELINQUISH: 2355 neverRelinquishIdentity = Boolean.parseBoolean(attrValue); 2356 break; 2357 case ATTR_TASK_AFFILIATION: 2358 taskAffiliation = Integer.parseInt(attrValue); 2359 break; 2360 case ATTR_PREV_AFFILIATION: 2361 prevTaskId = Integer.parseInt(attrValue); 2362 break; 2363 case ATTR_NEXT_AFFILIATION: 2364 nextTaskId = Integer.parseInt(attrValue); 2365 break; 2366 case ATTR_TASK_AFFILIATION_COLOR: 2367 taskAffiliationColor = Integer.parseInt(attrValue); 2368 break; 2369 case ATTR_CALLING_UID: 2370 callingUid = Integer.parseInt(attrValue); 2371 break; 2372 case ATTR_CALLING_PACKAGE: 2373 callingPackage = attrValue; 2374 break; 2375 case ATTR_RESIZE_MODE: 2376 resizeMode = Integer.parseInt(attrValue); 2377 break; 2378 case ATTR_SUPPORTS_PICTURE_IN_PICTURE: 2379 supportsPictureInPicture = Boolean.parseBoolean(attrValue); 2380 break; 2381 case ATTR_NON_FULLSCREEN_BOUNDS: 2382 lastNonFullscreenBounds = Rect.unflattenFromString(attrValue); 2383 break; 2384 case ATTR_MIN_WIDTH: 2385 minWidth = Integer.parseInt(attrValue); 2386 break; 2387 case ATTR_MIN_HEIGHT: 2388 minHeight = Integer.parseInt(attrValue); 2389 break; 2390 case ATTR_PERSIST_TASK_VERSION: 2391 persistTaskVersion = Integer.parseInt(attrValue); 2392 break; 2393 default: 2394 if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) { 2395 taskDescription.restoreFromXml(attrName, attrValue); 2396 } else { 2397 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName); 2398 } 2399 } 2400 } 2401 2402 int event; 2403 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && 2404 (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) { 2405 if (event == XmlPullParser.START_TAG) { 2406 final String name = in.getName(); 2407 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, 2408 "TaskRecord: START_TAG name=" + name); 2409 if (TAG_AFFINITYINTENT.equals(name)) { 2410 affinityIntent = Intent.restoreFromXml(in); 2411 } else if (TAG_INTENT.equals(name)) { 2412 intent = Intent.restoreFromXml(in); 2413 } else if (TAG_ACTIVITY.equals(name)) { 2414 ActivityRecord activity = 2415 ActivityRecord.restoreFromXml(in, stackSupervisor); 2416 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" + 2417 activity); 2418 if (activity != null) { 2419 activities.add(activity); 2420 } 2421 } else { 2422 handleUnknownTag(name, in); 2423 } 2424 } 2425 } 2426 if (!hasRootAffinity) { 2427 rootAffinity = affinity; 2428 } else if ("@".equals(rootAffinity)) { 2429 rootAffinity = null; 2430 } 2431 if (effectiveUid <= 0) { 2432 Intent checkIntent = intent != null ? intent : affinityIntent; 2433 effectiveUid = 0; 2434 if (checkIntent != null) { 2435 IPackageManager pm = AppGlobals.getPackageManager(); 2436 try { 2437 ApplicationInfo ai = pm.getApplicationInfo( 2438 checkIntent.getComponent().getPackageName(), 2439 PackageManager.MATCH_UNINSTALLED_PACKAGES 2440 | PackageManager.MATCH_DISABLED_COMPONENTS, userId); 2441 if (ai != null) { 2442 effectiveUid = ai.uid; 2443 } 2444 } catch (RemoteException e) { 2445 } 2446 } 2447 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent 2448 + ": effectiveUid=" + effectiveUid); 2449 } 2450 2451 if (persistTaskVersion < 1) { 2452 // We need to convert the resize mode of home activities saved before version one if 2453 // they are marked as RESIZE_MODE_RESIZEABLE to 2454 // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation 2455 // before version 1 and the system didn't resize home activities before then. 2456 if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) { 2457 resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 2458 } 2459 } else { 2460 // This activity has previously marked itself explicitly as both resizeable and 2461 // supporting picture-in-picture. Since there is no longer a requirement for 2462 // picture-in-picture activities to be resizeable, we can mark this simply as 2463 // resizeable and supporting picture-in-picture separately. 2464 if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) { 2465 resizeMode = RESIZE_MODE_RESIZEABLE; 2466 supportsPictureInPicture = true; 2467 } 2468 } 2469 2470 final TaskRecord task = create(stackSupervisor.mService, taskId, intent, affinityIntent, 2471 affinity, rootAffinity, realActivity, origActivity, rootHasReset, 2472 autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription, 2473 activities, lastTimeOnTop, neverRelinquishIdentity, taskDescription, 2474 taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid, 2475 callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended, 2476 userSetupComplete, minWidth, minHeight); 2477 task.mLastNonFullscreenBounds = lastNonFullscreenBounds; 2478 task.setBounds(lastNonFullscreenBounds); 2479 2480 for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { 2481 activities.get(activityNdx).setTask(task); 2482 } 2483 2484 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task); 2485 return task; 2486 } 2487 handleUnknownTag(String name, XmlPullParser in)2488 void handleUnknownTag(String name, XmlPullParser in) 2489 throws IOException, XmlPullParserException { 2490 Slog.e(TAG, "restoreTask: Unexpected name=" + name); 2491 XmlUtils.skipCurrentTag(in); 2492 } 2493 } 2494 } 2495