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