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