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