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_TASK_ID; 20 import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED; 21 import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION; 22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; 23 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 24 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 25 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 26 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 27 import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP; 28 import static android.app.WindowConfiguration.ROTATION_UNDEFINED; 29 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 30 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 31 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 32 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 33 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 34 import static android.app.WindowConfiguration.activityTypeToString; 35 import static android.app.WindowConfiguration.windowingModeToString; 36 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; 37 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 38 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; 39 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; 40 import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; 41 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; 42 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; 43 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED; 44 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; 45 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; 46 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; 47 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; 48 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; 49 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 50 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED; 51 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 52 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 53 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 54 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 55 import static android.content.res.Configuration.ORIENTATION_UNDEFINED; 56 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; 57 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; 58 import static android.view.Display.INVALID_DISPLAY; 59 import static android.view.SurfaceControl.METADATA_TASK_ID; 60 import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE; 61 62 import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP; 63 import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; 64 import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN; 65 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; 66 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE; 67 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; 68 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; 69 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; 70 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; 71 import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS; 72 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE; 73 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK; 74 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; 75 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; 76 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE; 77 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; 78 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS; 79 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; 80 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; 81 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; 82 import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK; 83 import static com.android.server.wm.IdentifierProto.HASH_CODE; 84 import static com.android.server.wm.IdentifierProto.TITLE; 85 import static com.android.server.wm.IdentifierProto.USER_ID; 86 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; 87 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; 88 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; 89 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; 90 import static com.android.server.wm.WindowContainerChildProto.TASK; 91 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; 92 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; 93 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 94 import static com.android.server.wm.WindowManagerService.dipToPixel; 95 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM; 96 97 import static java.lang.Integer.MAX_VALUE; 98 99 import android.annotation.IntDef; 100 import android.annotation.NonNull; 101 import android.annotation.Nullable; 102 import android.app.Activity; 103 import android.app.ActivityManager; 104 import android.app.ActivityManager.TaskDescription; 105 import android.app.ActivityManager.TaskSnapshot; 106 import android.app.ActivityOptions; 107 import android.app.ActivityTaskManager; 108 import android.app.AppGlobals; 109 import android.app.TaskInfo; 110 import android.app.WindowConfiguration; 111 import android.content.ComponentName; 112 import android.content.Intent; 113 import android.content.pm.ActivityInfo; 114 import android.content.pm.ApplicationInfo; 115 import android.content.pm.IPackageManager; 116 import android.content.pm.PackageManager; 117 import android.content.res.Configuration; 118 import android.graphics.Point; 119 import android.graphics.Rect; 120 import android.os.Debug; 121 import android.os.IBinder; 122 import android.os.RemoteException; 123 import android.os.SystemClock; 124 import android.os.Trace; 125 import android.os.UserHandle; 126 import android.provider.Settings; 127 import android.service.voice.IVoiceInteractionSession; 128 import android.util.ArraySet; 129 import android.util.DisplayMetrics; 130 import android.util.Slog; 131 import android.util.proto.ProtoOutputStream; 132 import android.view.DisplayInfo; 133 import android.view.RemoteAnimationAdapter; 134 import android.view.RemoteAnimationTarget; 135 import android.view.Surface; 136 import android.view.SurfaceControl; 137 import android.view.WindowManager; 138 import android.window.ITaskOrganizer; 139 140 import com.android.internal.annotations.VisibleForTesting; 141 import com.android.internal.app.IVoiceInteractor; 142 import com.android.internal.util.XmlUtils; 143 import com.android.internal.util.function.pooled.PooledConsumer; 144 import com.android.internal.util.function.pooled.PooledFunction; 145 import com.android.internal.util.function.pooled.PooledLambda; 146 import com.android.internal.util.function.pooled.PooledPredicate; 147 import com.android.server.protolog.common.ProtoLog; 148 import com.android.server.wm.ActivityStack.ActivityState; 149 150 import org.xmlpull.v1.XmlPullParser; 151 import org.xmlpull.v1.XmlPullParserException; 152 import org.xmlpull.v1.XmlSerializer; 153 154 import java.io.IOException; 155 import java.io.PrintWriter; 156 import java.lang.annotation.Retention; 157 import java.lang.annotation.RetentionPolicy; 158 import java.util.ArrayList; 159 import java.util.Objects; 160 import java.util.function.Consumer; 161 import java.util.function.Function; 162 import java.util.function.Predicate; 163 164 class Task extends WindowContainer<WindowContainer> { 165 private static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_ATM; 166 private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; 167 private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; 168 private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK; 169 private static final String TAG_TASKS = TAG + POSTFIX_TASKS; 170 171 private static final String ATTR_TASKID = "task_id"; 172 private static final String TAG_INTENT = "intent"; 173 private static final String TAG_AFFINITYINTENT = "affinity_intent"; 174 private static final String ATTR_REALACTIVITY = "real_activity"; 175 private static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended"; 176 private static final String ATTR_ORIGACTIVITY = "orig_activity"; 177 private static final String TAG_ACTIVITY = "activity"; 178 private static final String ATTR_AFFINITY = "affinity"; 179 private static final String ATTR_ROOT_AFFINITY = "root_affinity"; 180 private static final String ATTR_ROOTHASRESET = "root_has_reset"; 181 private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents"; 182 private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode"; 183 private static final String ATTR_USERID = "user_id"; 184 private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete"; 185 private static final String ATTR_EFFECTIVE_UID = "effective_uid"; 186 @Deprecated 187 private static final String ATTR_TASKTYPE = "task_type"; 188 private static final String ATTR_LASTDESCRIPTION = "last_description"; 189 private static final String ATTR_LASTTIMEMOVED = "last_time_moved"; 190 private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity"; 191 private static final String ATTR_TASK_AFFILIATION = "task_affiliation"; 192 private static final String ATTR_PREV_AFFILIATION = "prev_affiliation"; 193 private static final String ATTR_NEXT_AFFILIATION = "next_affiliation"; 194 private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color"; 195 private static final String ATTR_CALLING_UID = "calling_uid"; 196 private static final String ATTR_CALLING_PACKAGE = "calling_package"; 197 private static final String ATTR_CALLING_FEATURE_ID = "calling_feature_id"; 198 private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture"; 199 private static final String ATTR_RESIZE_MODE = "resize_mode"; 200 private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds"; 201 private static final String ATTR_MIN_WIDTH = "min_width"; 202 private static final String ATTR_MIN_HEIGHT = "min_height"; 203 private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version"; 204 private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity"; 205 206 // Current version of the task record we persist. Used to check if we need to run any upgrade 207 // code. 208 static final int PERSIST_TASK_VERSION = 1; 209 210 static final int INVALID_MIN_SIZE = -1; 211 private float mShadowRadius = 0; 212 213 /** 214 * The modes to control how the stack is moved to the front when calling {@link Task#reparent}. 215 */ 216 @Retention(RetentionPolicy.SOURCE) 217 @IntDef({ 218 REPARENT_MOVE_STACK_TO_FRONT, 219 REPARENT_KEEP_STACK_AT_FRONT, 220 REPARENT_LEAVE_STACK_IN_PLACE 221 }) 222 @interface ReparentMoveStackMode {} 223 // Moves the stack to the front if it was not at the front 224 static final int REPARENT_MOVE_STACK_TO_FRONT = 0; 225 // Only moves the stack to the front if it was focused or front most already 226 static final int REPARENT_KEEP_STACK_AT_FRONT = 1; 227 // Do not move the stack as a part of reparenting 228 static final int REPARENT_LEAVE_STACK_IN_PLACE = 2; 229 230 String affinity; // The affinity name for this task, or null; may change identity. 231 String rootAffinity; // Initial base affinity, or null; does not change from initial root. 232 String mWindowLayoutAffinity; // Launch param affinity of this task or null. Used when saving 233 // launch params of this task. 234 IVoiceInteractionSession voiceSession; // Voice interaction session driving task 235 IVoiceInteractor voiceInteractor; // Associated interactor to provide to app 236 Intent intent; // The original intent that started the task. Note that this value can 237 // be null. 238 Intent affinityIntent; // Intent of affinity-moved activity that started this task. 239 int effectiveUid; // The current effective uid of the identity of this task. 240 ComponentName origActivity; // The non-alias activity component of the intent. 241 ComponentName realActivity; // The actual activity component that started the task. 242 boolean realActivitySuspended; // True if the actual activity component that started the 243 // task is suspended. 244 boolean inRecents; // Actually in the recents list? 245 long lastActiveTime; // Last time this task was active in the current device session, 246 // including sleep. This time is initialized to the elapsed time when 247 // restored from disk. 248 boolean isAvailable; // Is the activity available to be launched? 249 boolean rootWasReset; // True if the intent at the root of the task had 250 // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag. 251 boolean autoRemoveRecents; // If true, we should automatically remove the task from 252 // recents when activity finishes 253 boolean askedCompatMode;// Have asked the user about compat mode for this task. 254 private boolean mHasBeenVisible; // Set if any activities in the task have been visible 255 256 String stringName; // caching of toString() result. 257 boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity 258 // was changed. 259 260 /** Can't be put in lockTask mode. */ 261 final static int LOCK_TASK_AUTH_DONT_LOCK = 0; 262 /** Can enter app pinning with user approval. Can never start over existing lockTask task. */ 263 final static int LOCK_TASK_AUTH_PINNABLE = 1; 264 /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */ 265 final static int LOCK_TASK_AUTH_LAUNCHABLE = 2; 266 /** Can enter lockTask without user approval. Can start over existing lockTask task. */ 267 final static int LOCK_TASK_AUTH_ALLOWLISTED = 3; 268 /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing 269 * lockTask task. */ 270 final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4; 271 int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE; 272 273 int mLockTaskUid = -1; // The uid of the application that called startLockTask(). 274 275 /** The process that had previously hosted the root activity of this task. 276 * Used to know that we should try harder to keep this process around, in case the 277 * user wants to return to it. */ 278 private WindowProcessController mRootProcess; 279 280 /** Takes on same value as first root activity */ 281 boolean isPersistable = false; 282 int maxRecents; 283 284 /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for 285 * determining the order when restoring. Sign indicates whether last task movement was to front 286 * (positive) or back (negative). Absolute value indicates time. */ 287 long mLastTimeMoved; 288 289 /** If original intent did not allow relinquishing task identity, save that information */ 290 private boolean mNeverRelinquishIdentity = true; 291 292 // Used in the unique case where we are clearing the task in order to reuse it. In that case we 293 // do not want to delete the stack when the task goes empty. 294 private boolean mReuseTask = false; 295 296 CharSequence lastDescription; // Last description captured for this item. 297 298 int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent. 299 int mAffiliatedTaskColor; // color of the parent task affiliation. 300 Task mPrevAffiliate; // previous task in affiliated chain. 301 int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence. 302 Task mNextAffiliate; // next task in affiliated chain. 303 int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence. 304 305 // For relaunching the task from recents as though it was launched by the original launcher. 306 int mCallingUid; 307 String mCallingPackage; 308 String mCallingFeatureId; 309 310 private final Rect mTmpStableBounds = new Rect(); 311 private final Rect mTmpNonDecorBounds = new Rect(); 312 private final Rect mTmpBounds = new Rect(); 313 private final Rect mTmpInsets = new Rect(); 314 private final Rect mTmpFullBounds = new Rect(); 315 316 // Last non-fullscreen bounds the task was launched in or resized to. 317 // The information is persisted and used to determine the appropriate stack to launch the 318 // task into on restore. 319 Rect mLastNonFullscreenBounds = null; 320 // Minimal width and height of this task when it's resizeable. -1 means it should use the 321 // default minimal width/height. 322 int mMinWidth; 323 int mMinHeight; 324 325 // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible) 326 // This number will be assigned when we evaluate OOM scores for all visible tasks. 327 int mLayerRank = -1; 328 329 /** Helper object used for updating override configuration. */ 330 private Configuration mTmpConfig = new Configuration(); 331 332 /** Used by fillTaskInfo */ 333 final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport(); 334 335 final ActivityTaskManagerService mAtmService; 336 final ActivityStackSupervisor mStackSupervisor; 337 final RootWindowContainer mRootWindowContainer; 338 339 /* Unique identifier for this task. */ 340 final int mTaskId; 341 /* User for which this task was created. */ 342 // TODO: Make final 343 int mUserId; 344 345 final Rect mPreparedFrozenBounds = new Rect(); 346 final Configuration mPreparedFrozenMergedConfig = new Configuration(); 347 348 // Id of the previous display the stack was on. 349 int mPrevDisplayId = INVALID_DISPLAY; 350 351 /** ID of the display which rotation {@link #mRotation} has. */ 352 private int mLastRotationDisplayId = INVALID_DISPLAY; 353 354 /** 355 * Display rotation as of the last time {@link #setBounds(Rect)} was called or this task was 356 * moved to a new display. 357 */ 358 @Surface.Rotation 359 private int mRotation; 360 361 /** 362 * Last requested orientation reported to DisplayContent. This is different from {@link 363 * #mOrientation} in the sense that this takes activities' requested orientation into 364 * account. Start with {@link ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} so that we don't need 365 * to notify for activities that don't specify any orientation. 366 */ 367 int mLastReportedRequestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 368 369 // For comparison with DisplayContent bounds. 370 private Rect mTmpRect = new Rect(); 371 // For handling display rotations. 372 private Rect mTmpRect2 = new Rect(); 373 374 // Resize mode of the task. See {@link ActivityInfo#resizeMode} 375 // Based on the {@link ActivityInfo#resizeMode} of the root activity. 376 int mResizeMode; 377 378 // Whether or not this task and its activities support PiP. Based on the 379 // {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag of the root activity. 380 boolean mSupportsPictureInPicture; 381 382 // Whether the task is currently being drag-resized 383 private boolean mDragResizing; 384 private int mDragResizeMode; 385 386 // This represents the last resolved activity values for this task 387 // NOTE: This value needs to be persisted with each task 388 private TaskDescription mTaskDescription; 389 390 // If set to true, the task will report that it is not in the floating 391 // state regardless of it's stack affiliation. As the floating state drives 392 // production of content insets this can be used to preserve them across 393 // stack moves and we in fact do so when moving from full screen to pinned. 394 private boolean mPreserveNonFloatingState = false; 395 396 private Dimmer mDimmer = new Dimmer(this); 397 private final Rect mTmpDimBoundsRect = new Rect(); 398 private final Point mLastSurfaceSize = new Point(); 399 400 /** @see #setCanAffectSystemUiFlags */ 401 private boolean mCanAffectSystemUiFlags = true; 402 403 private static Exception sTmpException; 404 405 /** ActivityRecords that are exiting, but still on screen for animations. */ 406 final ArrayList<ActivityRecord> mExitingActivities = new ArrayList<>(); 407 408 /** 409 * When we are in the process of pausing an activity, before starting the 410 * next one, this variable holds the activity that is currently being paused. 411 */ 412 ActivityRecord mPausingActivity = null; 413 414 /** 415 * This is the last activity that we put into the paused state. This is 416 * used to determine if we need to do an activity transition while sleeping, 417 * when we normally hold the top activity paused. 418 */ 419 ActivityRecord mLastPausedActivity = null; 420 421 /** 422 * Activities that specify No History must be removed once the user navigates away from them. 423 * If the device goes to sleep with such an activity in the paused state then we save it here 424 * and finish it later if another activity replaces it on wakeup. 425 */ 426 ActivityRecord mLastNoHistoryActivity = null; 427 428 /** Current activity that is resumed, or null if there is none. */ 429 ActivityRecord mResumedActivity = null; 430 431 private boolean mForceShowForAllUsers; 432 433 /** When set, will force the task to report as invisible. */ 434 static final int FLAG_FORCE_HIDDEN_FOR_PINNED_TASK = 1; 435 static final int FLAG_FORCE_HIDDEN_FOR_TASK_ORG = 1 << 1; 436 private int mForceHiddenFlags = 0; 437 438 // TODO(b/160201781): Revisit double invocation issue in Task#removeChild. 439 /** 440 * Skip {@link ActivityStackSupervisor#removeTask(Task, boolean, boolean, String)} execution if 441 * {@code true} to prevent double traversal of {@link #mChildren} in a loop. 442 */ 443 boolean mInRemoveTask; 444 445 // When non-null, this is a transaction that will get applied on the next frame returned after 446 // a relayout is requested from the client. While this is only valid on a leaf task; since the 447 // transaction can effect an ancestor task, this also needs to keep track of the ancestor task 448 // that this transaction manipulates because deferUntilFrame acts on individual surfaces. 449 SurfaceControl.Transaction mMainWindowSizeChangeTransaction; 450 Task mMainWindowSizeChangeTask; 451 452 private final FindRootHelper mFindRootHelper = new FindRootHelper(); 453 private class FindRootHelper { 454 private ActivityRecord mRoot; 455 clear()456 private void clear() { 457 mRoot = null; 458 } 459 findRoot(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone)460 ActivityRecord findRoot(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) { 461 final PooledFunction f = PooledLambda.obtainFunction(FindRootHelper::processActivity, 462 this, PooledLambda.__(ActivityRecord.class), ignoreRelinquishIdentity, 463 setToBottomIfNone); 464 clear(); 465 forAllActivities(f, false /*traverseTopToBottom*/); 466 f.recycle(); 467 return mRoot; 468 } 469 processActivity(ActivityRecord r, boolean ignoreRelinquishIdentity, boolean setToBottomIfNone)470 private boolean processActivity(ActivityRecord r, 471 boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) { 472 if (mRoot == null && setToBottomIfNone) { 473 // This is the first activity we are process. Set it as the candidate root in case 474 // we don't find a better one. 475 mRoot = r; 476 } 477 478 if (r.finishing) return false; 479 480 // Set this as the candidate root since it isn't finishing. 481 mRoot = r; 482 483 // Only end search if we are ignore relinquishing identity or we are not relinquishing. 484 return ignoreRelinquishIdentity || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0; 485 } 486 } 487 488 /** 489 * The TaskOrganizer which is delegated presentation of this task. If set the Task will 490 * emit an WindowContainerToken (allowing access to it's SurfaceControl leash) to the organizers 491 * taskAppeared callback, and emit a taskRemoved callback when the Task is vanished. 492 */ 493 ITaskOrganizer mTaskOrganizer; 494 private int mLastTaskOrganizerWindowingMode = -1; 495 /** 496 * Prevent duplicate calls to onTaskAppeared. 497 */ 498 boolean mTaskAppearedSent; 499 500 /** 501 * This task was created by the task organizer which has the following implementations. 502 * <ul> 503 * <lis>The task won't be removed when it is empty. Removal has to be an explicit request 504 * from the task organizer.</li> 505 * <li>Unlike other non-root tasks, it's direct children are visible to the task 506 * organizer for ordering purposes.</li> 507 * </ul> 508 */ 509 boolean mCreatedByOrganizer; 510 511 /** 512 * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int, 513 * ActivityInfo, Intent, TaskDescription)} instead. 514 */ Task(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent, IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, TaskDescription _taskDescription, ActivityStack stack)515 Task(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent, 516 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, 517 TaskDescription _taskDescription, ActivityStack stack) { 518 this(atmService, _taskId, _intent, null /*_affinityIntent*/, null /*_affinity*/, 519 null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/, 520 false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/, 521 UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/, 522 null /*_lastDescription*/, System.currentTimeMillis(), 523 true /*neverRelinquishIdentity*/, 524 _taskDescription != null ? _taskDescription : new TaskDescription(), 525 _taskId, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/, 526 info.applicationInfo.uid, info.packageName, null /* default featureId */, 527 info.resizeMode, info.supportsPictureInPicture(), false /*_realActivitySuspended*/, 528 false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info, 529 _voiceSession, _voiceInteractor, stack); 530 } 531 532 /** Don't use constructor directly. This is only used by XML parser. */ Task(ActivityTaskManagerService atmService, 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, long lastTimeMoved, boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, @Nullable String callingFeatureId, int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info, IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, ActivityStack stack)533 Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent, Intent _affinityIntent, 534 String _affinity, String _rootAffinity, ComponentName _realActivity, 535 ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents, 536 boolean _askedCompatMode, int _userId, int _effectiveUid, String _lastDescription, 537 long lastTimeMoved, boolean neverRelinquishIdentity, 538 TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId, 539 int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, 540 @Nullable String callingFeatureId, int resizeMode, boolean supportsPictureInPicture, 541 boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight, 542 ActivityInfo info, IVoiceInteractionSession _voiceSession, 543 IVoiceInteractor _voiceInteractor, ActivityStack stack) { 544 super(atmService.mWindowManager); 545 546 EventLogTags.writeWmTaskCreated(_taskId, stack != null ? getRootTaskId() : INVALID_TASK_ID); 547 mAtmService = atmService; 548 mStackSupervisor = atmService.mStackSupervisor; 549 mRootWindowContainer = mAtmService.mRootWindowContainer; 550 mTaskId = _taskId; 551 mUserId = _userId; 552 mResizeMode = resizeMode; 553 mSupportsPictureInPicture = supportsPictureInPicture; 554 mTaskDescription = _lastTaskDescription; 555 // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED). 556 setOrientation(SCREEN_ORIENTATION_UNSET); 557 mRemoteToken = new RemoteToken(this); 558 affinityIntent = _affinityIntent; 559 affinity = _affinity; 560 rootAffinity = _rootAffinity; 561 voiceSession = _voiceSession; 562 voiceInteractor = _voiceInteractor; 563 realActivity = _realActivity; 564 realActivitySuspended = _realActivitySuspended; 565 origActivity = _origActivity; 566 rootWasReset = _rootWasReset; 567 isAvailable = true; 568 autoRemoveRecents = _autoRemoveRecents; 569 askedCompatMode = _askedCompatMode; 570 mUserSetupComplete = userSetupComplete; 571 effectiveUid = _effectiveUid; 572 touchActiveTime(); 573 lastDescription = _lastDescription; 574 mLastTimeMoved = lastTimeMoved; 575 mNeverRelinquishIdentity = neverRelinquishIdentity; 576 mAffiliatedTaskId = taskAffiliation; 577 mAffiliatedTaskColor = taskAffiliationColor; 578 mPrevAffiliateTaskId = prevTaskId; 579 mNextAffiliateTaskId = nextTaskId; 580 mCallingUid = callingUid; 581 mCallingPackage = callingPackage; 582 mCallingFeatureId = callingFeatureId; 583 mResizeMode = resizeMode; 584 if (info != null) { 585 setIntent(_intent, info); 586 setMinDimensions(info); 587 } else { 588 intent = _intent; 589 mMinWidth = minWidth; 590 mMinHeight = minHeight; 591 } 592 mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity); 593 } 594 reuseAsLeafTask(IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, Intent intent, ActivityInfo info, ActivityRecord activity)595 Task reuseAsLeafTask(IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, 596 Intent intent, ActivityInfo info, ActivityRecord activity) { 597 voiceSession = _voiceSession; 598 voiceInteractor = _voiceInteractor; 599 setIntent(activity, intent, info); 600 setMinDimensions(info); 601 // Before we began to reuse a root task (old ActivityStack) as the leaf task, we used to 602 // create a leaf task in this case. Therefore now we won't send out the task created 603 // notification when we decide to reuse it here, so we send out the notification below. 604 // The reason why the created notification sent out when root task is created doesn't work 605 // is that realActivity isn't set until setIntent() method above is called for the first 606 // time. Eventually this notification will be removed when we can populate those information 607 // when root task is created. 608 mAtmService.getTaskChangeNotificationController().notifyTaskCreated(mTaskId, realActivity); 609 return this; 610 } 611 cleanUpResourcesForDestroy(ConfigurationContainer oldParent)612 private void cleanUpResourcesForDestroy(ConfigurationContainer oldParent) { 613 if (hasChild()) { 614 return; 615 } 616 617 if (isLeafTask()) { 618 // This task is going away, so save the last state if necessary. 619 saveLaunchingStateIfNeeded(((WindowContainer) oldParent).getDisplayContent()); 620 } 621 622 // TODO: VI what about activity? 623 final boolean isVoiceSession = voiceSession != null; 624 if (isVoiceSession) { 625 try { 626 voiceSession.taskFinished(intent, mTaskId); 627 } catch (RemoteException e) { 628 } 629 } 630 if (autoRemoveFromRecents() || isVoiceSession) { 631 // Task creator asked to remove this when done, or this task was a voice 632 // interaction, so it should not remain on the recent tasks list. 633 mStackSupervisor.mRecentTasks.remove(this); 634 } 635 636 removeIfPossible(); 637 } 638 639 @VisibleForTesting 640 @Override removeIfPossible()641 void removeIfPossible() { 642 final boolean isRootTask = isRootTask(); 643 if (!isRootTask) { 644 mAtmService.getLockTaskController().clearLockedTask(this); 645 } 646 if (shouldDeferRemoval()) { 647 if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId); 648 return; 649 } 650 removeImmediately(); 651 if (isLeafTask()) { 652 mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId); 653 } 654 } 655 setResizeMode(int resizeMode)656 void setResizeMode(int resizeMode) { 657 if (mResizeMode == resizeMode) { 658 return; 659 } 660 mResizeMode = resizeMode; 661 mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); 662 mRootWindowContainer.resumeFocusedStacksTopActivities(); 663 updateTaskDescription(); 664 } 665 resize(Rect bounds, int resizeMode, boolean preserveWindow)666 boolean resize(Rect bounds, int resizeMode, boolean preserveWindow) { 667 mAtmService.deferWindowLayout(); 668 669 try { 670 final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0; 671 672 if (getParent() == null) { 673 // Task doesn't exist in window manager yet (e.g. was restored from recents). 674 // All we can do for now is update the bounds so it can be used when the task is 675 // added to window manager. 676 setBounds(bounds); 677 if (!inFreeformWindowingMode()) { 678 // re-restore the task so it can have the proper stack association. 679 mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP); 680 } 681 return true; 682 } 683 684 if (!canResizeToBounds(bounds)) { 685 throw new IllegalArgumentException("resizeTask: Can not resize task=" + this 686 + " to bounds=" + bounds + " resizeMode=" + mResizeMode); 687 } 688 689 // Do not move the task to another stack here. 690 // This method assumes that the task is already placed in the right stack. 691 // we do not mess with that decision and we only do the resize! 692 693 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizeTask_" + mTaskId); 694 695 boolean updatedConfig = false; 696 mTmpConfig.setTo(getResolvedOverrideConfiguration()); 697 if (setBounds(bounds) != BOUNDS_CHANGE_NONE) { 698 updatedConfig = !mTmpConfig.equals(getResolvedOverrideConfiguration()); 699 } 700 // This variable holds information whether the configuration didn't change in a 701 // significant way and the activity was kept the way it was. If it's false, it means 702 // the activity had to be relaunched due to configuration change. 703 boolean kept = true; 704 if (updatedConfig) { 705 final ActivityRecord r = topRunningActivityLocked(); 706 if (r != null) { 707 kept = r.ensureActivityConfiguration(0 /* globalChanges */, 708 preserveWindow); 709 // Preserve other windows for resizing because if resizing happens when there 710 // is a dialog activity in the front, the activity that still shows some 711 // content to the user will become black and cause flickers. Note in most cases 712 // this won't cause tons of irrelevant windows being preserved because only 713 // activities in this task may experience a bounds change. Configs for other 714 // activities stay the same. 715 mRootWindowContainer.ensureActivitiesVisible(r, 0, preserveWindow); 716 if (!kept) { 717 mRootWindowContainer.resumeFocusedStacksTopActivities(); 718 } 719 } 720 } 721 resize(kept, forced); 722 723 saveLaunchingStateIfNeeded(); 724 725 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 726 return kept; 727 } finally { 728 mAtmService.continueWindowLayout(); 729 } 730 } 731 732 /** Convenience method to reparent a task to the top or bottom position of the stack. */ reparent(ActivityStack preferredStack, boolean toTop, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, String reason)733 boolean reparent(ActivityStack preferredStack, boolean toTop, 734 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, 735 String reason) { 736 return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume, 737 true /* schedulePictureInPictureModeChange */, reason); 738 } 739 740 /** 741 * Convenience method to reparent a task to the top or bottom position of the stack, with 742 * an option to skip scheduling the picture-in-picture mode change. 743 */ reparent(ActivityStack preferredStack, boolean toTop, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, String reason)744 boolean reparent(ActivityStack preferredStack, boolean toTop, 745 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, 746 boolean schedulePictureInPictureModeChange, String reason) { 747 return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, 748 deferResume, schedulePictureInPictureModeChange, reason); 749 } 750 751 /** 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)752 boolean reparent(ActivityStack preferredStack, int position, 753 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, 754 String reason) { 755 return reparent(preferredStack, position, moveStackMode, animate, deferResume, 756 true /* schedulePictureInPictureModeChange */, reason); 757 } 758 759 /** 760 * Reparents the task into a preferred stack, creating it if necessary. 761 * 762 * @param preferredStack the target stack to move this task 763 * @param position the position to place this task in the new stack 764 * @param animate whether or not we should wait for the new window created as a part of the 765 * reparenting to be drawn and animated in 766 * @param moveStackMode whether or not to move the stack to the front always, only if it was 767 * previously focused & in front, or never 768 * @param deferResume whether or not to update the visibility of other tasks and stacks that may 769 * have changed as a result of this reparenting 770 * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode 771 * change. Callers may set this to false if they are explicitly scheduling PiP mode 772 * changes themselves, like during the PiP animation 773 * @param reason the caller of this reparenting 774 * @return whether the task was reparented 775 */ 776 // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs. 777 // 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)778 boolean reparent(ActivityStack preferredStack, int position, 779 @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, 780 boolean schedulePictureInPictureModeChange, String reason) { 781 final ActivityStackSupervisor supervisor = mStackSupervisor; 782 final RootWindowContainer root = mRootWindowContainer; 783 final WindowManagerService windowManager = mAtmService.mWindowManager; 784 final ActivityStack sourceStack = getStack(); 785 final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack, 786 position == MAX_VALUE); 787 if (toStack == sourceStack) { 788 return false; 789 } 790 if (!canBeLaunchedOnDisplay(toStack.getDisplayId())) { 791 return false; 792 } 793 794 final boolean toTopOfStack = position == MAX_VALUE; 795 if (toTopOfStack && toStack.getResumedActivity() != null 796 && toStack.topRunningActivity() != null) { 797 // Pause the resumed activity on the target stack while re-parenting task on top of it. 798 toStack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */, 799 null /* resuming */); 800 } 801 802 final int toStackWindowingMode = toStack.getWindowingMode(); 803 final ActivityRecord topActivity = getTopNonFinishingActivity(); 804 805 final boolean mightReplaceWindow = topActivity != null 806 && replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode); 807 if (mightReplaceWindow) { 808 // We are about to relaunch the activity because its configuration changed due to 809 // being maximized, i.e. size change. The activity will first remove the old window 810 // and then add a new one. This call will tell window manager about this, so it can 811 // preserve the old window until the new one is drawn. This prevents having a gap 812 // between the removal and addition, in which no window is visible. We also want the 813 // entrance of the new window to be properly animated. 814 // Note here we always set the replacing window first, as the flags might be needed 815 // during the relaunch. If we end up not doing any relaunch, we clear the flags later. 816 windowManager.setWillReplaceWindow(topActivity.appToken, animate); 817 } 818 819 mAtmService.deferWindowLayout(); 820 boolean kept = true; 821 try { 822 final ActivityRecord r = topRunningActivityLocked(); 823 final boolean wasFocused = r != null && root.isTopDisplayFocusedStack(sourceStack) 824 && (topRunningActivityLocked() == r); 825 final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r; 826 final boolean wasPaused = r != null && sourceStack.mPausingActivity == r; 827 828 // In some cases the focused stack isn't the front stack. E.g. pinned stack. 829 // Whenever we are moving the top activity from the front stack we want to make sure to 830 // move the stack to the front. 831 final boolean wasFront = r != null && sourceStack.isTopStackInDisplayArea() 832 && (sourceStack.topRunningActivity() == r); 833 834 final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT 835 || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront)); 836 837 reparent(toStack, position, moveStackToFront, reason); 838 839 if (schedulePictureInPictureModeChange) { 840 // Notify of picture-in-picture mode changes 841 supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack); 842 } 843 844 // If the task had focus before (or we're requested to move focus), move focus to the 845 // new stack by moving the stack to the front. 846 if (r != null) { 847 toStack.moveToFrontAndResumeStateIfNeeded(r, moveStackToFront, wasResumed, 848 wasPaused, reason); 849 } 850 if (!animate) { 851 mStackSupervisor.mNoAnimActivities.add(topActivity); 852 } 853 854 // We might trigger a configuration change. Save the current task bounds for freezing. 855 // TODO: Should this call be moved inside the resize method in WM? 856 toStack.prepareFreezingTaskBounds(); 857 858 if (toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY 859 && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) { 860 // Move recents to front so it is not behind home stack when going into docked 861 // mode 862 mStackSupervisor.moveRecentsStackToFront(reason); 863 } 864 } finally { 865 mAtmService.continueWindowLayout(); 866 } 867 868 if (mightReplaceWindow) { 869 // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old 870 // window), we need to clear the replace window settings. Otherwise, we schedule a 871 // timeout to remove the old window if the replacing window is not coming in time. 872 windowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept); 873 } 874 875 if (!deferResume) { 876 // The task might have already been running and its visibility needs to be synchronized 877 // with the visibility of the stack / windows. 878 root.ensureActivitiesVisible(null, 0, !mightReplaceWindow); 879 root.resumeFocusedStacksTopActivities(); 880 } 881 882 // TODO: Handle incorrect request to move before the actual move, not after. 883 supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(), 884 mRootWindowContainer.getDefaultTaskDisplayArea(), toStack); 885 886 return (preferredStack == toStack); 887 } 888 889 /** 890 * @return {@code true} if the windows of tasks being moved to the target stack from the 891 * source stack should be replaced, meaning that window manager will keep the old window 892 * around until the new is ready. 893 */ replaceWindowsOnTaskMove( int sourceWindowingMode, int targetWindowingMode)894 private static boolean replaceWindowsOnTaskMove( 895 int sourceWindowingMode, int targetWindowingMode) { 896 return sourceWindowingMode == WINDOWING_MODE_FREEFORM 897 || targetWindowingMode == WINDOWING_MODE_FREEFORM; 898 } 899 900 /** 901 * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD! 902 */ getSnapshot(boolean isLowResolution, boolean restoreFromDisk)903 TaskSnapshot getSnapshot(boolean isLowResolution, boolean restoreFromDisk) { 904 905 // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more 906 // synchronized between AM and WM. 907 return mAtmService.mWindowManager.getTaskSnapshot(mTaskId, mUserId, isLowResolution, 908 restoreFromDisk); 909 } 910 touchActiveTime()911 void touchActiveTime() { 912 lastActiveTime = SystemClock.elapsedRealtime(); 913 } 914 getInactiveDuration()915 long getInactiveDuration() { 916 return SystemClock.elapsedRealtime() - lastActiveTime; 917 } 918 919 /** @see #setIntent(ActivityRecord, Intent, ActivityInfo) */ setIntent(ActivityRecord r)920 void setIntent(ActivityRecord r) { 921 setIntent(r, null /* intent */, null /* info */); 922 } 923 924 /** 925 * Sets the original intent, and the calling uid and package. 926 * 927 * @param r The activity that started the task 928 * @param intent The task info which could be different from {@code r.intent} if set. 929 * @param info The activity info which could be different from {@code r.info} if set. 930 */ setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info)931 void setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info) { 932 mCallingUid = r.launchedFromUid; 933 mCallingPackage = r.launchedFromPackage; 934 mCallingFeatureId = r.launchedFromFeatureId; 935 setIntent(intent != null ? intent : r.intent, info != null ? info : r.info); 936 setLockTaskAuth(r); 937 938 final WindowContainer parent = getParent(); 939 if (parent != null) { 940 final Task t = parent.asTask(); 941 if (t != null) { 942 t.setIntent(r); 943 } 944 } 945 } 946 947 /** Sets the original intent, _without_ updating the calling uid or package. */ setIntent(Intent _intent, ActivityInfo info)948 private void setIntent(Intent _intent, ActivityInfo info) { 949 final boolean isLeaf = isLeafTask(); 950 if (intent == null) { 951 mNeverRelinquishIdentity = 952 (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0; 953 } else if (mNeverRelinquishIdentity && isLeaf) { 954 return; 955 } 956 957 affinity = isLeaf ? info.taskAffinity : null; 958 if (intent == null) { 959 // If this task already has an intent associated with it, don't set the root 960 // affinity -- we don't want it changing after initially set, but the initially 961 // set value may be null. 962 rootAffinity = affinity; 963 } 964 effectiveUid = info.applicationInfo.uid; 965 stringName = null; 966 967 if (info.targetActivity == null) { 968 if (_intent != null) { 969 // If this Intent has a selector, we want to clear it for the 970 // recent task since it is not relevant if the user later wants 971 // to re-launch the app. 972 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) { 973 _intent = new Intent(_intent); 974 _intent.setSelector(null); 975 _intent.setSourceBounds(null); 976 } 977 } 978 if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent); 979 intent = _intent; 980 realActivity = _intent != null ? _intent.getComponent() : null; 981 origActivity = null; 982 } else { 983 ComponentName targetComponent = new ComponentName( 984 info.packageName, info.targetActivity); 985 if (_intent != null) { 986 Intent targetIntent = new Intent(_intent); 987 targetIntent.setSelector(null); 988 targetIntent.setSourceBounds(null); 989 if (DEBUG_TASKS) Slog.v(TAG_TASKS, 990 "Setting Intent of " + this + " to target " + targetIntent); 991 intent = targetIntent; 992 realActivity = targetComponent; 993 origActivity = _intent.getComponent(); 994 } else { 995 intent = null; 996 realActivity = targetComponent; 997 origActivity = new ComponentName(info.packageName, info.name); 998 } 999 } 1000 mWindowLayoutAffinity = 1001 info.windowLayout == null ? null : info.windowLayout.windowLayoutAffinity; 1002 1003 final int intentFlags = intent == null ? 0 : intent.getFlags(); 1004 if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { 1005 // Once we are set to an Intent with this flag, we count this 1006 // task as having a true root activity. 1007 rootWasReset = true; 1008 } 1009 mUserId = UserHandle.getUserId(info.applicationInfo.uid); 1010 mUserSetupComplete = Settings.Secure.getIntForUser( 1011 mAtmService.mContext.getContentResolver(), USER_SETUP_COMPLETE, 0, mUserId) != 0; 1012 if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) { 1013 // If the activity itself has requested auto-remove, then just always do it. 1014 autoRemoveRecents = true; 1015 } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS)) 1016 == FLAG_ACTIVITY_NEW_DOCUMENT) { 1017 // If the caller has not asked for the document to be retained, then we may 1018 // want to turn on auto-remove, depending on whether the target has set its 1019 // own document launch mode. 1020 if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) { 1021 autoRemoveRecents = false; 1022 } else { 1023 autoRemoveRecents = true; 1024 } 1025 } else { 1026 autoRemoveRecents = false; 1027 } 1028 if (mResizeMode != info.resizeMode) { 1029 mResizeMode = info.resizeMode; 1030 updateTaskDescription(); 1031 } 1032 mSupportsPictureInPicture = info.supportsPictureInPicture(); 1033 } 1034 1035 /** Sets the original minimal width and height. */ setMinDimensions(ActivityInfo info)1036 void setMinDimensions(ActivityInfo info) { 1037 if (info != null && info.windowLayout != null) { 1038 mMinWidth = info.windowLayout.minWidth; 1039 mMinHeight = info.windowLayout.minHeight; 1040 } else { 1041 mMinWidth = INVALID_MIN_SIZE; 1042 mMinHeight = INVALID_MIN_SIZE; 1043 } 1044 } 1045 1046 /** 1047 * Return true if the input activity has the same intent filter as the intent this task 1048 * record is based on (normally the root activity intent). 1049 */ isSameIntentFilter(ActivityRecord r)1050 boolean isSameIntentFilter(ActivityRecord r) { 1051 final Intent intent = new Intent(r.intent); 1052 // Make sure the component are the same if the input activity has the same real activity 1053 // as the one in the task because either one of them could be the alias activity. 1054 if (Objects.equals(realActivity, r.mActivityComponent) && this.intent != null) { 1055 intent.setComponent(this.intent.getComponent()); 1056 } 1057 return intent.filterEquals(this.intent); 1058 } 1059 returnsToHomeStack()1060 boolean returnsToHomeStack() { 1061 if (inMultiWindowMode() || !hasChild()) return false; 1062 if (intent != null) { 1063 final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME; 1064 return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags; 1065 } 1066 final Task bottomTask = getBottomMostTask(); 1067 return bottomTask != this && bottomTask.returnsToHomeStack(); 1068 } 1069 setPrevAffiliate(Task prevAffiliate)1070 void setPrevAffiliate(Task prevAffiliate) { 1071 mPrevAffiliate = prevAffiliate; 1072 mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.mTaskId; 1073 } 1074 setNextAffiliate(Task nextAffiliate)1075 void setNextAffiliate(Task nextAffiliate) { 1076 mNextAffiliate = nextAffiliate; 1077 mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.mTaskId; 1078 } 1079 1080 @Override onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent)1081 void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { 1082 final DisplayContent display = newParent != null 1083 ? ((WindowContainer) newParent).getDisplayContent() : null; 1084 final DisplayContent oldDisplay = oldParent != null 1085 ? ((WindowContainer) oldParent).getDisplayContent() : null; 1086 1087 mPrevDisplayId = (oldDisplay != null) ? oldDisplay.mDisplayId : INVALID_DISPLAY; 1088 1089 if (oldParent != null && newParent == null) { 1090 cleanUpResourcesForDestroy(oldParent); 1091 } 1092 1093 if (display != null) { 1094 // TODO(NOW!): Chat with the erosky@ of this code to see if this really makes sense here... 1095 // Rotations are relative to the display. This means if there are 2 displays rotated 1096 // differently (eg. 2 monitors with one landscape and one portrait), moving a stack 1097 // from one to the other could look like a rotation change. To prevent this 1098 // apparent rotation change (and corresponding bounds rotation), pretend like our 1099 // current rotation is already the same as the new display. 1100 // Note, if ActivityStack or related logic ever gets nested, this logic will need 1101 // to move to onConfigurationChanged. 1102 getConfiguration().windowConfiguration.setRotation( 1103 display.getWindowConfiguration().getRotation()); 1104 } 1105 1106 super.onParentChanged(newParent, oldParent); 1107 1108 // TODO(NOW): The check for null display content and setting it to null doesn't really 1109 // make sense here... 1110 1111 // TODO(stack-merge): This is mostly taking care of the case where the stask is removing from 1112 // the display, so we should probably consolidate it there instead. 1113 1114 if (getParent() == null && mDisplayContent != null) { 1115 EventLogTags.writeWmStackRemoved(getRootTaskId()); 1116 mDisplayContent = null; 1117 mWmService.mWindowPlacerLocked.requestTraversal(); 1118 } 1119 1120 if (oldParent != null) { 1121 final Task oldParentTask = ((WindowContainer) oldParent).asTask(); 1122 if (oldParentTask != null) { 1123 final PooledConsumer c = PooledLambda.obtainConsumer( 1124 Task::cleanUpActivityReferences, oldParentTask, 1125 PooledLambda.__(ActivityRecord.class)); 1126 forAllActivities(c); 1127 c.recycle(); 1128 } 1129 1130 if (oldParent.inPinnedWindowingMode() 1131 && (newParent == null || !newParent.inPinnedWindowingMode())) { 1132 // Notify if a task from the pinned stack is being removed 1133 // (or moved depending on the mode). 1134 mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned(); 1135 } 1136 } 1137 1138 if (newParent != null) { 1139 final Task newParentTask = ((WindowContainer) newParent).asTask(); 1140 if (newParentTask != null) { 1141 final ActivityRecord top = newParentTask.getTopNonFinishingActivity( 1142 false /* includeOverlays */); 1143 if (top != null && top.isState(RESUMED)) { 1144 newParentTask.setResumedActivity(top, "addedToTask"); 1145 } 1146 } 1147 1148 // TODO: Ensure that this is actually necessary here 1149 // Notify the voice session if required 1150 if (voiceSession != null) { 1151 try { 1152 voiceSession.taskStarted(intent, mTaskId); 1153 } catch (RemoteException e) { 1154 } 1155 } 1156 } 1157 1158 // First time we are adding the task to the system. 1159 if (oldParent == null && newParent != null) { 1160 1161 // TODO: Super random place to be doing this, but aligns with what used to be done 1162 // before we unified Task level. Look into if this can be done in a better place. 1163 updateOverrideConfigurationFromLaunchBounds(); 1164 } 1165 1166 // Update task bounds if needed. 1167 adjustBoundsForDisplayChangeIfNeeded(getDisplayContent()); 1168 1169 if (getWindowConfiguration().windowsAreScaleable()) { 1170 // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them 1171 // while a resize is pending. 1172 forceWindowsScaleable(true /* force */); 1173 } else { 1174 forceWindowsScaleable(false /* force */); 1175 } 1176 1177 mRootWindowContainer.updateUIDsPresentOnDisplay(); 1178 } 1179 cleanUpActivityReferences(ActivityRecord r)1180 void cleanUpActivityReferences(ActivityRecord r) { 1181 final WindowContainer parent = getParent(); 1182 if (parent != null && parent.asTask() != null) { 1183 parent.asTask().cleanUpActivityReferences(r); 1184 return; 1185 } 1186 r.removeTimeouts(); 1187 mExitingActivities.remove(r); 1188 1189 if (mResumedActivity != null && mResumedActivity == r) { 1190 setResumedActivity(null, "cleanUpActivityReferences"); 1191 } 1192 if (mPausingActivity != null && mPausingActivity == r) { 1193 mPausingActivity = null; 1194 } 1195 } 1196 1197 /** @return the currently resumed activity. */ getResumedActivity()1198 ActivityRecord getResumedActivity() { 1199 return mResumedActivity; 1200 } 1201 setResumedActivity(ActivityRecord r, String reason)1202 void setResumedActivity(ActivityRecord r, String reason) { 1203 if (mResumedActivity == r) { 1204 return; 1205 } 1206 1207 if (ActivityTaskManagerDebugConfig.DEBUG_STACK) Slog.d(TAG_STACK, 1208 "setResumedActivity stack:" + this + " + from: " 1209 + mResumedActivity + " to:" + r + " reason:" + reason); 1210 mResumedActivity = r; 1211 mStackSupervisor.updateTopResumedActivityIfNeeded(); 1212 } 1213 updateTaskMovement(boolean toFront)1214 void updateTaskMovement(boolean toFront) { 1215 if (isPersistable) { 1216 mLastTimeMoved = System.currentTimeMillis(); 1217 // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most 1218 // recently will be most negative, tasks sent to the bottom before that will be less 1219 // negative. Similarly for recent tasks moved to the top which will be most positive. 1220 if (!toFront) { 1221 mLastTimeMoved *= -1; 1222 } 1223 } 1224 mRootWindowContainer.invalidateTaskLayers(); 1225 } 1226 1227 // Close up recents linked list. closeRecentsChain()1228 private void closeRecentsChain() { 1229 if (mPrevAffiliate != null) { 1230 mPrevAffiliate.setNextAffiliate(mNextAffiliate); 1231 } 1232 if (mNextAffiliate != null) { 1233 mNextAffiliate.setPrevAffiliate(mPrevAffiliate); 1234 } 1235 setPrevAffiliate(null); 1236 setNextAffiliate(null); 1237 } 1238 removedFromRecents()1239 void removedFromRecents() { 1240 closeRecentsChain(); 1241 if (inRecents) { 1242 inRecents = false; 1243 mAtmService.notifyTaskPersisterLocked(this, false); 1244 } 1245 1246 clearRootProcess(); 1247 1248 mAtmService.mWindowManager.mTaskSnapshotController.notifyTaskRemovedFromRecents( 1249 mTaskId, mUserId); 1250 } 1251 setTaskToAffiliateWith(Task taskToAffiliateWith)1252 void setTaskToAffiliateWith(Task taskToAffiliateWith) { 1253 closeRecentsChain(); 1254 mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId; 1255 mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor; 1256 // Find the end 1257 while (taskToAffiliateWith.mNextAffiliate != null) { 1258 final Task nextRecents = taskToAffiliateWith.mNextAffiliate; 1259 if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) { 1260 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId=" 1261 + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId); 1262 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) { 1263 nextRecents.setPrevAffiliate(null); 1264 } 1265 taskToAffiliateWith.setNextAffiliate(null); 1266 break; 1267 } 1268 taskToAffiliateWith = nextRecents; 1269 } 1270 taskToAffiliateWith.setNextAffiliate(this); 1271 setPrevAffiliate(taskToAffiliateWith); 1272 setNextAffiliate(null); 1273 } 1274 1275 /** Returns the intent for the root activity for this task */ getBaseIntent()1276 Intent getBaseIntent() { 1277 if (intent != null) return intent; 1278 if (affinityIntent != null) return affinityIntent; 1279 // Probably a task that contains other tasks, so return the intent for the top task? 1280 final Task topTask = getTopMostTask(); 1281 return (topTask != this && topTask != null) ? topTask.getBaseIntent() : null; 1282 } 1283 1284 /** Returns the first non-finishing activity from the bottom. */ getRootActivity()1285 ActivityRecord getRootActivity() { 1286 // TODO: Figure out why we historical ignore relinquish identity for this case... 1287 return getRootActivity(true /*ignoreRelinquishIdentity*/, false /*setToBottomIfNone*/); 1288 } 1289 getRootActivity(boolean setToBottomIfNone)1290 ActivityRecord getRootActivity(boolean setToBottomIfNone) { 1291 return getRootActivity(false /*ignoreRelinquishIdentity*/, setToBottomIfNone); 1292 } 1293 getRootActivity(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone)1294 ActivityRecord getRootActivity(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) { 1295 return mFindRootHelper.findRoot(ignoreRelinquishIdentity, setToBottomIfNone); 1296 } 1297 getTopNonFinishingActivity()1298 ActivityRecord getTopNonFinishingActivity() { 1299 return getTopNonFinishingActivity(true /* includeOverlays */); 1300 } 1301 getTopNonFinishingActivity(boolean includeOverlays)1302 ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) { 1303 return getTopActivity(false /*includeFinishing*/, includeOverlays); 1304 } 1305 topRunningActivityLocked()1306 ActivityRecord topRunningActivityLocked() { 1307 if (getParent() == null) { 1308 return null; 1309 } 1310 return getActivity(ActivityRecord::canBeTopRunning); 1311 } 1312 1313 /** 1314 * Return true if any activities in this task belongs to input uid. 1315 */ isUidPresent(int uid)1316 boolean isUidPresent(int uid) { 1317 final PooledPredicate p = PooledLambda.obtainPredicate( 1318 ActivityRecord::isUid, PooledLambda.__(ActivityRecord.class), uid); 1319 final boolean isUidPresent = getActivity(p) != null; 1320 p.recycle(); 1321 return isUidPresent; 1322 } 1323 topActivityWithStartingWindow()1324 ActivityRecord topActivityWithStartingWindow() { 1325 if (getParent() == null) { 1326 return null; 1327 } 1328 return getActivity((r) -> r.mStartingWindowState == STARTING_WINDOW_SHOWN 1329 && r.okToShowLocked()); 1330 } 1331 1332 /** 1333 * Return the number of running activities, and the number of non-finishing/initializing 1334 * activities in the provided {@param reportOut} respectively. 1335 */ getNumRunningActivities(TaskActivitiesReport reportOut)1336 private void getNumRunningActivities(TaskActivitiesReport reportOut) { 1337 reportOut.reset(); 1338 forAllActivities(reportOut); 1339 } 1340 1341 /** 1342 * Reorder the history stack so that the passed activity is brought to the front. 1343 */ moveActivityToFrontLocked(ActivityRecord newTop)1344 final void moveActivityToFrontLocked(ActivityRecord newTop) { 1345 if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity " 1346 + newTop + " to stack at top callers=" + Debug.getCallers(4)); 1347 1348 positionChildAtTop(newTop); 1349 updateEffectiveIntent(); 1350 } 1351 1352 @Override getActivityType()1353 public int getActivityType() { 1354 final int applicationType = super.getActivityType(); 1355 if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) { 1356 return applicationType; 1357 } 1358 return getTopChild().getActivityType(); 1359 } 1360 1361 @Override addChild(WindowContainer child, int index)1362 void addChild(WindowContainer child, int index) { 1363 // If this task had any child before we added this one. 1364 boolean hadChild = hasChild(); 1365 // getActivityType() looks at the top child, so we need to read the type before adding 1366 // a new child in case the new child is on top and UNDEFINED. 1367 final int activityType = getActivityType(); 1368 1369 index = getAdjustedChildPosition(child, index); 1370 super.addChild(child, index); 1371 1372 ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this); 1373 1374 // A rootable task that is now being added to be the child of an organized task. Making 1375 // sure the stack references is keep updated. 1376 if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) { 1377 getDisplayArea().addStackReferenceIfNeeded((ActivityStack) child); 1378 } 1379 1380 // Make sure the list of display UID allowlists is updated 1381 // now that this record is in a new task. 1382 mRootWindowContainer.updateUIDsPresentOnDisplay(); 1383 1384 final ActivityRecord r = child.asActivityRecord(); 1385 if (r == null) return; 1386 1387 r.inHistory = true; 1388 1389 // Only set this based on the first activity 1390 if (!hadChild) { 1391 if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) { 1392 // Normally non-standard activity type for the activity record will be set when the 1393 // object is created, however we delay setting the standard application type until 1394 // this point so that the task can set the type for additional activities added in 1395 // the else condition below. 1396 r.setActivityType(ACTIVITY_TYPE_STANDARD); 1397 } 1398 setActivityType(r.getActivityType()); 1399 isPersistable = r.isPersistable(); 1400 mCallingUid = r.launchedFromUid; 1401 mCallingPackage = r.launchedFromPackage; 1402 mCallingFeatureId = r.launchedFromFeatureId; 1403 // Clamp to [1, max]. 1404 maxRecents = Math.min(Math.max(r.info.maxRecents, 1), 1405 ActivityTaskManager.getMaxAppRecentsLimitStatic()); 1406 } else { 1407 // Otherwise make all added activities match this one. 1408 r.setActivityType(activityType); 1409 } 1410 1411 updateEffectiveIntent(); 1412 } 1413 addChild(ActivityRecord r)1414 void addChild(ActivityRecord r) { 1415 addChild(r, Integer.MAX_VALUE /* add on top */); 1416 } 1417 1418 @Override removeChild(WindowContainer child)1419 void removeChild(WindowContainer child) { 1420 removeChild(child, "removeChild"); 1421 } 1422 removeChild(WindowContainer r, String reason)1423 void removeChild(WindowContainer r, String reason) { 1424 // A rootable child task that is now being removed from an organized task. Making sure 1425 // the stack references is keep updated. 1426 if (mCreatedByOrganizer && r.asTask() != null) { 1427 getDisplayArea().removeStackReferenceIfNeeded((ActivityStack) r); 1428 } 1429 if (!mChildren.contains(r)) { 1430 Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this); 1431 return; 1432 } 1433 1434 if (DEBUG_TASK_MOVEMENT) { 1435 Slog.d(TAG_WM, "removeChild: child=" + r + " reason=" + reason); 1436 } 1437 super.removeChild(r); 1438 1439 if (inPinnedWindowingMode()) { 1440 // We normally notify listeners of task stack changes on pause, however pinned stack 1441 // activities are normally in the paused state so no notification will be sent there 1442 // before the activity is removed. We send it here so instead. 1443 mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged(); 1444 } 1445 1446 if (hasChild()) { 1447 updateEffectiveIntent(); 1448 1449 // The following block can be executed multiple times if there is more than one overlay. 1450 // {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup 1451 // of the task by id and exiting early if not found. 1452 if (onlyHasTaskOverlayActivities(true /*includeFinishing*/)) { 1453 // When destroying a task, tell the supervisor to remove it so that any activity it 1454 // has can be cleaned up correctly. This is currently the only place where we remove 1455 // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays 1456 // state into removeChild(), we just clear the task here before the other residual 1457 // work. 1458 // TODO: If the callers to removeChild() changes such that we have multiple places 1459 // where we are destroying the task, move this back into removeChild() 1460 mStackSupervisor.removeTask(this, false /* killProcess */, 1461 !REMOVE_FROM_RECENTS, reason); 1462 } 1463 } else if (!mReuseTask && !mCreatedByOrganizer) { 1464 // Remove entire task if it doesn't have any activity left and it isn't marked for reuse 1465 // or created by task organizer. 1466 if (!isRootTask()) { 1467 getStack().removeChild(this, reason); 1468 } 1469 EventLogTags.writeWmTaskRemoved(mTaskId, 1470 "removeChild: last r=" + r + " in t=" + this); 1471 removeIfPossible(); 1472 } 1473 } 1474 1475 /** 1476 * @return whether or not there are ONLY task overlay activities in the task. 1477 * If {@param includeFinishing} is set, then don't ignore finishing activities in the 1478 * check. If there are no task overlay activities, this call returns false. 1479 */ onlyHasTaskOverlayActivities(boolean includeFinishing)1480 boolean onlyHasTaskOverlayActivities(boolean includeFinishing) { 1481 int count = 0; 1482 for (int i = getChildCount() - 1; i >= 0; i--) { 1483 final ActivityRecord r = getChildAt(i).asActivityRecord(); 1484 if (r == null) { 1485 // Has a child that is other than Activity. 1486 return false; 1487 } 1488 if (!includeFinishing && r.finishing) { 1489 continue; 1490 } 1491 if (!r.isTaskOverlay()) { 1492 return false; 1493 } 1494 count++; 1495 } 1496 return count > 0; 1497 } 1498 autoRemoveFromRecents()1499 private boolean autoRemoveFromRecents() { 1500 // We will automatically remove the task either if it has explicitly asked for 1501 // this, or it is empty and has never contained an activity that got shown to 1502 // the user. 1503 return autoRemoveRecents || (!hasChild() && !getHasBeenVisible()); 1504 } 1505 1506 /** Completely remove all activities associated with an existing task. */ performClearTask(String reason)1507 void performClearTask(String reason) { 1508 // Broken down into to cases to avoid object create due to capturing mStack. 1509 if (getStack() == null) { 1510 forAllActivities((r) -> { 1511 if (r.finishing) return; 1512 // Task was restored from persistent storage. 1513 r.takeFromHistory(); 1514 removeChild(r); 1515 }); 1516 } else { 1517 forAllActivities((r) -> { 1518 if (r.finishing) return; 1519 // TODO: figure-out how to avoid object creation due to capture of reason variable. 1520 r.finishIfPossible(Activity.RESULT_CANCELED, 1521 null /* resultData */, null /* resultGrants */, reason, false /* oomAdj */); 1522 }); 1523 } 1524 } 1525 1526 /** 1527 * Completely remove all activities associated with an existing task. 1528 */ performClearTaskLocked()1529 void performClearTaskLocked() { 1530 mReuseTask = true; 1531 mStackSupervisor.beginDeferResume(); 1532 try { 1533 performClearTask("clear-task-all"); 1534 } finally { 1535 mStackSupervisor.endDeferResume(); 1536 mReuseTask = false; 1537 } 1538 } 1539 performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags)1540 ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) { 1541 mReuseTask = true; 1542 mStackSupervisor.beginDeferResume(); 1543 final ActivityRecord result; 1544 try { 1545 result = performClearTaskLocked(newR, launchFlags); 1546 } finally { 1547 mStackSupervisor.endDeferResume(); 1548 mReuseTask = false; 1549 } 1550 return result; 1551 } 1552 1553 /** 1554 * Perform clear operation as requested by 1555 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the 1556 * stack to the given task, then look for 1557 * an instance of that activity in the stack and, if found, finish all 1558 * activities on top of it and return the instance. 1559 * 1560 * @param newR Description of the new activity being started. 1561 * @return Returns the old activity that should be continued to be used, 1562 * or {@code null} if none was found. 1563 */ performClearTaskLocked(ActivityRecord newR, int launchFlags)1564 private ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) { 1565 final ActivityRecord r = findActivityInHistory(newR.mActivityComponent); 1566 if (r == null) return null; 1567 1568 final PooledFunction f = PooledLambda.obtainFunction(Task::finishActivityAbove, 1569 PooledLambda.__(ActivityRecord.class), r); 1570 forAllActivities(f); 1571 f.recycle(); 1572 1573 // Finally, if this is a normal launch mode (that is, not expecting onNewIntent()), then we 1574 // will finish the current instance of the activity so a new fresh one can be started. 1575 if (r.launchMode == ActivityInfo.LAUNCH_MULTIPLE 1576 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0 1577 && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) { 1578 if (!r.finishing) { 1579 r.finishIfPossible("clear-task-top", false /* oomAdj */); 1580 return null; 1581 } 1582 } 1583 1584 return r; 1585 } 1586 finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity)1587 private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity) { 1588 // Stop operation once we reach the boundary activity. 1589 if (r == boundaryActivity) return true; 1590 1591 if (!r.finishing) { 1592 final ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */); 1593 if (opts != null) { 1594 // TODO: Why is this updating the boundary activity vs. the current activity??? 1595 boundaryActivity.updateOptionsLocked(opts); 1596 } 1597 r.finishIfPossible("clear-task-stack", false /* oomAdj */); 1598 } 1599 1600 return false; 1601 } 1602 lockTaskAuthToString()1603 String lockTaskAuthToString() { 1604 switch (mLockTaskAuth) { 1605 case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK"; 1606 case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE"; 1607 case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE"; 1608 case LOCK_TASK_AUTH_ALLOWLISTED: return "LOCK_TASK_AUTH_ALLOWLISTED"; 1609 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV"; 1610 default: return "unknown=" + mLockTaskAuth; 1611 } 1612 } 1613 setLockTaskAuth()1614 void setLockTaskAuth() { 1615 setLockTaskAuth(getRootActivity()); 1616 } 1617 setLockTaskAuth(@ullable ActivityRecord r)1618 private void setLockTaskAuth(@Nullable ActivityRecord r) { 1619 if (r == null) { 1620 mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE; 1621 return; 1622 } 1623 1624 final String pkg = (realActivity != null) ? realActivity.getPackageName() : null; 1625 final LockTaskController lockTaskController = mAtmService.getLockTaskController(); 1626 switch (r.lockTaskLaunchMode) { 1627 case LOCK_TASK_LAUNCH_MODE_DEFAULT: 1628 mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg) 1629 ? LOCK_TASK_AUTH_ALLOWLISTED : LOCK_TASK_AUTH_PINNABLE; 1630 break; 1631 1632 case LOCK_TASK_LAUNCH_MODE_NEVER: 1633 mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK; 1634 break; 1635 1636 case LOCK_TASK_LAUNCH_MODE_ALWAYS: 1637 mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV; 1638 break; 1639 1640 case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED: 1641 mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg) 1642 ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE; 1643 break; 1644 } 1645 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this 1646 + " mLockTaskAuth=" + lockTaskAuthToString()); 1647 } 1648 1649 @Override supportsSplitScreenWindowingMode()1650 public boolean supportsSplitScreenWindowingMode() { 1651 final Task topTask = getTopMostTask(); 1652 return super.supportsSplitScreenWindowingMode() 1653 && (topTask == null || topTask.supportsSplitScreenWindowingModeInner()); 1654 } 1655 supportsSplitScreenWindowingModeInner()1656 private boolean supportsSplitScreenWindowingModeInner() { 1657 // A task can not be docked even if it is considered resizeable because it only supports 1658 // picture-in-picture mode but has a non-resizeable resizeMode 1659 return super.supportsSplitScreenWindowingMode() 1660 && mAtmService.mSupportsSplitScreenMultiWindow 1661 && (mAtmService.mForceResizableActivities 1662 || (isResizeable(false /* checkSupportsPip */) 1663 && !ActivityInfo.isPreserveOrientationMode(mResizeMode))); 1664 } 1665 1666 /** 1667 * Check whether this task can be launched on the specified display. 1668 * 1669 * @param displayId Target display id. 1670 * @return {@code true} if either it is the default display or this activity can be put on a 1671 * secondary display. 1672 */ canBeLaunchedOnDisplay(int displayId)1673 boolean canBeLaunchedOnDisplay(int displayId) { 1674 return mStackSupervisor.canPlaceEntityOnDisplay(displayId, 1675 -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */); 1676 } 1677 1678 /** 1679 * Check that a given bounds matches the application requested orientation. 1680 * 1681 * @param bounds The bounds to be tested. 1682 * @return True if the requested bounds are okay for a resizing request. 1683 */ canResizeToBounds(Rect bounds)1684 private boolean canResizeToBounds(Rect bounds) { 1685 if (bounds == null || !inFreeformWindowingMode()) { 1686 // Note: If not on the freeform workspace, we ignore the bounds. 1687 return true; 1688 } 1689 final boolean landscape = bounds.width() > bounds.height(); 1690 final Rect configBounds = getRequestedOverrideBounds(); 1691 if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) { 1692 return configBounds.isEmpty() 1693 || landscape == (configBounds.width() > configBounds.height()); 1694 } 1695 return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape) 1696 && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape); 1697 } 1698 1699 /** 1700 * @return {@code true} if the task is being cleared for the purposes of being reused. 1701 */ isClearingToReuseTask()1702 boolean isClearingToReuseTask() { 1703 return mReuseTask; 1704 } 1705 1706 /** 1707 * Find the activity in the history stack within the given task. Returns 1708 * the index within the history at which it's found, or < 0 if not found. 1709 */ findActivityInHistory(ComponentName component)1710 ActivityRecord findActivityInHistory(ComponentName component) { 1711 final PooledPredicate p = PooledLambda.obtainPredicate(Task::matchesActivityInHistory, 1712 PooledLambda.__(ActivityRecord.class), component); 1713 final ActivityRecord r = getActivity(p); 1714 p.recycle(); 1715 return r; 1716 } 1717 matchesActivityInHistory( ActivityRecord r, ComponentName activityComponent)1718 private static boolean matchesActivityInHistory( 1719 ActivityRecord r, ComponentName activityComponent) { 1720 return !r.finishing && r.mActivityComponent.equals(activityComponent); 1721 } 1722 1723 /** Updates the last task description values. */ updateTaskDescription()1724 void updateTaskDescription() { 1725 final ActivityRecord root = getRootActivity(true); 1726 if (root == null) return; 1727 1728 final TaskDescription taskDescription = new TaskDescription(); 1729 final PooledFunction f = PooledLambda.obtainFunction( 1730 Task::setTaskDescriptionFromActivityAboveRoot, 1731 PooledLambda.__(ActivityRecord.class), root, taskDescription); 1732 forAllActivities(f); 1733 f.recycle(); 1734 taskDescription.setResizeMode(mResizeMode); 1735 taskDescription.setMinWidth(mMinWidth); 1736 taskDescription.setMinHeight(mMinHeight); 1737 setTaskDescription(taskDescription); 1738 // Update the task affiliation color if we are the parent of the group 1739 if (mTaskId == mAffiliatedTaskId) { 1740 mAffiliatedTaskColor = taskDescription.getPrimaryColor(); 1741 } 1742 mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged( 1743 getTaskInfo()); 1744 1745 final WindowContainer parent = getParent(); 1746 if (parent != null) { 1747 final Task t = parent.asTask(); 1748 if (t != null) { 1749 t.updateTaskDescription(); 1750 } 1751 } 1752 1753 if (isOrganized()) { 1754 mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */); 1755 } 1756 } 1757 setTaskDescriptionFromActivityAboveRoot( ActivityRecord r, ActivityRecord root, TaskDescription td)1758 private static boolean setTaskDescriptionFromActivityAboveRoot( 1759 ActivityRecord r, ActivityRecord root, TaskDescription td) { 1760 if (!r.isTaskOverlay() && r.taskDescription != null) { 1761 final TaskDescription atd = r.taskDescription; 1762 if (td.getLabel() == null) { 1763 td.setLabel(atd.getLabel()); 1764 } 1765 if (td.getRawIcon() == null) { 1766 td.setIcon(atd.getRawIcon()); 1767 } 1768 if (td.getIconFilename() == null) { 1769 td.setIconFilename(atd.getIconFilename()); 1770 } 1771 if (td.getPrimaryColor() == 0) { 1772 td.setPrimaryColor(atd.getPrimaryColor()); 1773 } 1774 if (td.getBackgroundColor() == 0) { 1775 td.setBackgroundColor(atd.getBackgroundColor()); 1776 } 1777 if (td.getStatusBarColor() == 0) { 1778 td.setStatusBarColor(atd.getStatusBarColor()); 1779 td.setEnsureStatusBarContrastWhenTransparent( 1780 atd.getEnsureStatusBarContrastWhenTransparent()); 1781 } 1782 if (td.getNavigationBarColor() == 0) { 1783 td.setNavigationBarColor(atd.getNavigationBarColor()); 1784 td.setEnsureNavigationBarContrastWhenTransparent( 1785 atd.getEnsureNavigationBarContrastWhenTransparent()); 1786 } 1787 1788 } 1789 1790 // End search once we get to root. 1791 return r == root; 1792 } 1793 1794 // TODO (AM refactor): Invoke automatically when there is a change in children 1795 @VisibleForTesting updateEffectiveIntent()1796 void updateEffectiveIntent() { 1797 final ActivityRecord root = getRootActivity(true /*setToBottomIfNone*/); 1798 if (root != null) { 1799 setIntent(root); 1800 // Update the task description when the activities change 1801 updateTaskDescription(); 1802 } 1803 } 1804 adjustForMinimalTaskDimensions(@onNull Rect bounds, @NonNull Rect previousBounds, @NonNull Configuration parentConfig)1805 void adjustForMinimalTaskDimensions(@NonNull Rect bounds, @NonNull Rect previousBounds, 1806 @NonNull Configuration parentConfig) { 1807 int minWidth = mMinWidth; 1808 int minHeight = mMinHeight; 1809 // If the task has no requested minimal size, we'd like to enforce a minimal size 1810 // so that the user can not render the task too small to manipulate. We don't need 1811 // to do this for the pinned stack as the bounds are controlled by the system. 1812 if (!inPinnedWindowingMode()) { 1813 final int defaultMinSizeDp = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp; 1814 final float density = (float) parentConfig.densityDpi / DisplayMetrics.DENSITY_DEFAULT; 1815 final int defaultMinSize = (int) (defaultMinSizeDp * density); 1816 1817 if (minWidth == INVALID_MIN_SIZE) { 1818 minWidth = defaultMinSize; 1819 } 1820 if (minHeight == INVALID_MIN_SIZE) { 1821 minHeight = defaultMinSize; 1822 } 1823 } 1824 if (bounds.isEmpty()) { 1825 // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they 1826 // do, we can just skip. 1827 final Rect parentBounds = parentConfig.windowConfiguration.getBounds(); 1828 if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) { 1829 return; 1830 } 1831 bounds.set(parentBounds); 1832 } 1833 final boolean adjustWidth = minWidth > bounds.width(); 1834 final boolean adjustHeight = minHeight > bounds.height(); 1835 if (!(adjustWidth || adjustHeight)) { 1836 return; 1837 } 1838 1839 if (adjustWidth) { 1840 if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) { 1841 bounds.left = bounds.right - minWidth; 1842 } else { 1843 // Either left bounds match, or neither match, or the previous bounds were 1844 // fullscreen and we default to keeping left. 1845 bounds.right = bounds.left + minWidth; 1846 } 1847 } 1848 if (adjustHeight) { 1849 if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) { 1850 bounds.top = bounds.bottom - minHeight; 1851 } else { 1852 // Either top bounds match, or neither match, or the previous bounds were 1853 // fullscreen and we default to keeping top. 1854 bounds.bottom = bounds.top + minHeight; 1855 } 1856 } 1857 } 1858 setLastNonFullscreenBounds(Rect bounds)1859 void setLastNonFullscreenBounds(Rect bounds) { 1860 if (mLastNonFullscreenBounds == null) { 1861 mLastNonFullscreenBounds = new Rect(bounds); 1862 } else { 1863 mLastNonFullscreenBounds.set(bounds); 1864 } 1865 } 1866 1867 /** 1868 * This should be called when an child activity changes state. This should only 1869 * be called from 1870 * {@link ActivityRecord#setState(ActivityState, String)} . 1871 * @param record The {@link ActivityRecord} whose state has changed. 1872 * @param state The new state. 1873 * @param reason The reason for the change. 1874 */ onActivityStateChanged(ActivityRecord record, ActivityState state, String reason)1875 void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) { 1876 final Task parentTask = getParent().asTask(); 1877 if (parentTask != null) { 1878 parentTask.onActivityStateChanged(record, state, reason); 1879 // We still want to update the resumed activity if the parent task is created by 1880 // organizer in order to keep the information synced once got reparented out from the 1881 // organized task. 1882 if (!parentTask.mCreatedByOrganizer) { 1883 return; 1884 } 1885 } 1886 1887 if (record == mResumedActivity && state != RESUMED) { 1888 setResumedActivity(null, reason + " - onActivityStateChanged"); 1889 } 1890 1891 if (state == RESUMED) { 1892 if (ActivityTaskManagerDebugConfig.DEBUG_STACK) { 1893 Slog.v(TAG_STACK, "set resumed activity to:" + record + " reason:" + reason); 1894 } 1895 setResumedActivity(record, reason + " - onActivityStateChanged"); 1896 if (record == mRootWindowContainer.getTopResumedActivity()) { 1897 mAtmService.setResumedActivityUncheckLocked(record, reason); 1898 } 1899 mStackSupervisor.mRecentTasks.add(record.getTask()); 1900 } 1901 } 1902 1903 @Override onConfigurationChanged(Configuration newParentConfig)1904 public void onConfigurationChanged(Configuration newParentConfig) { 1905 // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so 1906 // restore the last recorded non-fullscreen bounds. 1907 final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds(); 1908 boolean nextPersistTaskBounds = 1909 getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds(); 1910 if (getRequestedOverrideWindowingMode() == WINDOWING_MODE_UNDEFINED) { 1911 nextPersistTaskBounds = newParentConfig.windowConfiguration.persistTaskBounds(); 1912 } 1913 if (!prevPersistTaskBounds && nextPersistTaskBounds 1914 && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) { 1915 // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop. 1916 getRequestedOverrideConfiguration().windowConfiguration 1917 .setBounds(mLastNonFullscreenBounds); 1918 } 1919 1920 final int prevWinMode = getWindowingMode(); 1921 mTmpPrevBounds.set(getBounds()); 1922 final boolean wasInMultiWindowMode = inMultiWindowMode(); 1923 final boolean wasInPictureInPicture = inPinnedWindowingMode(); 1924 super.onConfigurationChanged(newParentConfig); 1925 // Only need to update surface size here since the super method will handle updating 1926 // surface position. 1927 updateSurfaceSize(getSyncTransaction()); 1928 1929 if (wasInPictureInPicture != inPinnedWindowingMode()) { 1930 mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, getStack()); 1931 } else if (wasInMultiWindowMode != inMultiWindowMode()) { 1932 mStackSupervisor.scheduleUpdateMultiWindowMode(this); 1933 } 1934 1935 final int newWinMode = getWindowingMode(); 1936 if ((prevWinMode != newWinMode) && (mDisplayContent != null) 1937 && shouldStartChangeTransition(prevWinMode, newWinMode)) { 1938 initializeChangeTransition(mTmpPrevBounds); 1939 } 1940 1941 // If the configuration supports persistent bounds (eg. Freeform), keep track of the 1942 // current (non-fullscreen) bounds for persistence. 1943 if (getWindowConfiguration().persistTaskBounds()) { 1944 final Rect currentBounds = getRequestedOverrideBounds(); 1945 if (!currentBounds.isEmpty()) { 1946 setLastNonFullscreenBounds(currentBounds); 1947 } 1948 } 1949 1950 saveLaunchingStateIfNeeded(); 1951 final boolean taskOrgChanged = updateTaskOrganizerState(false /* forceUpdate */); 1952 // If the task organizer has changed, then it will already be receiving taskAppeared with 1953 // the latest task-info thus the task-info won't have changed. 1954 if (!taskOrgChanged && isOrganized()) { 1955 mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */); 1956 } 1957 } 1958 1959 /** 1960 * Initializes a change transition. See {@link SurfaceFreezer} for more information. 1961 */ initializeChangeTransition(Rect startBounds)1962 private void initializeChangeTransition(Rect startBounds) { 1963 mDisplayContent.prepareAppTransition(TRANSIT_TASK_CHANGE_WINDOWING_MODE, 1964 false /* alwaysKeepCurrent */, 0, false /* forceOverride */); 1965 mDisplayContent.mChangingContainers.add(this); 1966 1967 mSurfaceFreezer.freeze(getPendingTransaction(), startBounds); 1968 } 1969 shouldStartChangeTransition(int prevWinMode, int newWinMode)1970 private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) { 1971 if (mWmService.mDisableTransitionAnimation 1972 || !isVisible() 1973 || getDisplayContent().mAppTransition.isTransitionSet() 1974 || getSurfaceControl() == null 1975 || !isLeafTask()) { 1976 return false; 1977 } 1978 // Only do an animation into and out-of freeform mode for now. Other mode 1979 // transition animations are currently handled by system-ui. 1980 return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM); 1981 } 1982 1983 @Override migrateToNewSurfaceControl()1984 void migrateToNewSurfaceControl() { 1985 super.migrateToNewSurfaceControl(); 1986 mLastSurfaceSize.x = 0; 1987 mLastSurfaceSize.y = 0; 1988 updateSurfaceSize(getPendingTransaction()); 1989 } 1990 updateSurfaceSize(SurfaceControl.Transaction transaction)1991 void updateSurfaceSize(SurfaceControl.Transaction transaction) { 1992 if (mSurfaceControl == null || isOrganized()) { 1993 return; 1994 } 1995 1996 // Apply crop to root tasks only and clear the crops of the descendant tasks. 1997 int width = 0; 1998 int height = 0; 1999 if (isRootTask()) { 2000 final Rect taskBounds = getBounds(); 2001 width = taskBounds.width(); 2002 height = taskBounds.height(); 2003 2004 final int outset = getTaskOutset(); 2005 width += 2 * outset; 2006 height += 2 * outset; 2007 } 2008 if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) { 2009 return; 2010 } 2011 transaction.setWindowCrop(mSurfaceControl, width, height); 2012 mLastSurfaceSize.set(width, height); 2013 } 2014 2015 /** 2016 * Calculate an amount by which to expand the task bounds in each direction. 2017 * Used to make room for shadows in the pinned windowing mode. 2018 */ getTaskOutset()2019 int getTaskOutset() { 2020 // If we are drawing shadows on the task then don't outset the stack. 2021 if (mWmService.mRenderShadowsInCompositor) { 2022 return 0; 2023 } 2024 DisplayContent displayContent = getDisplayContent(); 2025 if (inPinnedWindowingMode() && displayContent != null) { 2026 final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics(); 2027 2028 // We multiply by two to match the client logic for converting view elevation 2029 // to insets, as in {@link WindowManager.LayoutParams#setSurfaceInsets} 2030 return (int) Math.ceil( 2031 mWmService.dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP, displayMetrics) 2032 * 2); 2033 } 2034 return 0; 2035 } 2036 2037 @VisibleForTesting getLastSurfaceSize()2038 Point getLastSurfaceSize() { 2039 return mLastSurfaceSize; 2040 } 2041 2042 @VisibleForTesting isInChangeTransition()2043 boolean isInChangeTransition() { 2044 return mSurfaceFreezer.hasLeash() || AppTransition.isChangeTransit(mTransit); 2045 } 2046 2047 @Override getFreezeSnapshotTarget()2048 public SurfaceControl getFreezeSnapshotTarget() { 2049 final int transit = mDisplayContent.mAppTransition.getAppTransition(); 2050 if (!AppTransition.isChangeTransit(transit)) { 2051 return null; 2052 } 2053 // Skip creating snapshot if this transition is controlled by a remote animator which 2054 // doesn't need it. 2055 final ArraySet<Integer> activityTypes = new ArraySet<>(); 2056 activityTypes.add(getActivityType()); 2057 final RemoteAnimationAdapter adapter = 2058 mDisplayContent.mAppTransitionController.getRemoteAnimationOverride( 2059 this, transit, activityTypes); 2060 if (adapter != null && !adapter.getChangeNeedsSnapshot()) { 2061 return null; 2062 } 2063 return getSurfaceControl(); 2064 } 2065 2066 @Override writeIdentifierToProto(ProtoOutputStream proto, long fieldId)2067 void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { 2068 final long token = proto.start(fieldId); 2069 proto.write(HASH_CODE, System.identityHashCode(this)); 2070 proto.write(USER_ID, mUserId); 2071 proto.write(TITLE, intent != null && intent.getComponent() != null 2072 ? intent.getComponent().flattenToShortString() : "Task"); 2073 proto.end(token); 2074 } 2075 2076 /** 2077 * Saves launching state if necessary so that we can launch the activity to its latest state. 2078 * It only saves state if this task has been shown to user and it's in fullscreen or freeform 2079 * mode on freeform displays. 2080 */ saveLaunchingStateIfNeeded()2081 private void saveLaunchingStateIfNeeded() { 2082 saveLaunchingStateIfNeeded(getDisplayContent()); 2083 } 2084 saveLaunchingStateIfNeeded(DisplayContent display)2085 private void saveLaunchingStateIfNeeded(DisplayContent display) { 2086 if (!getHasBeenVisible()) { 2087 // Not ever visible to user. 2088 return; 2089 } 2090 2091 final int windowingMode = getWindowingMode(); 2092 if (windowingMode != WINDOWING_MODE_FULLSCREEN 2093 && windowingMode != WINDOWING_MODE_FREEFORM) { 2094 return; 2095 } 2096 2097 // Don't persist state if display isn't in freeform mode. Then the task will be launched 2098 // back to its last state in a freeform display when it's launched in a freeform display 2099 // next time. 2100 if (getWindowConfiguration().getDisplayWindowingMode() != WINDOWING_MODE_FREEFORM) { 2101 return; 2102 } 2103 2104 // Saves the new state so that we can launch the activity at the same location. 2105 mStackSupervisor.mLaunchParamsPersister.saveTask(this, display); 2106 } 2107 2108 /** 2109 * Adjust bounds to stay within stack bounds. 2110 * 2111 * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way 2112 * that keep them unchanged, but be contained within the stack bounds. 2113 * 2114 * @param bounds Bounds to be adjusted. 2115 * @param stackBounds Bounds within which the other bounds should remain. 2116 * @param overlapPxX The amount of px required to be visible in the X dimension. 2117 * @param overlapPxY The amount of px required to be visible in the Y dimension. 2118 */ fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX, int overlapPxY)2119 private static void fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX, 2120 int overlapPxY) { 2121 if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) { 2122 return; 2123 } 2124 2125 // For each side of the parent (eg. left), check if the opposing side of the window (eg. 2126 // right) is at least overlap pixels away. If less, offset the window by that difference. 2127 int horizontalDiff = 0; 2128 // If window is smaller than overlap, use it's smallest dimension instead 2129 int overlapLR = Math.min(overlapPxX, bounds.width()); 2130 if (bounds.right < (stackBounds.left + overlapLR)) { 2131 horizontalDiff = overlapLR - (bounds.right - stackBounds.left); 2132 } else if (bounds.left > (stackBounds.right - overlapLR)) { 2133 horizontalDiff = -(overlapLR - (stackBounds.right - bounds.left)); 2134 } 2135 int verticalDiff = 0; 2136 int overlapTB = Math.min(overlapPxY, bounds.width()); 2137 if (bounds.bottom < (stackBounds.top + overlapTB)) { 2138 verticalDiff = overlapTB - (bounds.bottom - stackBounds.top); 2139 } else if (bounds.top > (stackBounds.bottom - overlapTB)) { 2140 verticalDiff = -(overlapTB - (stackBounds.bottom - bounds.top)); 2141 } 2142 bounds.offset(horizontalDiff, verticalDiff); 2143 } 2144 2145 /** 2146 * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than 2147 * intersectBounds on a side, then the respective side will not be intersected. 2148 * 2149 * The assumption is that if inOutBounds is initially larger than intersectBounds, then the 2150 * inset on that side is no-longer applicable. This scenario happens when a task's minimal 2151 * bounds are larger than the provided parent/display bounds. 2152 * 2153 * @param inOutBounds the bounds to intersect. 2154 * @param intersectBounds the bounds to intersect with. 2155 * @param intersectInsets insets to apply to intersectBounds before intersecting. 2156 */ intersectWithInsetsIfFits( Rect inOutBounds, Rect intersectBounds, Rect intersectInsets)2157 static void intersectWithInsetsIfFits( 2158 Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) { 2159 if (inOutBounds.right <= intersectBounds.right) { 2160 inOutBounds.right = 2161 Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right); 2162 } 2163 if (inOutBounds.bottom <= intersectBounds.bottom) { 2164 inOutBounds.bottom = 2165 Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom); 2166 } 2167 if (inOutBounds.left >= intersectBounds.left) { 2168 inOutBounds.left = 2169 Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left); 2170 } 2171 if (inOutBounds.top >= intersectBounds.top) { 2172 inOutBounds.top = 2173 Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top); 2174 } 2175 } 2176 2177 /** 2178 * Gets bounds with non-decor and stable insets applied respectively. 2179 * 2180 * If bounds overhangs the display, those edges will not get insets. See 2181 * {@link #intersectWithInsetsIfFits} 2182 * 2183 * @param outNonDecorBounds where to place bounds with non-decor insets applied. 2184 * @param outStableBounds where to place bounds with stable insets applied. 2185 * @param bounds the bounds to inset. 2186 */ calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, DisplayInfo displayInfo)2187 private void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, 2188 DisplayInfo displayInfo) { 2189 outNonDecorBounds.set(bounds); 2190 outStableBounds.set(bounds); 2191 if (getStack() == null || getStack().getDisplay() == null) { 2192 return; 2193 } 2194 DisplayPolicy policy = getStack().getDisplay().mDisplayContent.getDisplayPolicy(); 2195 if (policy == null) { 2196 return; 2197 } 2198 mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); 2199 2200 policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth, 2201 displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets); 2202 intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets); 2203 2204 policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation); 2205 intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets); 2206 } 2207 2208 /** 2209 * Forces the app bounds related configuration can be computed by 2210 * {@link #computeConfigResourceOverrides(Configuration, Configuration, DisplayInfo, 2211 * ActivityRecord.CompatDisplayInsets)}. 2212 */ invalidateAppBoundsConfig(@onNull Configuration inOutConfig)2213 private static void invalidateAppBoundsConfig(@NonNull Configuration inOutConfig) { 2214 final Rect appBounds = inOutConfig.windowConfiguration.getAppBounds(); 2215 if (appBounds != null) { 2216 appBounds.setEmpty(); 2217 } 2218 inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED; 2219 inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED; 2220 } 2221 computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo)2222 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, 2223 @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) { 2224 if (overrideDisplayInfo != null) { 2225 // Make sure the screen related configs can be computed by the provided display info. 2226 inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED; 2227 invalidateAppBoundsConfig(inOutConfig); 2228 } 2229 computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo, 2230 null /* compatInsets */); 2231 } 2232 computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig)2233 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, 2234 @NonNull Configuration parentConfig) { 2235 computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */, 2236 null /* compatInsets */); 2237 } 2238 computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)2239 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, 2240 @NonNull Configuration parentConfig, 2241 @Nullable ActivityRecord.CompatDisplayInsets compatInsets) { 2242 if (compatInsets != null) { 2243 // Make sure the app bounds can be computed by the compat insets. 2244 invalidateAppBoundsConfig(inOutConfig); 2245 } 2246 computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */, 2247 compatInsets); 2248 } 2249 2250 /** 2251 * Calculates configuration values used by the client to get resources. This should be run 2252 * using app-facing bounds (bounds unmodified by animations or transient interactions). 2253 * 2254 * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely 2255 * configuring an "inherit-bounds" window which means that all configuration settings would 2256 * just be inherited from the parent configuration. 2257 **/ computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)2258 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, 2259 @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo, 2260 @Nullable ActivityRecord.CompatDisplayInsets compatInsets) { 2261 int windowingMode = inOutConfig.windowConfiguration.getWindowingMode(); 2262 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 2263 windowingMode = parentConfig.windowConfiguration.getWindowingMode(); 2264 } 2265 2266 float density = inOutConfig.densityDpi; 2267 if (density == Configuration.DENSITY_DPI_UNDEFINED) { 2268 density = parentConfig.densityDpi; 2269 } 2270 density *= DisplayMetrics.DENSITY_DEFAULT_SCALE; 2271 2272 // The bounds may have been overridden at this level. If the parent cannot cover these 2273 // bounds, the configuration is still computed according to the override bounds. 2274 final boolean insideParentBounds; 2275 2276 final Rect parentBounds = parentConfig.windowConfiguration.getBounds(); 2277 final Rect resolvedBounds = inOutConfig.windowConfiguration.getBounds(); 2278 if (resolvedBounds == null || resolvedBounds.isEmpty()) { 2279 mTmpFullBounds.set(parentBounds); 2280 insideParentBounds = true; 2281 } else { 2282 mTmpFullBounds.set(resolvedBounds); 2283 insideParentBounds = parentBounds.contains(resolvedBounds); 2284 } 2285 2286 // Non-null compatibility insets means the activity prefers to keep its original size, so 2287 // out bounds doesn't need to be restricted by the parent or current display 2288 final boolean customContainerPolicy = compatInsets != null; 2289 2290 Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); 2291 if (outAppBounds == null || outAppBounds.isEmpty()) { 2292 // App-bounds hasn't been overridden, so calculate a value for it. 2293 inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds); 2294 outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); 2295 2296 if (!customContainerPolicy && windowingMode != WINDOWING_MODE_FREEFORM) { 2297 final Rect containingAppBounds; 2298 if (insideParentBounds) { 2299 containingAppBounds = parentConfig.windowConfiguration.getAppBounds(); 2300 } else { 2301 // Restrict appBounds to display non-decor rather than parent because the 2302 // override bounds are beyond the parent. Otherwise, it won't match the 2303 // overridden bounds. 2304 final TaskDisplayArea displayArea = getDisplayArea(); 2305 containingAppBounds = displayArea != null 2306 ? displayArea.getWindowConfiguration().getAppBounds() : null; 2307 } 2308 if (containingAppBounds != null && !containingAppBounds.isEmpty()) { 2309 outAppBounds.intersect(containingAppBounds); 2310 } 2311 } 2312 } 2313 2314 if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED 2315 || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { 2316 if (!customContainerPolicy && WindowConfiguration.isFloating(windowingMode)) { 2317 mTmpNonDecorBounds.set(mTmpFullBounds); 2318 mTmpStableBounds.set(mTmpFullBounds); 2319 } else if (!customContainerPolicy 2320 && (overrideDisplayInfo != null || getDisplayContent() != null)) { 2321 final DisplayInfo di = overrideDisplayInfo != null 2322 ? overrideDisplayInfo 2323 : getDisplayContent().getDisplayInfo(); 2324 2325 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen 2326 // area, i.e. the screen area without the system bars. 2327 // The non decor inset are areas that could never be removed in Honeycomb. See 2328 // {@link WindowManagerPolicy#getNonDecorInsetsLw}. 2329 calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di); 2330 } else { 2331 // Apply the given non-decor and stable insets to calculate the corresponding bounds 2332 // for screen size of configuration. 2333 int rotation = inOutConfig.windowConfiguration.getRotation(); 2334 if (rotation == ROTATION_UNDEFINED) { 2335 rotation = parentConfig.windowConfiguration.getRotation(); 2336 } 2337 if (rotation != ROTATION_UNDEFINED && customContainerPolicy) { 2338 mTmpNonDecorBounds.set(mTmpFullBounds); 2339 mTmpStableBounds.set(mTmpFullBounds); 2340 compatInsets.getBoundsByRotation(mTmpBounds, rotation); 2341 intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds, 2342 compatInsets.mNonDecorInsets[rotation]); 2343 intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds, 2344 compatInsets.mStableInsets[rotation]); 2345 outAppBounds.set(mTmpNonDecorBounds); 2346 } else { 2347 // Set to app bounds because it excludes decor insets. 2348 mTmpNonDecorBounds.set(outAppBounds); 2349 mTmpStableBounds.set(outAppBounds); 2350 } 2351 } 2352 2353 if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) { 2354 final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density); 2355 inOutConfig.screenWidthDp = (insideParentBounds && !customContainerPolicy) 2356 ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp) 2357 : overrideScreenWidthDp; 2358 } 2359 if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { 2360 final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density); 2361 inOutConfig.screenHeightDp = (insideParentBounds && !customContainerPolicy) 2362 ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp) 2363 : overrideScreenHeightDp; 2364 } 2365 2366 if (inOutConfig.smallestScreenWidthDp 2367 == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { 2368 if (WindowConfiguration.isFloating(windowingMode)) { 2369 // For floating tasks, calculate the smallest width from the bounds of the task 2370 inOutConfig.smallestScreenWidthDp = (int) ( 2371 Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density); 2372 } 2373 // otherwise, it will just inherit 2374 } 2375 } 2376 2377 if (inOutConfig.orientation == ORIENTATION_UNDEFINED) { 2378 inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp) 2379 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; 2380 } 2381 if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) { 2382 // For calculating screen layout, we need to use the non-decor inset screen area for the 2383 // calculation for compatibility reasons, i.e. screen area without system bars that 2384 // could never go away in Honeycomb. 2385 int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density); 2386 int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density); 2387 // Use overrides if provided. If both overrides are provided, mTmpNonDecorBounds is 2388 // undefined so it can't be used. 2389 if (inOutConfig.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) { 2390 compatScreenWidthDp = inOutConfig.screenWidthDp; 2391 } 2392 if (inOutConfig.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { 2393 compatScreenHeightDp = inOutConfig.screenHeightDp; 2394 } 2395 // Reducing the screen layout starting from its parent config. 2396 inOutConfig.screenLayout = computeScreenLayoutOverride(parentConfig.screenLayout, 2397 compatScreenWidthDp, compatScreenHeightDp); 2398 } 2399 } 2400 2401 /** Computes LONG, SIZE and COMPAT parts of {@link Configuration#screenLayout}. */ computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp, int screenHeightDp)2402 static int computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp, 2403 int screenHeightDp) { 2404 sourceScreenLayout = sourceScreenLayout 2405 & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK); 2406 final int longSize = Math.max(screenWidthDp, screenHeightDp); 2407 final int shortSize = Math.min(screenWidthDp, screenHeightDp); 2408 return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize); 2409 } 2410 2411 @Override resolveOverrideConfiguration(Configuration newParentConfig)2412 void resolveOverrideConfiguration(Configuration newParentConfig) { 2413 mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds()); 2414 super.resolveOverrideConfiguration(newParentConfig); 2415 2416 int windowingMode = 2417 getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode(); 2418 2419 // Resolve override windowing mode to fullscreen for home task (even on freeform 2420 // display), or split-screen if in split-screen mode. 2421 if (getActivityType() == ACTIVITY_TYPE_HOME && windowingMode == WINDOWING_MODE_UNDEFINED) { 2422 final int parentWindowingMode = newParentConfig.windowConfiguration.getWindowingMode(); 2423 windowingMode = WindowConfiguration.isSplitScreenWindowingMode(parentWindowingMode) 2424 ? parentWindowingMode : WINDOWING_MODE_FULLSCREEN; 2425 getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode); 2426 } 2427 2428 if (isLeafTask()) { 2429 resolveLeafOnlyOverrideConfigs(newParentConfig, mTmpBounds /* previousBounds */); 2430 } 2431 computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig); 2432 } 2433 resolveLeafOnlyOverrideConfigs(Configuration newParentConfig, Rect previousBounds)2434 private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig, 2435 Rect previousBounds) { 2436 int windowingMode = 2437 getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode(); 2438 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 2439 windowingMode = newParentConfig.windowConfiguration.getWindowingMode(); 2440 } 2441 Rect outOverrideBounds = 2442 getResolvedOverrideConfiguration().windowConfiguration.getBounds(); 2443 2444 if (windowingMode == WINDOWING_MODE_FULLSCREEN) { 2445 computeFullscreenBounds(outOverrideBounds, null /* refActivity */, 2446 newParentConfig.windowConfiguration.getBounds(), 2447 newParentConfig.orientation); 2448 // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if 2449 // the parent or display is smaller than the size, the content may be cropped. 2450 return; 2451 } 2452 2453 adjustForMinimalTaskDimensions(outOverrideBounds, previousBounds, newParentConfig); 2454 if (windowingMode == WINDOWING_MODE_FREEFORM) { 2455 // by policy, make sure the window remains within parent somewhere 2456 final float density = 2457 ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT; 2458 final Rect parentBounds = 2459 new Rect(newParentConfig.windowConfiguration.getBounds()); 2460 final DisplayContent display = getDisplayContent(); 2461 if (display != null) { 2462 // If a freeform window moves below system bar, there is no way to move it again 2463 // by touch. Because its caption is covered by system bar. So we exclude them 2464 // from stack bounds. and then caption will be shown inside stable area. 2465 final Rect stableBounds = new Rect(); 2466 display.getStableRect(stableBounds); 2467 parentBounds.intersect(stableBounds); 2468 } 2469 2470 fitWithinBounds(outOverrideBounds, parentBounds, 2471 (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP), 2472 (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP)); 2473 2474 // Prevent to overlap caption with stable insets. 2475 final int offsetTop = parentBounds.top - outOverrideBounds.top; 2476 if (offsetTop > 0) { 2477 outOverrideBounds.offset(0, offsetTop); 2478 } 2479 } 2480 } 2481 2482 /** 2483 * Compute bounds (letterbox or pillarbox) for 2484 * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the 2485 * orientation change and the requested orientation is different from the parent. 2486 */ computeFullscreenBounds(@onNull Rect outBounds, @Nullable ActivityRecord refActivity, @NonNull Rect parentBounds, int parentOrientation)2487 void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity, 2488 @NonNull Rect parentBounds, int parentOrientation) { 2489 // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent". 2490 outBounds.setEmpty(); 2491 if (handlesOrientationChangeFromDescendant()) { 2492 return; 2493 } 2494 if (refActivity == null) { 2495 // Use the top activity as the reference of orientation. Don't include overlays because 2496 // it is usually not the actual content or just temporarily shown. 2497 // E.g. ForcedResizableInfoActivity. 2498 refActivity = getTopNonFinishingActivity(false /* includeOverlays */); 2499 } 2500 2501 // If the task or the reference activity requires a different orientation (either by 2502 // override or activityInfo), make it fit the available bounds by scaling down its bounds. 2503 final int overrideOrientation = getRequestedOverrideConfiguration().orientation; 2504 final int forcedOrientation = 2505 (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null) 2506 ? overrideOrientation : refActivity.getRequestedConfigurationOrientation(); 2507 if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) { 2508 return; 2509 } 2510 2511 final int parentWidth = parentBounds.width(); 2512 final int parentHeight = parentBounds.height(); 2513 final float aspect = ((float) parentHeight) / parentWidth; 2514 if (forcedOrientation == ORIENTATION_LANDSCAPE) { 2515 final int height = (int) (parentWidth / aspect); 2516 final int top = parentBounds.centerY() - height / 2; 2517 outBounds.set(parentBounds.left, top, parentBounds.right, top + height); 2518 } else { 2519 final int width = (int) (parentHeight * aspect); 2520 final int left = parentBounds.centerX() - width / 2; 2521 outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom); 2522 } 2523 } 2524 updateOverrideConfigurationFromLaunchBounds()2525 Rect updateOverrideConfigurationFromLaunchBounds() { 2526 // If the task is controlled by another organized task, do not set override 2527 // configurations and let its parent (organized task) to control it; 2528 final Task rootTask = getRootTask(); 2529 final Rect bounds = rootTask != this && rootTask.isOrganized() ? null : getLaunchBounds(); 2530 setBounds(bounds); 2531 if (bounds != null && !bounds.isEmpty()) { 2532 // TODO: Review if we actually want to do this - we are setting the launch bounds 2533 // directly here. 2534 bounds.set(getRequestedOverrideBounds()); 2535 } 2536 return bounds; 2537 } 2538 2539 /** Updates the task's bounds and override configuration to match what is expected for the 2540 * input stack. */ updateOverrideConfigurationForStack(ActivityStack inStack)2541 void updateOverrideConfigurationForStack(ActivityStack inStack) { 2542 final ActivityStack stack = getStack(); 2543 2544 if (stack != null && stack == inStack) { 2545 return; 2546 } 2547 2548 if (inStack.inFreeformWindowingMode()) { 2549 if (!isResizeable()) { 2550 throw new IllegalArgumentException("Can not position non-resizeable task=" 2551 + this + " in stack=" + inStack); 2552 } 2553 if (!matchParentBounds()) { 2554 return; 2555 } 2556 if (mLastNonFullscreenBounds != null) { 2557 setBounds(mLastNonFullscreenBounds); 2558 } else { 2559 mStackSupervisor.getLaunchParamsController().layoutTask(this, null); 2560 } 2561 } else { 2562 setBounds(inStack.getRequestedOverrideBounds()); 2563 } 2564 } 2565 2566 /** Returns the bounds that should be used to launch this task. */ getLaunchBounds()2567 Rect getLaunchBounds() { 2568 final ActivityStack stack = getStack(); 2569 if (stack == null) { 2570 return null; 2571 } 2572 2573 final int windowingMode = getWindowingMode(); 2574 if (!isActivityTypeStandardOrUndefined() 2575 || windowingMode == WINDOWING_MODE_FULLSCREEN 2576 || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) { 2577 return isResizeable() ? stack.getRequestedOverrideBounds() : null; 2578 } else if (!getWindowConfiguration().persistTaskBounds()) { 2579 return stack.getRequestedOverrideBounds(); 2580 } 2581 return mLastNonFullscreenBounds; 2582 } 2583 setRootProcess(WindowProcessController proc)2584 void setRootProcess(WindowProcessController proc) { 2585 clearRootProcess(); 2586 if (intent != null 2587 && (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) { 2588 mRootProcess = proc; 2589 mRootProcess.addRecentTask(this); 2590 } 2591 } 2592 clearRootProcess()2593 void clearRootProcess() { 2594 if (mRootProcess != null) { 2595 mRootProcess.removeRecentTask(this); 2596 mRootProcess = null; 2597 } 2598 } 2599 2600 @Override getDisplayContent()2601 DisplayContent getDisplayContent() { 2602 // TODO: Why aren't we just using our own display content vs. parent's??? 2603 final ActivityStack stack = getStack(); 2604 return stack != null && stack != this 2605 ? stack.getDisplayContent() : super.getDisplayContent(); 2606 } 2607 getDisplayId()2608 int getDisplayId() { 2609 final DisplayContent dc = getDisplayContent(); 2610 return dc != null ? dc.mDisplayId : INVALID_DISPLAY; 2611 } 2612 2613 // TODO: Migrate callers to getRootTask() getStack()2614 ActivityStack getStack() { 2615 return (ActivityStack) getRootTask(); 2616 } 2617 2618 /** @return Id of root task. */ getRootTaskId()2619 int getRootTaskId() { 2620 return getRootTask().mTaskId; 2621 } 2622 getRootTask()2623 Task getRootTask() { 2624 final WindowContainer parent = getParent(); 2625 if (parent == null) return this; 2626 2627 final Task parentTask = parent.asTask(); 2628 return parentTask == null ? this : parentTask.getRootTask(); 2629 } 2630 2631 // TODO(task-merge): Figure out what's the right thing to do for places that used it. isRootTask()2632 boolean isRootTask() { 2633 return getRootTask() == this; 2634 } 2635 isLeafTask()2636 boolean isLeafTask() { 2637 for (int i = mChildren.size() - 1; i >= 0; --i) { 2638 if (mChildren.get(i).asTask() != null) { 2639 return false; 2640 } 2641 } 2642 return true; 2643 } 2644 getDescendantTaskCount()2645 int getDescendantTaskCount() { 2646 final int[] currentCount = {0}; 2647 final PooledConsumer c = PooledLambda.obtainConsumer((t, count) -> { count[0]++; }, 2648 PooledLambda.__(Task.class), currentCount); 2649 forAllLeafTasks(c, false /* traverseTopToBottom */); 2650 c.recycle(); 2651 return currentCount[0]; 2652 } 2653 2654 /** 2655 * Find next proper focusable stack and make it focused. 2656 * @return The stack that now got the focus, {@code null} if none found. 2657 */ adjustFocusToNextFocusableTask(String reason)2658 ActivityStack adjustFocusToNextFocusableTask(String reason) { 2659 return adjustFocusToNextFocusableTask(reason, false /* allowFocusSelf */, 2660 true /* moveDisplayToTop */); 2661 } 2662 2663 /** Return the next focusable task by looking from the siblings and parent tasks */ getNextFocusableTask(boolean allowFocusSelf)2664 private Task getNextFocusableTask(boolean allowFocusSelf) { 2665 final WindowContainer parent = getParent(); 2666 if (parent == null) { 2667 return null; 2668 } 2669 2670 final Task focusableTask = parent.getTask((task) -> (allowFocusSelf || task != this) 2671 && ((ActivityStack) task).isFocusableAndVisible()); 2672 if (focusableTask == null && parent.asTask() != null) { 2673 return parent.asTask().getNextFocusableTask(allowFocusSelf); 2674 } else { 2675 return focusableTask; 2676 } 2677 } 2678 2679 /** 2680 * Find next proper focusable task and make it focused. 2681 * @param reason The reason of making the adjustment. 2682 * @param allowFocusSelf Is the focus allowed to remain on the same task. 2683 * @param moveDisplayToTop Whether to move display to top while making the task focused. 2684 * @return The root task that now got the focus, {@code null} if none found. 2685 */ adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf, boolean moveDisplayToTop)2686 ActivityStack adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf, 2687 boolean moveDisplayToTop) { 2688 ActivityStack focusableTask = (ActivityStack) getNextFocusableTask(allowFocusSelf); 2689 if (focusableTask == null) { 2690 focusableTask = mRootWindowContainer.getNextFocusableStack((ActivityStack) this, 2691 !allowFocusSelf); 2692 } 2693 if (focusableTask == null) { 2694 return null; 2695 } 2696 2697 final ActivityStack rootTask = (ActivityStack) focusableTask.getRootTask(); 2698 if (!moveDisplayToTop) { 2699 // There may be multiple task layers above this task, so when relocating the task to the 2700 // top, we should move this task and each of its parent task that below display area to 2701 // the top of each layer. 2702 WindowContainer parent = focusableTask.getParent(); 2703 WindowContainer next = focusableTask; 2704 do { 2705 parent.positionChildAt(POSITION_TOP, next, false /* includingParents */); 2706 next = parent; 2707 parent = next.getParent(); 2708 } while (next.asTask() != null && parent != null); 2709 return rootTask; 2710 } 2711 2712 final String myReason = reason + " adjustFocusToNextFocusableStack"; 2713 final ActivityRecord top = focusableTask.topRunningActivity(); 2714 if (focusableTask.isActivityTypeHome() && (top == null || !top.mVisibleRequested)) { 2715 // If we will be focusing on the home stack next and its current top activity isn't 2716 // visible, then use the move the home stack task to top to make the activity visible. 2717 focusableTask.getDisplayArea().moveHomeActivityToTop(myReason); 2718 return rootTask; 2719 } 2720 2721 // Move the entire hierarchy to top with updating global top resumed activity 2722 // and focused application if needed. 2723 focusableTask.moveToFront(myReason); 2724 // Top display focused stack is changed, update top resumed activity if needed. 2725 if (rootTask.mResumedActivity != null) { 2726 mStackSupervisor.updateTopResumedActivityIfNeeded(); 2727 // Set focused app directly because if the next focused activity is already resumed 2728 // (e.g. the next top activity is on a different display), there won't have activity 2729 // state change to update it. 2730 mAtmService.setResumedActivityUncheckLocked(rootTask.mResumedActivity, reason); 2731 } 2732 return rootTask; 2733 } 2734 2735 /** Calculate the minimum possible position for a task that can be shown to the user. 2736 * The minimum position will be above all other tasks that can't be shown. 2737 * @param minPosition The minimum position the caller is suggesting. 2738 * We will start adjusting up from here. 2739 * @param size The size of the current task list. 2740 */ 2741 // TODO: Move user to their own window container. computeMinUserPosition(int minPosition, int size)2742 private int computeMinUserPosition(int minPosition, int size) { 2743 while (minPosition < size) { 2744 final WindowContainer child = mChildren.get(minPosition); 2745 final boolean canShow = child.showToCurrentUser(); 2746 if (canShow) { 2747 break; 2748 } 2749 minPosition++; 2750 } 2751 return minPosition; 2752 } 2753 2754 /** Calculate the maximum possible position for a task that can't be shown to the user. 2755 * The maximum position will be below all other tasks that can be shown. 2756 * @param maxPosition The maximum position the caller is suggesting. 2757 * We will start adjusting down from here. 2758 */ 2759 // TODO: Move user to their own window container. computeMaxUserPosition(int maxPosition)2760 private int computeMaxUserPosition(int maxPosition) { 2761 while (maxPosition > 0) { 2762 final WindowContainer child = mChildren.get(maxPosition); 2763 final boolean canShow = child.showToCurrentUser(); 2764 if (!canShow) { 2765 break; 2766 } 2767 maxPosition--; 2768 } 2769 return maxPosition; 2770 } 2771 getAdjustedChildPosition(WindowContainer wc, int suggestedPosition)2772 private int getAdjustedChildPosition(WindowContainer wc, int suggestedPosition) { 2773 final boolean canShowChild = wc.showToCurrentUser(); 2774 2775 final int size = mChildren.size(); 2776 2777 // Figure-out min/max possible position depending on if child can show for current user. 2778 int minPosition = (canShowChild) ? computeMinUserPosition(0, size) : 0; 2779 int maxPosition = (canShowChild) ? size : computeMaxUserPosition(size - 1); 2780 2781 // Factor in always-on-top children in max possible position. 2782 if (!wc.isAlwaysOnTop()) { 2783 2784 // We want to place all non-always-on-top containers below always-on-top ones. 2785 while (maxPosition > minPosition) { 2786 if (!mChildren.get(maxPosition - 1).isAlwaysOnTop()) break; 2787 --maxPosition; 2788 } 2789 } 2790 2791 // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid. 2792 if (suggestedPosition == POSITION_BOTTOM && minPosition == 0) { 2793 return POSITION_BOTTOM; 2794 } else if (suggestedPosition == POSITION_TOP && maxPosition >= (size - 1)) { 2795 return POSITION_TOP; 2796 } 2797 // Reset position based on minimum/maximum possible positions. 2798 return Math.min(Math.max(suggestedPosition, minPosition), maxPosition); 2799 } 2800 2801 @Override positionChildAt(int position, WindowContainer child, boolean includingParents)2802 void positionChildAt(int position, WindowContainer child, boolean includingParents) { 2803 position = getAdjustedChildPosition(child, position); 2804 super.positionChildAt(position, child, includingParents); 2805 2806 // Log positioning. 2807 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "positionChildAt: child=" + child 2808 + " position=" + position + " parent=" + this); 2809 2810 final int toTop = position >= (mChildren.size() - 1) ? 1 : 0; 2811 final Task task = child.asTask(); 2812 if (task != null) { 2813 EventLogTags.writeWmTaskMoved(task.mTaskId, toTop, position); 2814 } 2815 } 2816 2817 @VisibleForTesting hasWindowsAlive()2818 boolean hasWindowsAlive() { 2819 return getActivity(ActivityRecord::hasWindowsAlive) != null; 2820 } 2821 2822 @VisibleForTesting shouldDeferRemoval()2823 boolean shouldDeferRemoval() { 2824 if (mChildren.isEmpty()) { 2825 // No reason to defer removal of a Task that doesn't have any child. 2826 return false; 2827 } 2828 return hasWindowsAlive() && getStack().isAnimating(TRANSITION | CHILDREN); 2829 } 2830 2831 @Override removeImmediately()2832 void removeImmediately() { 2833 if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId); 2834 EventLogTags.writeWmTaskRemoved(mTaskId, "removeTask"); 2835 2836 if (mDisplayContent != null && mDisplayContent.isSingleTaskInstance()) { 2837 mAtmService.notifySingleTaskDisplayEmpty(mDisplayContent.mDisplayId); 2838 } 2839 2840 // If applicable let the TaskOrganizer know the Task is vanishing. 2841 setTaskOrganizer(null); 2842 2843 super.removeImmediately(); 2844 } 2845 2846 // TODO: Consolidate this with Task.reparent() reparent(ActivityStack stack, int position, boolean moveParents, String reason)2847 void reparent(ActivityStack stack, int position, boolean moveParents, String reason) { 2848 if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId 2849 + " from stack=" + getStack()); 2850 EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask:" + reason); 2851 2852 reparent(stack, position); 2853 2854 stack.positionChildAt(position, this, moveParents); 2855 2856 // If we are moving from the fullscreen stack to the pinned stack then we want to preserve 2857 // our insets so that there will not be a jump in the area covered by system decorations. 2858 // We rely on the pinned animation to later unset this value. 2859 mPreserveNonFloatingState = stack.inPinnedWindowingMode(); 2860 } 2861 setBounds(Rect bounds, boolean forceResize)2862 public int setBounds(Rect bounds, boolean forceResize) { 2863 final int boundsChanged = setBounds(bounds); 2864 2865 if (forceResize && (boundsChanged & BOUNDS_CHANGE_SIZE) != BOUNDS_CHANGE_SIZE) { 2866 onResize(); 2867 return BOUNDS_CHANGE_SIZE | boundsChanged; 2868 } 2869 2870 return boundsChanged; 2871 } 2872 2873 /** Set the task bounds. Passing in null sets the bounds to fullscreen. */ 2874 @Override setBounds(Rect bounds)2875 public int setBounds(Rect bounds) { 2876 int rotation = Surface.ROTATION_0; 2877 final DisplayContent displayContent = getStack() != null 2878 ? getStack().getDisplayContent() : null; 2879 if (displayContent != null) { 2880 rotation = displayContent.getDisplayInfo().rotation; 2881 } 2882 2883 final int boundsChange = super.setBounds(bounds); 2884 mRotation = rotation; 2885 updateSurfacePosition(); 2886 return boundsChange; 2887 } 2888 2889 @Override onDescendantOrientationChanged(IBinder freezeDisplayToken, ConfigurationContainer requestingContainer)2890 public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken, 2891 ConfigurationContainer requestingContainer) { 2892 if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) { 2893 return true; 2894 } 2895 2896 // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill 2897 // it if possible. 2898 if (getParent() != null) { 2899 onConfigurationChanged(getParent().getConfiguration()); 2900 return true; 2901 } 2902 return false; 2903 } 2904 resize(boolean relayout, boolean forced)2905 void resize(boolean relayout, boolean forced) { 2906 if (setBounds(getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE && relayout) { 2907 getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); 2908 } 2909 } 2910 2911 @Override onDisplayChanged(DisplayContent dc)2912 void onDisplayChanged(DisplayContent dc) { 2913 final boolean isRootTask = isRootTask(); 2914 if (!isRootTask) { 2915 adjustBoundsForDisplayChangeIfNeeded(dc); 2916 } 2917 super.onDisplayChanged(dc); 2918 if (isLeafTask()) { 2919 final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY; 2920 mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged( 2921 mTaskId, displayId); 2922 } 2923 } 2924 isResizeable(boolean checkSupportsPip)2925 boolean isResizeable(boolean checkSupportsPip) { 2926 return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode) 2927 || (checkSupportsPip && mSupportsPictureInPicture)); 2928 } 2929 isResizeable()2930 boolean isResizeable() { 2931 return isResizeable(true /* checkSupportsPip */); 2932 } 2933 2934 /** 2935 * Tests if the orientation should be preserved upon user interactive resizig operations. 2936 2937 * @return true if orientation should not get changed upon resizing operation. 2938 */ preserveOrientationOnResize()2939 boolean preserveOrientationOnResize() { 2940 return mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY 2941 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY 2942 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; 2943 } 2944 cropWindowsToStackBounds()2945 boolean cropWindowsToStackBounds() { 2946 // Don't crop HOME/RECENTS windows to stack bounds. This is because in split-screen 2947 // they extend past their stack and sysui uses the stack surface to control cropping. 2948 // TODO(b/158242495): get rid of this when drag/drop can use surface bounds. 2949 if (isActivityTypeHome() || isActivityTypeRecents()) { 2950 // Make sure this is the top-most non-organizer root task (if not top-most, it means 2951 // another translucent task could be above this, so this needs to stay cropped. 2952 final Task rootTask = getRootTask(); 2953 final Task topNonOrgTask = 2954 rootTask.mCreatedByOrganizer ? rootTask.getTopMostTask() : rootTask; 2955 if (this == topNonOrgTask || isDescendantOf(topNonOrgTask)) { 2956 return false; 2957 } 2958 } 2959 return isResizeable(); 2960 } 2961 2962 /** 2963 * Prepares the task bounds to be frozen with the current size. See 2964 * {@link ActivityRecord#freezeBounds}. 2965 */ prepareFreezingBounds()2966 void prepareFreezingBounds() { 2967 mPreparedFrozenBounds.set(getBounds()); 2968 mPreparedFrozenMergedConfig.setTo(getConfiguration()); 2969 } 2970 2971 @Override getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, Rect outSurfaceInsets)2972 void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, 2973 Rect outSurfaceInsets) { 2974 final WindowState windowState = getTopVisibleAppMainWindow(); 2975 if (windowState != null) { 2976 windowState.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); 2977 } else { 2978 super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); 2979 } 2980 } 2981 2982 /** 2983 * Calculate the maximum visible area of this task. If the task has only one app, 2984 * the result will be visible frame of that app. If the task has more than one apps, 2985 * we search from top down if the next app got different visible area. 2986 * 2987 * This effort is to handle the case where some task (eg. GMail composer) might pop up 2988 * a dialog that's different in size from the activity below, in which case we should 2989 * be dimming the entire task area behind the dialog. 2990 * 2991 * @param out Rect containing the max visible bounds. 2992 * @return true if the task has some visible app windows; false otherwise. 2993 */ getMaxVisibleBounds(ActivityRecord token, Rect out, boolean[] foundTop)2994 private static void getMaxVisibleBounds(ActivityRecord token, Rect out, boolean[] foundTop) { 2995 // skip hidden (or about to hide) apps 2996 if (token.mIsExiting || !token.isClientVisible() || !token.mVisibleRequested) { 2997 return; 2998 } 2999 final WindowState win = token.findMainWindow(); 3000 if (win == null) { 3001 return; 3002 } 3003 if (!foundTop[0]) { 3004 foundTop[0] = true; 3005 out.setEmpty(); 3006 } 3007 3008 win.getMaxVisibleBounds(out); 3009 } 3010 3011 /** Bounds of the task to be used for dimming, as well as touch related tests. */ getDimBounds(Rect out)3012 void getDimBounds(Rect out) { 3013 final DisplayContent displayContent = getStack().getDisplayContent(); 3014 // It doesn't matter if we in particular are part of the resize, since we couldn't have 3015 // a DimLayer anyway if we weren't visible. 3016 final boolean dockedResizing = displayContent != null 3017 && displayContent.mDividerControllerLocked.isResizing(); 3018 if (inFreeformWindowingMode()) { 3019 boolean[] foundTop = { false }; 3020 final PooledConsumer c = PooledLambda.obtainConsumer(Task::getMaxVisibleBounds, 3021 PooledLambda.__(ActivityRecord.class), out, foundTop); 3022 forAllActivities(c); 3023 c.recycle(); 3024 if (foundTop[0]) { 3025 return; 3026 } 3027 } 3028 3029 if (!matchParentBounds()) { 3030 // When minimizing the docked stack when going home, we don't adjust the task bounds 3031 // so we need to intersect the task bounds with the stack bounds here. 3032 // 3033 // If we are Docked Resizing with snap points, the task bounds could be smaller than the 3034 // stack bounds and so we don't even want to use them. Even if the app should not be 3035 // resized the Dim should keep up with the divider. 3036 if (dockedResizing) { 3037 getStack().getBounds(out); 3038 } else { 3039 getStack().getBounds(mTmpRect); 3040 mTmpRect.intersect(getBounds()); 3041 out.set(mTmpRect); 3042 } 3043 } else { 3044 out.set(getBounds()); 3045 } 3046 return; 3047 } 3048 setDragResizing(boolean dragResizing, int dragResizeMode)3049 void setDragResizing(boolean dragResizing, int dragResizeMode) { 3050 if (mDragResizing != dragResizing) { 3051 // No need to check if the mode is allowed if it's leaving dragResize 3052 if (dragResizing && !DragResizeMode.isModeAllowedForStack(getStack(), dragResizeMode)) { 3053 throw new IllegalArgumentException("Drag resize mode not allow for stack stackId=" 3054 + getRootTaskId() + " dragResizeMode=" + dragResizeMode); 3055 } 3056 mDragResizing = dragResizing; 3057 mDragResizeMode = dragResizeMode; 3058 resetDragResizingChangeReported(); 3059 } 3060 } 3061 isDragResizing()3062 boolean isDragResizing() { 3063 return mDragResizing; 3064 } 3065 getDragResizeMode()3066 int getDragResizeMode() { 3067 return mDragResizeMode; 3068 } 3069 adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent)3070 void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) { 3071 if (displayContent == null) { 3072 return; 3073 } 3074 if (matchParentBounds()) { 3075 // TODO: Yeah...not sure if this works with WindowConfiguration, but shouldn't be a 3076 // problem once we move mBounds into WindowConfiguration. 3077 setBounds(null); 3078 return; 3079 } 3080 final int displayId = displayContent.getDisplayId(); 3081 final int newRotation = displayContent.getDisplayInfo().rotation; 3082 if (displayId != mLastRotationDisplayId) { 3083 // This task is on a display that it wasn't on. There is no point to keep the relative 3084 // position if display rotations for old and new displays are different. Just keep these 3085 // values. 3086 mLastRotationDisplayId = displayId; 3087 mRotation = newRotation; 3088 return; 3089 } 3090 3091 if (mRotation == newRotation) { 3092 // Rotation didn't change. We don't need to adjust the bounds to keep the relative 3093 // position. 3094 return; 3095 } 3096 3097 // Device rotation changed. 3098 // - We don't want the task to move around on the screen when this happens, so update the 3099 // task bounds so it stays in the same place. 3100 // - Rotate the bounds and notify activity manager if the task can be resized independently 3101 // from its stack. The stack will take care of task rotation for the other case. 3102 mTmpRect2.set(getBounds()); 3103 3104 if (!getWindowConfiguration().canResizeTask()) { 3105 setBounds(mTmpRect2); 3106 return; 3107 } 3108 3109 displayContent.rotateBounds(mRotation, newRotation, mTmpRect2); 3110 if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) { 3111 mAtmService.resizeTask(mTaskId, getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION); 3112 } 3113 } 3114 3115 /** Cancels any running app transitions associated with the task. */ cancelTaskWindowTransition()3116 void cancelTaskWindowTransition() { 3117 for (int i = mChildren.size() - 1; i >= 0; --i) { 3118 mChildren.get(i).cancelAnimation(); 3119 } 3120 } 3121 showForAllUsers()3122 boolean showForAllUsers() { 3123 if (mChildren.isEmpty()) return false; 3124 final ActivityRecord r = getTopNonFinishingActivity(); 3125 return r != null && r.mShowForAllUsers; 3126 } 3127 3128 @Override showToCurrentUser()3129 boolean showToCurrentUser() { 3130 return mForceShowForAllUsers || showForAllUsers() 3131 || mWmService.isCurrentProfile(getTopMostTask().mUserId); 3132 } 3133 setForceShowForAllUsers(boolean forceShowForAllUsers)3134 void setForceShowForAllUsers(boolean forceShowForAllUsers) { 3135 mForceShowForAllUsers = forceShowForAllUsers; 3136 } 3137 3138 @Override isAttached()3139 public boolean isAttached() { 3140 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 3141 return taskDisplayArea != null && !taskDisplayArea.isRemoved(); 3142 } 3143 3144 @Override 3145 @Nullable getDisplayArea()3146 TaskDisplayArea getDisplayArea() { 3147 return (TaskDisplayArea) super.getDisplayArea(); 3148 } 3149 3150 /** 3151 * When we are in a floating stack (Freeform, Pinned, ...) we calculate 3152 * insets differently. However if we are animating to the fullscreen stack 3153 * we need to begin calculating insets as if we were fullscreen, otherwise 3154 * we will have a jump at the end. 3155 */ isFloating()3156 boolean isFloating() { 3157 return getWindowConfiguration().tasksAreFloating() && !mPreserveNonFloatingState; 3158 } 3159 3160 /** 3161 * Returns true if the stack is translucent and can have other contents visible behind it if 3162 * needed. A stack is considered translucent if it don't contain a visible or 3163 * starting (about to be visible) activity that is fullscreen (opaque). 3164 * @param starting The currently starting activity or null if there is none. 3165 */ 3166 @VisibleForTesting isTranslucent(ActivityRecord starting)3167 boolean isTranslucent(ActivityRecord starting) { 3168 if (!isAttached() || isForceHidden()) { 3169 return true; 3170 } 3171 final PooledPredicate p = PooledLambda.obtainPredicate(Task::isOpaqueActivity, 3172 PooledLambda.__(ActivityRecord.class), starting); 3173 final ActivityRecord opaque = getActivity(p); 3174 p.recycle(); 3175 return opaque == null; 3176 } 3177 isOpaqueActivity(ActivityRecord r, ActivityRecord starting)3178 private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) { 3179 if (r.finishing) { 3180 // We don't factor in finishing activities when determining translucency since 3181 // they will be gone soon. 3182 return false; 3183 } 3184 3185 if (!r.visibleIgnoringKeyguard && r != starting) { 3186 // Also ignore invisible activities that are not the currently starting 3187 // activity (about to be visible). 3188 return false; 3189 } 3190 3191 if (r.occludesParent() || r.hasWallpaper) { 3192 // Stack isn't translucent if it has at least one fullscreen activity 3193 // that is visible. 3194 return true; 3195 } 3196 return false; 3197 } 3198 3199 @Override makeAnimationLeash()3200 public SurfaceControl.Builder makeAnimationLeash() { 3201 return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId); 3202 } 3203 3204 @Override getAnimationLeashParent()3205 public SurfaceControl getAnimationLeashParent() { 3206 if (WindowManagerService.sHierarchicalAnimations) { 3207 return super.getAnimationLeashParent(); 3208 } 3209 // Currently, only the recents animation will create animation leashes for tasks. In this 3210 // case, reparent the task to the home animation layer while it is being animated to allow 3211 // the home activity to reorder the app windows relative to its own. 3212 return getAppAnimationLayer(ANIMATION_LAYER_HOME); 3213 } 3214 3215 @Override getAnimationBounds(int appStackClipMode)3216 Rect getAnimationBounds(int appStackClipMode) { 3217 // TODO(b/131661052): we should remove appStackClipMode with hierarchical animations. 3218 if (appStackClipMode == STACK_CLIP_BEFORE_ANIM && getStack() != null) { 3219 // Using the stack bounds here effectively applies the clipping before animation. 3220 return getStack().getBounds(); 3221 } 3222 return super.getAnimationBounds(appStackClipMode); 3223 } 3224 shouldAnimate()3225 boolean shouldAnimate() { 3226 /** 3227 * Animations are handled by the TaskOrganizer implementation. 3228 */ 3229 if (isOrganized()) { 3230 return false; 3231 } 3232 // Don't animate while the task runs recents animation but only if we are in the mode 3233 // where we cancel with deferred screenshot, which means that the controller has 3234 // transformed the task. 3235 final RecentsAnimationController controller = mWmService.getRecentsAnimationController(); 3236 if (controller != null && controller.isAnimatingTask(this) 3237 && controller.shouldDeferCancelUntilNextTransition()) { 3238 return false; 3239 } 3240 return true; 3241 } 3242 3243 @Override setInitialSurfaceControlProperties(SurfaceControl.Builder b)3244 void setInitialSurfaceControlProperties(SurfaceControl.Builder b) { 3245 b.setEffectLayer().setMetadata(METADATA_TASK_ID, mTaskId); 3246 super.setInitialSurfaceControlProperties(b); 3247 } 3248 isTaskAnimating()3249 boolean isTaskAnimating() { 3250 final RecentsAnimationController recentsAnim = mWmService.getRecentsAnimationController(); 3251 if (recentsAnim != null) { 3252 if (recentsAnim.isAnimatingTask(this)) { 3253 return true; 3254 } 3255 } 3256 return forAllTasks((t) -> { return t != this && t.isTaskAnimating(); }); 3257 } 3258 3259 @Override createRemoteAnimationTarget( RemoteAnimationController.RemoteAnimationRecord record)3260 RemoteAnimationTarget createRemoteAnimationTarget( 3261 RemoteAnimationController.RemoteAnimationRecord record) { 3262 final ActivityRecord activity = getTopMostActivity(); 3263 return activity != null ? activity.createRemoteAnimationTarget(record) : null; 3264 } 3265 3266 @Override canCreateRemoteAnimationTarget()3267 boolean canCreateRemoteAnimationTarget() { 3268 return true; 3269 } 3270 getTopVisibleAppMainWindow()3271 WindowState getTopVisibleAppMainWindow() { 3272 final ActivityRecord activity = getTopVisibleActivity(); 3273 return activity != null ? activity.findMainWindow() : null; 3274 } 3275 topRunningActivity()3276 ActivityRecord topRunningActivity() { 3277 return topRunningActivity(false /* focusableOnly */); 3278 } 3279 topRunningActivity(boolean focusableOnly)3280 ActivityRecord topRunningActivity(boolean focusableOnly) { 3281 // Split into 2 to avoid object creation due to variable capture. 3282 if (focusableOnly) { 3283 return getActivity((r) -> r.canBeTopRunning() && r.isFocusable()); 3284 } else { 3285 return getActivity(ActivityRecord::canBeTopRunning); 3286 } 3287 } 3288 topRunningNonDelayedActivityLocked(ActivityRecord notTop)3289 ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) { 3290 final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunningNonDelayed 3291 , PooledLambda.__(ActivityRecord.class), notTop); 3292 final ActivityRecord r = getActivity(p); 3293 p.recycle(); 3294 return r; 3295 } 3296 isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop)3297 private static boolean isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop) { 3298 return !r.delayedResume && r != notTop && r.canBeTopRunning(); 3299 } 3300 3301 /** 3302 * This is a simplified version of topRunningActivity that provides a number of 3303 * optional skip-over modes. It is intended for use with the ActivityController hook only. 3304 * 3305 * @param token If non-null, any history records matching this token will be skipped. 3306 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID. 3307 * 3308 * @return Returns the HistoryRecord of the next activity on the stack. 3309 */ topRunningActivity(IBinder token, int taskId)3310 ActivityRecord topRunningActivity(IBinder token, int taskId) { 3311 final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunning, 3312 PooledLambda.__(ActivityRecord.class), taskId, token); 3313 final ActivityRecord r = getActivity(p); 3314 p.recycle(); 3315 return r; 3316 } 3317 isTopRunning(ActivityRecord r, int taskId, IBinder notTop)3318 private static boolean isTopRunning(ActivityRecord r, int taskId, IBinder notTop) { 3319 return r.getTask().mTaskId != taskId && r.appToken != notTop && r.canBeTopRunning(); 3320 } 3321 getTopFullscreenActivity()3322 ActivityRecord getTopFullscreenActivity() { 3323 return getActivity((r) -> { 3324 final WindowState win = r.findMainWindow(); 3325 return (win != null && win.mAttrs.isFullscreen()); 3326 }); 3327 } 3328 3329 ActivityRecord getTopVisibleActivity() { 3330 return getActivity((r) -> { 3331 // skip hidden (or about to hide) apps 3332 return !r.mIsExiting && r.isClientVisible() && r.mVisibleRequested; 3333 }); 3334 } 3335 3336 boolean isTopActivityFocusable() { 3337 final ActivityRecord r = topRunningActivity(); 3338 return r != null ? r.isFocusable() 3339 : (isFocusable() && getWindowConfiguration().canReceiveKeys()); 3340 } 3341 3342 boolean isFocusableAndVisible() { 3343 return isTopActivityFocusable() && shouldBeVisible(null /* starting */); 3344 } 3345 3346 void positionChildAtTop(ActivityRecord child) { 3347 positionChildAt(child, POSITION_TOP); 3348 } 3349 3350 void positionChildAt(ActivityRecord child, int position) { 3351 if (child == null) { 3352 Slog.w(TAG_WM, 3353 "Attempted to position of non-existing app"); 3354 return; 3355 } 3356 3357 positionChildAt(position, child, false /* includeParents */); 3358 } 3359 3360 void forceWindowsScaleable(boolean force) { 3361 mWmService.openSurfaceTransaction(); 3362 try { 3363 for (int i = mChildren.size() - 1; i >= 0; i--) { 3364 mChildren.get(i).forceWindowsScaleableInTransaction(force); 3365 } 3366 } finally { 3367 mWmService.closeSurfaceTransaction("forceWindowsScaleable"); 3368 } 3369 } 3370 3371 void setTaskDescription(TaskDescription taskDescription) { 3372 mTaskDescription = taskDescription; 3373 } 3374 3375 void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) { 3376 mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged( 3377 mTaskId, snapshot); 3378 } 3379 3380 TaskDescription getTaskDescription() { 3381 return mTaskDescription; 3382 } 3383 3384 @Override 3385 int getOrientation(int candidate) { 3386 return canSpecifyOrientation() ? super.getOrientation(candidate) : SCREEN_ORIENTATION_UNSET; 3387 } 3388 3389 private boolean canSpecifyOrientation() { 3390 final int windowingMode = getWindowingMode(); 3391 final int activityType = getActivityType(); 3392 return windowingMode == WINDOWING_MODE_FULLSCREEN 3393 || activityType == ACTIVITY_TYPE_HOME 3394 || activityType == ACTIVITY_TYPE_RECENTS 3395 || activityType == ACTIVITY_TYPE_ASSISTANT; 3396 } 3397 3398 @Override 3399 boolean fillsParent() { 3400 return matchParentBounds(); 3401 } 3402 3403 @Override 3404 void forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom) { 3405 final int count = mChildren.size(); 3406 boolean isLeafTask = true; 3407 if (traverseTopToBottom) { 3408 for (int i = count - 1; i >= 0; --i) { 3409 final Task child = mChildren.get(i).asTask(); 3410 if (child != null) { 3411 isLeafTask = false; 3412 child.forAllLeafTasks(callback, traverseTopToBottom); 3413 } 3414 } 3415 } else { 3416 for (int i = 0; i < count; i++) { 3417 final Task child = mChildren.get(i).asTask(); 3418 if (child != null) { 3419 isLeafTask = false; 3420 child.forAllLeafTasks(callback, traverseTopToBottom); 3421 } 3422 } 3423 } 3424 if (isLeafTask) callback.accept(this); 3425 } 3426 3427 @Override 3428 void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom) { 3429 super.forAllTasks(callback, traverseTopToBottom); 3430 callback.accept(this); 3431 } 3432 3433 @Override 3434 boolean forAllTasks(Function<Task, Boolean> callback) { 3435 if (super.forAllTasks(callback)) return true; 3436 return callback.apply(this); 3437 } 3438 3439 @Override 3440 boolean forAllLeafTasks(Function<Task, Boolean> callback) { 3441 boolean isLeafTask = true; 3442 for (int i = mChildren.size() - 1; i >= 0; --i) { 3443 final Task child = mChildren.get(i).asTask(); 3444 if (child != null) { 3445 isLeafTask = false; 3446 if (child.forAllLeafTasks(callback)) { 3447 return true; 3448 } 3449 } 3450 } 3451 if (isLeafTask) { 3452 return callback.apply(this); 3453 } 3454 return false; 3455 } 3456 3457 @Override 3458 Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) { 3459 final Task t = super.getTask(callback, traverseTopToBottom); 3460 if (t != null) return t; 3461 return callback.test(this) ? this : null; 3462 } 3463 3464 /** 3465 * @param canAffectSystemUiFlags If false, all windows in this task can not affect SystemUI 3466 * flags. See {@link WindowState#canAffectSystemUiFlags()}. 3467 */ 3468 void setCanAffectSystemUiFlags(boolean canAffectSystemUiFlags) { 3469 mCanAffectSystemUiFlags = canAffectSystemUiFlags; 3470 } 3471 3472 /** 3473 * @see #setCanAffectSystemUiFlags 3474 */ 3475 boolean canAffectSystemUiFlags() { 3476 return mCanAffectSystemUiFlags; 3477 } 3478 3479 void dontAnimateDimExit() { 3480 mDimmer.dontAnimateExit(); 3481 } 3482 3483 String getName() { 3484 return "Task=" + mTaskId; 3485 } 3486 3487 void clearPreserveNonFloatingState() { 3488 mPreserveNonFloatingState = false; 3489 } 3490 3491 @Override 3492 Dimmer getDimmer() { 3493 // If the window is in multi-window mode, we want to dim at the Task level to ensure the dim 3494 // bounds match the area the app lives in 3495 if (inMultiWindowMode()) { 3496 return mDimmer; 3497 } 3498 3499 // If we're not at the root task level, we want to keep traversing through the parents to 3500 // find the root. 3501 // Once at the root task level, we want to check {@link #isTranslucent(ActivityRecord)}. 3502 // If true, we want to get the Dimmer from the level above since we don't want to animate 3503 // the dim with the Task. 3504 if (!isRootTask() || isTranslucent(null)) { 3505 return super.getDimmer(); 3506 } 3507 3508 return mDimmer; 3509 } 3510 3511 @Override 3512 void prepareSurfaces() { 3513 mDimmer.resetDimStates(); 3514 super.prepareSurfaces(); 3515 getDimBounds(mTmpDimBoundsRect); 3516 3517 // Bounds need to be relative, as the dim layer is a child. 3518 if (inFreeformWindowingMode()) { 3519 getBounds(mTmpRect); 3520 mTmpDimBoundsRect.offsetTo(mTmpDimBoundsRect.left - mTmpRect.left, 3521 mTmpDimBoundsRect.top - mTmpRect.top); 3522 } else { 3523 mTmpDimBoundsRect.offsetTo(0, 0); 3524 } 3525 3526 updateShadowsRadius(isFocused(), getSyncTransaction()); 3527 3528 if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) { 3529 scheduleAnimation(); 3530 } 3531 } 3532 3533 @Override 3534 protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter, 3535 int transit, boolean isVoiceInteraction, 3536 @Nullable ArrayList<WindowContainer> sources) { 3537 final RecentsAnimationController control = mWmService.getRecentsAnimationController(); 3538 if (control != null) { 3539 // We let the transition to be controlled by RecentsAnimation, and callback task's 3540 // RemoteAnimationTarget for remote runner to animate. 3541 if (enter) { 3542 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, 3543 "applyAnimationUnchecked, control: %s, task: %s, transit: %s", 3544 control, asTask(), AppTransition.appTransitionToString(transit)); 3545 control.addTaskToTargets(this, (type, anim) -> { 3546 for (int i = 0; i < sources.size(); ++i) { 3547 sources.get(i).onAnimationFinished(type, anim); 3548 } 3549 }); 3550 } 3551 } else { 3552 super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources); 3553 } 3554 } 3555 3556 @Override 3557 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 3558 super.dump(pw, prefix, dumpAll); 3559 pw.println(prefix + "bounds=" + getBounds().toShortString()); 3560 final String doublePrefix = prefix + " "; 3561 for (int i = mChildren.size() - 1; i >= 0; i--) { 3562 final WindowContainer<?> child = mChildren.get(i); 3563 pw.println(prefix + "* " + child); 3564 // Only dump non-activity because full activity info is already printed by 3565 // RootWindowContainer#dumpActivities. 3566 if (child.asActivityRecord() == null) { 3567 child.dump(pw, doublePrefix, dumpAll); 3568 } 3569 } 3570 } 3571 3572 3573 /** 3574 * Fills in a {@link TaskInfo} with information from this task. Note that the base intent in the 3575 * task info will not include any extras or clip data. 3576 */ 3577 void fillTaskInfo(TaskInfo info) { 3578 fillTaskInfo(info, true /* stripExtras */); 3579 } 3580 3581 /** 3582 * Fills in a {@link TaskInfo} with information from this task. 3583 */ 3584 void fillTaskInfo(TaskInfo info, boolean stripExtras) { 3585 getNumRunningActivities(mReuseActivitiesReport); 3586 info.userId = mUserId; 3587 info.stackId = getRootTaskId(); 3588 info.taskId = mTaskId; 3589 info.displayId = getDisplayId(); 3590 info.isRunning = getTopNonFinishingActivity() != null; 3591 final Intent baseIntent = getBaseIntent(); 3592 // Make a copy of base intent because this is like a snapshot info. 3593 // Besides, {@link RecentTasks#getRecentTasksImpl} may modify it. 3594 final int baseIntentFlags = baseIntent == null ? 0 : baseIntent.getFlags(); 3595 info.baseIntent = baseIntent == null 3596 ? new Intent() 3597 : stripExtras ? baseIntent.cloneFilter() : new Intent(baseIntent); 3598 info.baseIntent.setFlags(baseIntentFlags); 3599 info.baseActivity = mReuseActivitiesReport.base != null 3600 ? mReuseActivitiesReport.base.intent.getComponent() 3601 : null; 3602 info.topActivity = mReuseActivitiesReport.top != null 3603 ? mReuseActivitiesReport.top.mActivityComponent 3604 : null; 3605 info.origActivity = origActivity; 3606 info.realActivity = realActivity; 3607 info.numActivities = mReuseActivitiesReport.numActivities; 3608 info.lastActiveTime = lastActiveTime; 3609 info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription()); 3610 info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode(); 3611 info.configuration.setTo(getConfiguration()); 3612 info.token = mRemoteToken.toWindowContainerToken(); 3613 3614 //TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child 3615 // order changes. 3616 final Task top = getTopMostTask(); 3617 info.resizeMode = top != null ? top.mResizeMode : mResizeMode; 3618 info.topActivityType = top.getActivityType(); 3619 info.isResizeable = isResizeable(); 3620 3621 ActivityRecord rootActivity = top.getRootActivity(); 3622 if (rootActivity == null || rootActivity.pictureInPictureArgs.empty()) { 3623 info.pictureInPictureParams = null; 3624 } else { 3625 info.pictureInPictureParams = rootActivity.pictureInPictureArgs; 3626 } 3627 info.topActivityInfo = mReuseActivitiesReport.top != null 3628 ? mReuseActivitiesReport.top.info 3629 : null; 3630 info.requestedOrientation = mReuseActivitiesReport.base != null 3631 ? mReuseActivitiesReport.base.getRequestedOrientation() 3632 : SCREEN_ORIENTATION_UNSET; 3633 } 3634 3635 /** 3636 * Returns a {@link TaskInfo} with information from this task. 3637 */ 3638 ActivityManager.RunningTaskInfo getTaskInfo() { 3639 ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo(); 3640 fillTaskInfo(info); 3641 return info; 3642 } 3643 3644 boolean isTaskId(int taskId) { 3645 return mTaskId == taskId; 3646 } 3647 3648 @Override 3649 Task asTask() { 3650 // I'm a task! 3651 return this; 3652 } 3653 3654 /** 3655 * Returns true if the task should be visible. 3656 * 3657 * @param starting The currently starting activity or null if there is none. 3658 */ 3659 boolean shouldBeVisible(ActivityRecord starting) { 3660 return getVisibility(starting) != STACK_VISIBILITY_INVISIBLE; 3661 } 3662 3663 /** 3664 * Returns true if the task should be visible. 3665 * 3666 * @param starting The currently starting activity or null if there is none. 3667 */ 3668 @ActivityStack.StackVisibility 3669 int getVisibility(ActivityRecord starting) { 3670 if (!isAttached() || isForceHidden()) { 3671 return STACK_VISIBILITY_INVISIBLE; 3672 } 3673 3674 if (isTopActivityLaunchedBehind()) { 3675 return STACK_VISIBILITY_VISIBLE; 3676 } 3677 3678 boolean gotSplitScreenStack = false; 3679 boolean gotOpaqueSplitScreenPrimary = false; 3680 boolean gotOpaqueSplitScreenSecondary = false; 3681 boolean gotTranslucentFullscreen = false; 3682 boolean gotTranslucentSplitScreenPrimary = false; 3683 boolean gotTranslucentSplitScreenSecondary = false; 3684 boolean shouldBeVisible = true; 3685 3686 // This stack is only considered visible if all its parent stacks are considered visible, 3687 // so check the visibility of all ancestor stacks first. 3688 final WindowContainer parent = getParent(); 3689 if (parent.asTask() != null) { 3690 final int parentVisibility = parent.asTask().getVisibility(starting); 3691 if (parentVisibility == STACK_VISIBILITY_INVISIBLE) { 3692 // Can't be visible if parent isn't visible 3693 return STACK_VISIBILITY_INVISIBLE; 3694 } else if (parentVisibility == STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) { 3695 // Parent is behind a translucent container so the highest visibility this container 3696 // can get is that. 3697 gotTranslucentFullscreen = true; 3698 } 3699 } 3700 3701 final int windowingMode = getWindowingMode(); 3702 final boolean isAssistantType = isActivityTypeAssistant(); 3703 for (int i = parent.getChildCount() - 1; i >= 0; --i) { 3704 final WindowContainer wc = parent.getChildAt(i); 3705 final Task other = wc.asTask(); 3706 if (other == null) continue; 3707 3708 final boolean hasRunningActivities = other.topRunningActivity() != null; 3709 if (other == this) { 3710 // Should be visible if there is no other stack occluding it, unless it doesn't 3711 // have any running activities, not starting one and not home stack. 3712 shouldBeVisible = hasRunningActivities || isInTask(starting) != null 3713 || isActivityTypeHome(); 3714 break; 3715 } 3716 3717 if (!hasRunningActivities) { 3718 continue; 3719 } 3720 3721 final int otherWindowingMode = other.getWindowingMode(); 3722 3723 if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) { 3724 if (other.isTranslucent(starting)) { 3725 // Can be visible behind a translucent fullscreen stack. 3726 gotTranslucentFullscreen = true; 3727 continue; 3728 } 3729 return STACK_VISIBILITY_INVISIBLE; 3730 } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY 3731 && !gotOpaqueSplitScreenPrimary) { 3732 gotSplitScreenStack = true; 3733 gotTranslucentSplitScreenPrimary = other.isTranslucent(starting); 3734 gotOpaqueSplitScreenPrimary = !gotTranslucentSplitScreenPrimary; 3735 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY 3736 && gotOpaqueSplitScreenPrimary) { 3737 // Can not be visible behind another opaque stack in split-screen-primary mode. 3738 return STACK_VISIBILITY_INVISIBLE; 3739 } 3740 } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY 3741 && !gotOpaqueSplitScreenSecondary) { 3742 gotSplitScreenStack = true; 3743 gotTranslucentSplitScreenSecondary = other.isTranslucent(starting); 3744 gotOpaqueSplitScreenSecondary = !gotTranslucentSplitScreenSecondary; 3745 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY 3746 && gotOpaqueSplitScreenSecondary) { 3747 // Can not be visible behind another opaque stack in split-screen-secondary mode. 3748 return STACK_VISIBILITY_INVISIBLE; 3749 } 3750 } 3751 if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) { 3752 // Can not be visible if we are in split-screen windowing mode and both halves of 3753 // the screen are opaque. 3754 return STACK_VISIBILITY_INVISIBLE; 3755 } 3756 if (isAssistantType && gotSplitScreenStack) { 3757 // Assistant stack can't be visible behind split-screen. In addition to this not 3758 // making sense, it also works around an issue here we boost the z-order of the 3759 // assistant window surfaces in window manager whenever it is visible. 3760 return STACK_VISIBILITY_INVISIBLE; 3761 } 3762 } 3763 3764 if (!shouldBeVisible) { 3765 return STACK_VISIBILITY_INVISIBLE; 3766 } 3767 3768 // Handle cases when there can be a translucent split-screen stack on top. 3769 switch (windowingMode) { 3770 case WINDOWING_MODE_FULLSCREEN: 3771 if (gotTranslucentSplitScreenPrimary || gotTranslucentSplitScreenSecondary) { 3772 // At least one of the split-screen stacks that covers this one is translucent. 3773 return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; 3774 } 3775 break; 3776 case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: 3777 if (gotTranslucentSplitScreenPrimary) { 3778 // Covered by translucent primary split-screen on top. 3779 return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; 3780 } 3781 break; 3782 case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: 3783 if (gotTranslucentSplitScreenSecondary) { 3784 // Covered by translucent secondary split-screen on top. 3785 return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; 3786 } 3787 break; 3788 } 3789 3790 // Lastly - check if there is a translucent fullscreen stack on top. 3791 return gotTranslucentFullscreen ? STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT 3792 : STACK_VISIBILITY_VISIBLE; 3793 } 3794 3795 private boolean isTopActivityLaunchedBehind() { 3796 final ActivityRecord top = topRunningActivity(); 3797 if (top != null && top.mLaunchTaskBehind) { 3798 return true; 3799 } 3800 return false; 3801 } 3802 3803 ActivityRecord isInTask(ActivityRecord r) { 3804 if (r == null) { 3805 return null; 3806 } 3807 if (r.isDescendantOf(this)) { 3808 return r; 3809 } 3810 return null; 3811 } 3812 3813 void dump(PrintWriter pw, String prefix) { 3814 pw.print(prefix); pw.print("userId="); pw.print(mUserId); 3815 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid); 3816 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid); 3817 pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete); 3818 pw.print(" mCallingPackage="); pw.print(mCallingPackage); 3819 pw.print(" mCallingFeatureId="); pw.println(mCallingFeatureId); 3820 if (affinity != null || rootAffinity != null) { 3821 pw.print(prefix); pw.print("affinity="); pw.print(affinity); 3822 if (affinity == null || !affinity.equals(rootAffinity)) { 3823 pw.print(" root="); pw.println(rootAffinity); 3824 } else { 3825 pw.println(); 3826 } 3827 } 3828 if (mWindowLayoutAffinity != null) { 3829 pw.print(prefix); pw.print("windowLayoutAffinity="); pw.println(mWindowLayoutAffinity); 3830 } 3831 if (voiceSession != null || voiceInteractor != null) { 3832 pw.print(prefix); pw.print("VOICE: session=0x"); 3833 pw.print(Integer.toHexString(System.identityHashCode(voiceSession))); 3834 pw.print(" interactor=0x"); 3835 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor))); 3836 } 3837 if (intent != null) { 3838 StringBuilder sb = new StringBuilder(128); 3839 sb.append(prefix); sb.append("intent={"); 3840 intent.toShortString(sb, false, true, false, false); 3841 sb.append('}'); 3842 pw.println(sb.toString()); 3843 } 3844 if (affinityIntent != null) { 3845 StringBuilder sb = new StringBuilder(128); 3846 sb.append(prefix); sb.append("affinityIntent={"); 3847 affinityIntent.toShortString(sb, false, true, false, false); 3848 sb.append('}'); 3849 pw.println(sb.toString()); 3850 } 3851 if (origActivity != null) { 3852 pw.print(prefix); pw.print("origActivity="); 3853 pw.println(origActivity.flattenToShortString()); 3854 } 3855 if (realActivity != null) { 3856 pw.print(prefix); pw.print("mActivityComponent="); 3857 pw.println(realActivity.flattenToShortString()); 3858 } 3859 if (autoRemoveRecents || isPersistable || !isActivityTypeStandard()) { 3860 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents); 3861 pw.print(" isPersistable="); pw.print(isPersistable); 3862 pw.print(" activityType="); pw.println(getActivityType()); 3863 } 3864 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask 3865 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) { 3866 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset); 3867 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity); 3868 pw.print(" mReuseTask="); pw.print(mReuseTask); 3869 pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString()); 3870 } 3871 if (mAffiliatedTaskId != mTaskId || mPrevAffiliateTaskId != INVALID_TASK_ID 3872 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID 3873 || mNextAffiliate != null) { 3874 pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId); 3875 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId); 3876 pw.print(" ("); 3877 if (mPrevAffiliate == null) { 3878 pw.print("null"); 3879 } else { 3880 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate))); 3881 } 3882 pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId); 3883 pw.print(" ("); 3884 if (mNextAffiliate == null) { 3885 pw.print("null"); 3886 } else { 3887 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate))); 3888 } 3889 pw.println(")"); 3890 } 3891 pw.print(prefix); pw.print("Activities="); pw.println(mChildren); 3892 if (!askedCompatMode || !inRecents || !isAvailable) { 3893 pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode); 3894 pw.print(" inRecents="); pw.print(inRecents); 3895 pw.print(" isAvailable="); pw.println(isAvailable); 3896 } 3897 if (lastDescription != null) { 3898 pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription); 3899 } 3900 if (mRootProcess != null) { 3901 pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess); 3902 } 3903 pw.print(prefix); pw.print("taskId=" + mTaskId); pw.println(" stackId=" + getRootTaskId()); 3904 pw.print(prefix); pw.print("mHasBeenVisible="); pw.println(getHasBeenVisible()); 3905 pw.print(prefix); pw.print("mResizeMode="); 3906 pw.print(ActivityInfo.resizeModeToString(mResizeMode)); 3907 pw.print(" mSupportsPictureInPicture="); pw.print(mSupportsPictureInPicture); 3908 pw.print(" isResizeable="); pw.println(isResizeable()); 3909 pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime); 3910 pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)"); 3911 } 3912 3913 @Override 3914 public String toString() { 3915 StringBuilder sb = new StringBuilder(128); 3916 if (stringName != null) { 3917 sb.append(stringName); 3918 sb.append(" U="); 3919 sb.append(mUserId); 3920 sb.append(" StackId="); 3921 sb.append(getRootTaskId()); 3922 sb.append(" sz="); 3923 sb.append(getChildCount()); 3924 sb.append('}'); 3925 return sb.toString(); 3926 } 3927 sb.append("Task{"); 3928 sb.append(Integer.toHexString(System.identityHashCode(this))); 3929 sb.append(" #"); 3930 sb.append(mTaskId); 3931 sb.append(" visible=" + shouldBeVisible(null /* starting */)); 3932 sb.append(" type=" + activityTypeToString(getActivityType())); 3933 sb.append(" mode=" + windowingModeToString(getWindowingMode())); 3934 sb.append(" translucent=" + isTranslucent(null /* starting */)); 3935 if (affinity != null) { 3936 sb.append(" A="); 3937 sb.append(affinity); 3938 } else if (intent != null && intent.getComponent() != null) { 3939 sb.append(" I="); 3940 sb.append(intent.getComponent().flattenToShortString()); 3941 } else if (affinityIntent != null && affinityIntent.getComponent() != null) { 3942 sb.append(" aI="); 3943 sb.append(affinityIntent.getComponent().flattenToShortString()); 3944 } else { 3945 sb.append(" ??"); 3946 } 3947 stringName = sb.toString(); 3948 return toString(); 3949 } 3950 3951 /** @see #getNumRunningActivities(TaskActivitiesReport) */ 3952 static class TaskActivitiesReport implements Consumer<ActivityRecord> { 3953 int numRunning; 3954 int numActivities; 3955 ActivityRecord top; 3956 ActivityRecord base; 3957 3958 void reset() { 3959 numRunning = numActivities = 0; 3960 top = base = null; 3961 } 3962 3963 @Override 3964 public void accept(ActivityRecord r) { 3965 if (r.finishing) { 3966 return; 3967 } 3968 3969 base = r; 3970 3971 // Increment the total number of non-finishing activities 3972 numActivities++; 3973 3974 if (top == null || (top.isState(ActivityState.INITIALIZING))) { 3975 top = r; 3976 // Reset the number of running activities until we hit the first non-initializing 3977 // activity 3978 numRunning = 0; 3979 } 3980 if (r.attachedToProcess()) { 3981 // Increment the number of actually running activities 3982 numRunning++; 3983 } 3984 } 3985 } 3986 3987 /** 3988 * Saves this {@link Task} to XML using given serializer. 3989 */ 3990 void saveToXml(XmlSerializer out) throws Exception { 3991 if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this); 3992 3993 out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId)); 3994 if (realActivity != null) { 3995 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString()); 3996 } 3997 out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended)); 3998 if (origActivity != null) { 3999 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString()); 4000 } 4001 // Write affinity, and root affinity if it is different from affinity. 4002 // We use the special string "@" for a null root affinity, so we can identify 4003 // later whether we were given a root affinity or should just make it the 4004 // same as the affinity. 4005 if (affinity != null) { 4006 out.attribute(null, ATTR_AFFINITY, affinity); 4007 if (!affinity.equals(rootAffinity)) { 4008 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 4009 } 4010 } else if (rootAffinity != null) { 4011 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 4012 } 4013 if (mWindowLayoutAffinity != null) { 4014 out.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity); 4015 } 4016 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset)); 4017 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents)); 4018 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode)); 4019 out.attribute(null, ATTR_USERID, String.valueOf(mUserId)); 4020 out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete)); 4021 out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid)); 4022 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved)); 4023 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity)); 4024 if (lastDescription != null) { 4025 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); 4026 } 4027 if (getTaskDescription() != null) { 4028 getTaskDescription().saveToXml(out); 4029 } 4030 out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); 4031 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); 4032 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId)); 4033 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId)); 4034 out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid)); 4035 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage); 4036 out.attribute(null, ATTR_CALLING_FEATURE_ID, 4037 mCallingFeatureId == null ? "" : mCallingFeatureId); 4038 out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode)); 4039 out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE, 4040 String.valueOf(mSupportsPictureInPicture)); 4041 if (mLastNonFullscreenBounds != null) { 4042 out.attribute( 4043 null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString()); 4044 } 4045 out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth)); 4046 out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight)); 4047 out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION)); 4048 4049 if (affinityIntent != null) { 4050 out.startTag(null, TAG_AFFINITYINTENT); 4051 affinityIntent.saveToXml(out); 4052 out.endTag(null, TAG_AFFINITYINTENT); 4053 } 4054 4055 if (intent != null) { 4056 out.startTag(null, TAG_INTENT); 4057 intent.saveToXml(out); 4058 out.endTag(null, TAG_INTENT); 4059 } 4060 4061 sTmpException = null; 4062 final PooledFunction f = PooledLambda.obtainFunction(Task::saveActivityToXml, 4063 PooledLambda.__(ActivityRecord.class), getBottomMostActivity(), out); 4064 forAllActivities(f); 4065 f.recycle(); 4066 if (sTmpException != null) { 4067 throw sTmpException; 4068 } 4069 } 4070 4071 private static boolean saveActivityToXml( 4072 ActivityRecord r, ActivityRecord first, XmlSerializer out) { 4073 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() 4074 || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT 4075 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) 4076 && r != first) { 4077 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET). 4078 return true; 4079 } 4080 try { 4081 out.startTag(null, TAG_ACTIVITY); 4082 r.saveToXml(out); 4083 out.endTag(null, TAG_ACTIVITY); 4084 return false; 4085 } catch (Exception e) { 4086 sTmpException = e; 4087 return true; 4088 } 4089 } 4090 4091 static Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) 4092 throws IOException, XmlPullParserException { 4093 Intent intent = null; 4094 Intent affinityIntent = null; 4095 ArrayList<ActivityRecord> activities = new ArrayList<>(); 4096 ComponentName realActivity = null; 4097 boolean realActivitySuspended = false; 4098 ComponentName origActivity = null; 4099 String affinity = null; 4100 String rootAffinity = null; 4101 boolean hasRootAffinity = false; 4102 String windowLayoutAffinity = null; 4103 boolean rootHasReset = false; 4104 boolean autoRemoveRecents = false; 4105 boolean askedCompatMode = false; 4106 int taskType = 0; 4107 int userId = 0; 4108 boolean userSetupComplete = true; 4109 int effectiveUid = -1; 4110 String lastDescription = null; 4111 long lastTimeOnTop = 0; 4112 boolean neverRelinquishIdentity = true; 4113 int taskId = INVALID_TASK_ID; 4114 final int outerDepth = in.getDepth(); 4115 TaskDescription taskDescription = new TaskDescription(); 4116 int taskAffiliation = INVALID_TASK_ID; 4117 int taskAffiliationColor = 0; 4118 int prevTaskId = INVALID_TASK_ID; 4119 int nextTaskId = INVALID_TASK_ID; 4120 int callingUid = -1; 4121 String callingPackage = ""; 4122 String callingFeatureId = null; 4123 int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; 4124 boolean supportsPictureInPicture = false; 4125 Rect lastNonFullscreenBounds = null; 4126 int minWidth = INVALID_MIN_SIZE; 4127 int minHeight = INVALID_MIN_SIZE; 4128 int persistTaskVersion = 0; 4129 4130 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { 4131 final String attrName = in.getAttributeName(attrNdx); 4132 final String attrValue = in.getAttributeValue(attrNdx); 4133 if (TaskPersister.DEBUG) { 4134 Slog.d(TaskPersister.TAG, "Task: attribute name=" + attrName + " value=" 4135 + attrValue); 4136 } 4137 switch (attrName) { 4138 case ATTR_TASKID: 4139 if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue); 4140 break; 4141 case ATTR_REALACTIVITY: 4142 realActivity = ComponentName.unflattenFromString(attrValue); 4143 break; 4144 case ATTR_REALACTIVITY_SUSPENDED: 4145 realActivitySuspended = Boolean.valueOf(attrValue); 4146 break; 4147 case ATTR_ORIGACTIVITY: 4148 origActivity = ComponentName.unflattenFromString(attrValue); 4149 break; 4150 case ATTR_AFFINITY: 4151 affinity = attrValue; 4152 break; 4153 case ATTR_ROOT_AFFINITY: 4154 rootAffinity = attrValue; 4155 hasRootAffinity = true; 4156 break; 4157 case ATTR_WINDOW_LAYOUT_AFFINITY: 4158 windowLayoutAffinity = attrValue; 4159 break; 4160 case ATTR_ROOTHASRESET: 4161 rootHasReset = Boolean.parseBoolean(attrValue); 4162 break; 4163 case ATTR_AUTOREMOVERECENTS: 4164 autoRemoveRecents = Boolean.parseBoolean(attrValue); 4165 break; 4166 case ATTR_ASKEDCOMPATMODE: 4167 askedCompatMode = Boolean.parseBoolean(attrValue); 4168 break; 4169 case ATTR_USERID: 4170 userId = Integer.parseInt(attrValue); 4171 break; 4172 case ATTR_USER_SETUP_COMPLETE: 4173 userSetupComplete = Boolean.parseBoolean(attrValue); 4174 break; 4175 case ATTR_EFFECTIVE_UID: 4176 effectiveUid = Integer.parseInt(attrValue); 4177 break; 4178 case ATTR_TASKTYPE: 4179 taskType = Integer.parseInt(attrValue); 4180 break; 4181 case ATTR_LASTDESCRIPTION: 4182 lastDescription = attrValue; 4183 break; 4184 case ATTR_LASTTIMEMOVED: 4185 lastTimeOnTop = Long.parseLong(attrValue); 4186 break; 4187 case ATTR_NEVERRELINQUISH: 4188 neverRelinquishIdentity = Boolean.parseBoolean(attrValue); 4189 break; 4190 case ATTR_TASK_AFFILIATION: 4191 taskAffiliation = Integer.parseInt(attrValue); 4192 break; 4193 case ATTR_PREV_AFFILIATION: 4194 prevTaskId = Integer.parseInt(attrValue); 4195 break; 4196 case ATTR_NEXT_AFFILIATION: 4197 nextTaskId = Integer.parseInt(attrValue); 4198 break; 4199 case ATTR_TASK_AFFILIATION_COLOR: 4200 taskAffiliationColor = Integer.parseInt(attrValue); 4201 break; 4202 case ATTR_CALLING_UID: 4203 callingUid = Integer.parseInt(attrValue); 4204 break; 4205 case ATTR_CALLING_PACKAGE: 4206 callingPackage = attrValue; 4207 break; 4208 case ATTR_CALLING_FEATURE_ID: 4209 callingFeatureId = attrValue; 4210 break; 4211 case ATTR_RESIZE_MODE: 4212 resizeMode = Integer.parseInt(attrValue); 4213 break; 4214 case ATTR_SUPPORTS_PICTURE_IN_PICTURE: 4215 supportsPictureInPicture = Boolean.parseBoolean(attrValue); 4216 break; 4217 case ATTR_NON_FULLSCREEN_BOUNDS: 4218 lastNonFullscreenBounds = Rect.unflattenFromString(attrValue); 4219 break; 4220 case ATTR_MIN_WIDTH: 4221 minWidth = Integer.parseInt(attrValue); 4222 break; 4223 case ATTR_MIN_HEIGHT: 4224 minHeight = Integer.parseInt(attrValue); 4225 break; 4226 case ATTR_PERSIST_TASK_VERSION: 4227 persistTaskVersion = Integer.parseInt(attrValue); 4228 break; 4229 default: 4230 if (!attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) { 4231 Slog.w(TAG, "Task: Unknown attribute=" + attrName); 4232 } 4233 } 4234 } 4235 taskDescription.restoreFromXml(in); 4236 4237 int event; 4238 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) 4239 && (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) { 4240 if (event == XmlPullParser.START_TAG) { 4241 final String name = in.getName(); 4242 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: START_TAG name=" + name); 4243 if (TAG_AFFINITYINTENT.equals(name)) { 4244 affinityIntent = Intent.restoreFromXml(in); 4245 } else if (TAG_INTENT.equals(name)) { 4246 intent = Intent.restoreFromXml(in); 4247 } else if (TAG_ACTIVITY.equals(name)) { 4248 ActivityRecord activity = 4249 ActivityRecord.restoreFromXml(in, stackSupervisor); 4250 if (TaskPersister.DEBUG) { 4251 Slog.d(TaskPersister.TAG, "Task: activity=" + activity); 4252 } 4253 if (activity != null) { 4254 activities.add(activity); 4255 } 4256 } else { 4257 Slog.e(TAG, "restoreTask: Unexpected name=" + name); 4258 XmlUtils.skipCurrentTag(in); 4259 } 4260 } 4261 } 4262 if (!hasRootAffinity) { 4263 rootAffinity = affinity; 4264 } else if ("@".equals(rootAffinity)) { 4265 rootAffinity = null; 4266 } 4267 if (effectiveUid <= 0) { 4268 Intent checkIntent = intent != null ? intent : affinityIntent; 4269 effectiveUid = 0; 4270 if (checkIntent != null) { 4271 IPackageManager pm = AppGlobals.getPackageManager(); 4272 try { 4273 ApplicationInfo ai = pm.getApplicationInfo( 4274 checkIntent.getComponent().getPackageName(), 4275 PackageManager.MATCH_UNINSTALLED_PACKAGES 4276 | PackageManager.MATCH_DISABLED_COMPONENTS, userId); 4277 if (ai != null) { 4278 effectiveUid = ai.uid; 4279 } 4280 } catch (RemoteException e) { 4281 } 4282 } 4283 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent 4284 + ": effectiveUid=" + effectiveUid); 4285 } 4286 4287 if (persistTaskVersion < 1) { 4288 // We need to convert the resize mode of home activities saved before version one if 4289 // they are marked as RESIZE_MODE_RESIZEABLE to 4290 // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation 4291 // before version 1 and the system didn't resize home activities before then. 4292 if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) { 4293 resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 4294 } 4295 } else { 4296 // This activity has previously marked itself explicitly as both resizeable and 4297 // supporting picture-in-picture. Since there is no longer a requirement for 4298 // picture-in-picture activities to be resizeable, we can mark this simply as 4299 // resizeable and supporting picture-in-picture separately. 4300 if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) { 4301 resizeMode = RESIZE_MODE_RESIZEABLE; 4302 supportsPictureInPicture = true; 4303 } 4304 } 4305 4306 final Task task = new ActivityStack(stackSupervisor.mService, taskId, intent, 4307 affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, 4308 autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription, 4309 lastTimeOnTop, neverRelinquishIdentity, taskDescription, taskAffiliation, 4310 prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage, 4311 callingFeatureId, resizeMode, supportsPictureInPicture, realActivitySuspended, 4312 userSetupComplete, minWidth, minHeight, null /*ActivityInfo*/, 4313 null /*_voiceSession*/, null /*_voiceInteractor*/, null /* stack */); 4314 task.mLastNonFullscreenBounds = lastNonFullscreenBounds; 4315 task.setBounds(lastNonFullscreenBounds); 4316 task.mWindowLayoutAffinity = windowLayoutAffinity; 4317 4318 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { 4319 task.addChild(activities.get(activityNdx)); 4320 } 4321 4322 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task); 4323 return task; 4324 } 4325 4326 @Override 4327 boolean isOrganized() { 4328 return mTaskOrganizer != null; 4329 } 4330 4331 @Override 4332 protected void reparentSurfaceControl(SurfaceControl.Transaction t, SurfaceControl newParent) { 4333 /** 4334 * Avoid reparenting SurfaceControl of the organized tasks that are always on top, since 4335 * the surfaces should be controlled by the organizer itself, like bubbles. 4336 */ 4337 if (isOrganized() && isAlwaysOnTop()) { 4338 return; 4339 } 4340 super.reparentSurfaceControl(t, newParent); 4341 } 4342 4343 void setHasBeenVisible(boolean hasBeenVisible) { 4344 final boolean prevHasBeenVisible = mHasBeenVisible; 4345 mHasBeenVisible = hasBeenVisible; 4346 if (hasBeenVisible) { 4347 // If the task is not yet visible when it is added to the task organizer, then we should 4348 // hide it to allow the task organizer to show it when it is properly reparented. We 4349 // skip this for tasks created by the organizer because they can synchronously update 4350 // the leash before new children are added to the task. 4351 if (!mCreatedByOrganizer && mTaskOrganizer != null && !prevHasBeenVisible) { 4352 getSyncTransaction().hide(getSurfaceControl()); 4353 commitPendingTransaction(); 4354 } 4355 4356 sendTaskAppeared(); 4357 if (!isRootTask()) { 4358 getRootTask().setHasBeenVisible(true); 4359 } 4360 } 4361 } 4362 4363 boolean getHasBeenVisible() { 4364 return mHasBeenVisible; 4365 } 4366 4367 /** In the case that these conditions are true, we want to send the Task to the organizer: 4368 * 1. An organizer has been set 4369 * 2. The Task was created by the organizer 4370 * or 4371 * 2a. We have a SurfaceControl 4372 * 2b. We have finished drawing 4373 * Any time any of these conditions are updated, the updating code should call 4374 * sendTaskAppeared. 4375 */ 4376 boolean taskAppearedReady() { 4377 if (mTaskOrganizer == null) { 4378 return false; 4379 } 4380 4381 if (mCreatedByOrganizer) { 4382 return true; 4383 } 4384 4385 return mSurfaceControl != null && getHasBeenVisible(); 4386 } 4387 4388 private void sendTaskAppeared() { 4389 if (mTaskOrganizer != null) { 4390 mAtmService.mTaskOrganizerController.onTaskAppeared(mTaskOrganizer, this); 4391 } 4392 } 4393 4394 private void sendTaskVanished(ITaskOrganizer organizer) { 4395 if (organizer != null) { 4396 mAtmService.mTaskOrganizerController.onTaskVanished(organizer, this); 4397 } 4398 } 4399 4400 @VisibleForTesting 4401 boolean setTaskOrganizer(ITaskOrganizer organizer) { 4402 if (mTaskOrganizer == organizer) { 4403 return false; 4404 } 4405 4406 ITaskOrganizer previousOrganizer = mTaskOrganizer; 4407 // Update the new task organizer before calling sendTaskVanished since it could result in 4408 // a new SurfaceControl getting created that would notify the old organizer about it. 4409 mTaskOrganizer = organizer; 4410 // Let the old organizer know it has lost control. 4411 sendTaskVanished(previousOrganizer); 4412 4413 if (mTaskOrganizer != null) { 4414 sendTaskAppeared(); 4415 } else { 4416 // No longer managed by any organizer. 4417 mTaskAppearedSent = false; 4418 mLastTaskOrganizerWindowingMode = -1; 4419 setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */); 4420 if (mCreatedByOrganizer) { 4421 removeImmediately(); 4422 } 4423 } 4424 4425 return true; 4426 } 4427 4428 /** 4429 * Called when the task state changes (ie. from windowing mode change) an the task organizer 4430 * state should also be updated. 4431 * 4432 * @param forceUpdate Updates the task organizer to the one currently specified in the task 4433 * org controller for the task's windowing mode, ignoring the cached 4434 * windowing mode checks. 4435 * @return {@code true} if task organizer changed. 4436 */ 4437 boolean updateTaskOrganizerState(boolean forceUpdate) { 4438 if (!isRootTask()) { 4439 return false; 4440 } 4441 4442 final int windowingMode = getWindowingMode(); 4443 if (!forceUpdate && windowingMode == mLastTaskOrganizerWindowingMode) { 4444 // If our windowing mode hasn't actually changed, then just stick 4445 // with our old organizer. This lets us implement the semantic 4446 // where SysUI can continue to manage it's old tasks 4447 // while CTS temporarily takes over the registration. 4448 return false; 4449 } 4450 /* 4451 * Different windowing modes may be managed by different task organizers. If 4452 * getTaskOrganizer returns null, we still call setTaskOrganizer to 4453 * make sure we clear it. 4454 */ 4455 final ITaskOrganizer org = 4456 mWmService.mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode); 4457 final boolean result = setTaskOrganizer(org); 4458 mLastTaskOrganizerWindowingMode = windowingMode; 4459 return result; 4460 } 4461 4462 @Override 4463 void setSurfaceControl(SurfaceControl sc) { 4464 super.setSurfaceControl(sc); 4465 // If the TaskOrganizer was set before we created the SurfaceControl, we need to 4466 // emit the callbacks now. 4467 sendTaskAppeared(); 4468 } 4469 4470 /** 4471 * @return true if the task is currently focused. 4472 */ 4473 private boolean isFocused() { 4474 if (mDisplayContent == null || mDisplayContent.mCurrentFocus == null) { 4475 return false; 4476 } 4477 return mDisplayContent.mCurrentFocus.getTask() == this; 4478 } 4479 4480 /** 4481 * @return true if the task is visible and has at least one visible child. 4482 */ 4483 private boolean hasVisibleChildren() { 4484 if (!isAttached() || isForceHidden()) { 4485 return false; 4486 } 4487 4488 return getActivity(ActivityRecord::isVisible) != null; 4489 } 4490 4491 /** 4492 * @return the desired shadow radius in pixels for the current task. 4493 */ 4494 private float getShadowRadius(boolean taskIsFocused) { 4495 int elevation = 0; 4496 4497 // Get elevation for a specific windowing mode. 4498 if (inPinnedWindowingMode()) { 4499 elevation = PINNED_WINDOWING_MODE_ELEVATION_IN_DIP; 4500 } else if (inFreeformWindowingMode()) { 4501 elevation = taskIsFocused 4502 ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; 4503 } else { 4504 // For all other windowing modes, do not draw a shadow. 4505 return 0; 4506 } 4507 4508 // If the task has no visible children, do not draw a shadow. 4509 if (!hasVisibleChildren()) { 4510 return 0; 4511 } 4512 4513 return dipToPixel(elevation, getDisplayContent().getDisplayMetrics()); 4514 } 4515 4516 /** 4517 * Update the length of the shadow if needed based on windowing mode and task focus state. 4518 */ 4519 private void updateShadowsRadius(boolean taskIsFocused, 4520 SurfaceControl.Transaction pendingTransaction) { 4521 if (!mWmService.mRenderShadowsInCompositor || !isRootTask()) return; 4522 4523 final float newShadowRadius = getShadowRadius(taskIsFocused); 4524 if (mShadowRadius != newShadowRadius) { 4525 mShadowRadius = newShadowRadius; 4526 pendingTransaction.setShadowRadius(getSurfaceControl(), mShadowRadius); 4527 } 4528 } 4529 4530 /** 4531 * Called on the task of a window which gained or lost focus. 4532 * @param hasFocus 4533 */ 4534 void onWindowFocusChanged(boolean hasFocus) { 4535 updateShadowsRadius(hasFocus, getSyncTransaction()); 4536 } 4537 4538 void onPictureInPictureParamsChanged() { 4539 if (isOrganized()) { 4540 mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, true /* force */); 4541 } 4542 } 4543 4544 /** 4545 * See {@link WindowContainerTransaction#setBoundsChangeTransaction}. In short this 4546 * transaction will be consumed by the next BASE_APPLICATION window within our hierarchy 4547 * to resize, and it will defer the transaction until that resize frame completes. 4548 */ 4549 void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t) { 4550 setMainWindowSizeChangeTransaction(t, this); 4551 forAllWindows(WindowState::requestRedrawForSync, true); 4552 } 4553 4554 private void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t, Task origin) { 4555 // This is only meaningful on an activity's task, so put it on the top one. 4556 ActivityRecord topActivity = getTopNonFinishingActivity(); 4557 Task leaf = topActivity != null ? topActivity.getTask() : null; 4558 if (leaf == null) { 4559 return; 4560 } 4561 if (leaf != this) { 4562 leaf.setMainWindowSizeChangeTransaction(t, origin); 4563 return; 4564 } 4565 mMainWindowSizeChangeTransaction = t; 4566 mMainWindowSizeChangeTask = t == null ? null : origin; 4567 } 4568 4569 SurfaceControl.Transaction getMainWindowSizeChangeTransaction() { 4570 return mMainWindowSizeChangeTransaction; 4571 } 4572 4573 Task getMainWindowSizeChangeTask() { 4574 return mMainWindowSizeChangeTask; 4575 } 4576 4577 void setActivityWindowingMode(int windowingMode) { 4578 PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setWindowingMode, 4579 PooledLambda.__(ActivityRecord.class), windowingMode); 4580 forAllActivities(c); 4581 c.recycle(); 4582 } 4583 4584 /** 4585 * Sets/unsets the forced-hidden state flag for this task depending on {@param set}. 4586 * @return Whether the force hidden state changed 4587 */ 4588 boolean setForceHidden(int flags, boolean set) { 4589 int newFlags = mForceHiddenFlags; 4590 if (set) { 4591 newFlags |= flags; 4592 } else { 4593 newFlags &= ~flags; 4594 } 4595 if (mForceHiddenFlags == newFlags) { 4596 return false; 4597 } 4598 final boolean wasHidden = isForceHidden(); 4599 mForceHiddenFlags = newFlags; 4600 if (wasHidden != isForceHidden() && isTopActivityFocusable()) { 4601 // The change in force-hidden state will change visibility without triggering a root 4602 // task order change, so we should reset the preferred top focusable root task to ensure 4603 // it's not used if a new activity is started from this task. 4604 getDisplayArea().resetPreferredTopFocusableRootTaskIfNeeded(this); 4605 } 4606 return true; 4607 } 4608 4609 /** 4610 * Returns whether this task is currently forced to be hidden for any reason. 4611 */ 4612 protected boolean isForceHidden() { 4613 return mForceHiddenFlags != 0; 4614 } 4615 4616 @Override 4617 long getProtoFieldId() { 4618 return TASK; 4619 } 4620 4621 } 4622