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