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_WHITELISTED; 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_WHITELISTED = 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 whitelists 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 performClearTask("clear-task-all"); 1532 mReuseTask = false; 1533 } 1534 performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags)1535 ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) { 1536 mReuseTask = true; 1537 final ActivityRecord result = performClearTaskLocked(newR, launchFlags); 1538 mReuseTask = false; 1539 return result; 1540 } 1541 1542 /** 1543 * Perform clear operation as requested by 1544 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the 1545 * stack to the given task, then look for 1546 * an instance of that activity in the stack and, if found, finish all 1547 * activities on top of it and return the instance. 1548 * 1549 * @param newR Description of the new activity being started. 1550 * @return Returns the old activity that should be continued to be used, 1551 * or {@code null} if none was found. 1552 */ performClearTaskLocked(ActivityRecord newR, int launchFlags)1553 private ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) { 1554 final ActivityRecord r = findActivityInHistory(newR.mActivityComponent); 1555 if (r == null) return null; 1556 1557 final PooledFunction f = PooledLambda.obtainFunction(Task::finishActivityAbove, 1558 PooledLambda.__(ActivityRecord.class), r); 1559 forAllActivities(f); 1560 f.recycle(); 1561 1562 // Finally, if this is a normal launch mode (that is, not expecting onNewIntent()), then we 1563 // will finish the current instance of the activity so a new fresh one can be started. 1564 if (r.launchMode == ActivityInfo.LAUNCH_MULTIPLE 1565 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0 1566 && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) { 1567 if (!r.finishing) { 1568 r.finishIfPossible("clear-task-top", false /* oomAdj */); 1569 return null; 1570 } 1571 } 1572 1573 return r; 1574 } 1575 finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity)1576 private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity) { 1577 // Stop operation once we reach the boundary activity. 1578 if (r == boundaryActivity) return true; 1579 1580 if (!r.finishing) { 1581 final ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */); 1582 if (opts != null) { 1583 // TODO: Why is this updating the boundary activity vs. the current activity??? 1584 boundaryActivity.updateOptionsLocked(opts); 1585 } 1586 r.finishIfPossible("clear-task-stack", false /* oomAdj */); 1587 } 1588 1589 return false; 1590 } 1591 lockTaskAuthToString()1592 String lockTaskAuthToString() { 1593 switch (mLockTaskAuth) { 1594 case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK"; 1595 case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE"; 1596 case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE"; 1597 case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED"; 1598 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV"; 1599 default: return "unknown=" + mLockTaskAuth; 1600 } 1601 } 1602 setLockTaskAuth()1603 void setLockTaskAuth() { 1604 setLockTaskAuth(getRootActivity()); 1605 } 1606 setLockTaskAuth(@ullable ActivityRecord r)1607 private void setLockTaskAuth(@Nullable ActivityRecord r) { 1608 if (r == null) { 1609 mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE; 1610 return; 1611 } 1612 1613 final String pkg = (realActivity != null) ? realActivity.getPackageName() : null; 1614 final LockTaskController lockTaskController = mAtmService.getLockTaskController(); 1615 switch (r.lockTaskLaunchMode) { 1616 case LOCK_TASK_LAUNCH_MODE_DEFAULT: 1617 mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg) 1618 ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE; 1619 break; 1620 1621 case LOCK_TASK_LAUNCH_MODE_NEVER: 1622 mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK; 1623 break; 1624 1625 case LOCK_TASK_LAUNCH_MODE_ALWAYS: 1626 mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV; 1627 break; 1628 1629 case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED: 1630 mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg) 1631 ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE; 1632 break; 1633 } 1634 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this 1635 + " mLockTaskAuth=" + lockTaskAuthToString()); 1636 } 1637 1638 @Override supportsSplitScreenWindowingMode()1639 public boolean supportsSplitScreenWindowingMode() { 1640 final Task topTask = getTopMostTask(); 1641 return super.supportsSplitScreenWindowingMode() 1642 && (topTask == null || topTask.supportsSplitScreenWindowingModeInner()); 1643 } 1644 supportsSplitScreenWindowingModeInner()1645 private boolean supportsSplitScreenWindowingModeInner() { 1646 // A task can not be docked even if it is considered resizeable because it only supports 1647 // picture-in-picture mode but has a non-resizeable resizeMode 1648 return super.supportsSplitScreenWindowingMode() 1649 && mAtmService.mSupportsSplitScreenMultiWindow 1650 && (mAtmService.mForceResizableActivities 1651 || (isResizeable(false /* checkSupportsPip */) 1652 && !ActivityInfo.isPreserveOrientationMode(mResizeMode))); 1653 } 1654 1655 /** 1656 * Check whether this task can be launched on the specified display. 1657 * 1658 * @param displayId Target display id. 1659 * @return {@code true} if either it is the default display or this activity can be put on a 1660 * secondary display. 1661 */ canBeLaunchedOnDisplay(int displayId)1662 boolean canBeLaunchedOnDisplay(int displayId) { 1663 return mStackSupervisor.canPlaceEntityOnDisplay(displayId, 1664 -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */); 1665 } 1666 1667 /** 1668 * Check that a given bounds matches the application requested orientation. 1669 * 1670 * @param bounds The bounds to be tested. 1671 * @return True if the requested bounds are okay for a resizing request. 1672 */ canResizeToBounds(Rect bounds)1673 private boolean canResizeToBounds(Rect bounds) { 1674 if (bounds == null || !inFreeformWindowingMode()) { 1675 // Note: If not on the freeform workspace, we ignore the bounds. 1676 return true; 1677 } 1678 final boolean landscape = bounds.width() > bounds.height(); 1679 final Rect configBounds = getRequestedOverrideBounds(); 1680 if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) { 1681 return configBounds.isEmpty() 1682 || landscape == (configBounds.width() > configBounds.height()); 1683 } 1684 return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape) 1685 && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape); 1686 } 1687 1688 /** 1689 * @return {@code true} if the task is being cleared for the purposes of being reused. 1690 */ isClearingToReuseTask()1691 boolean isClearingToReuseTask() { 1692 return mReuseTask; 1693 } 1694 1695 /** 1696 * Find the activity in the history stack within the given task. Returns 1697 * the index within the history at which it's found, or < 0 if not found. 1698 */ findActivityInHistory(ComponentName component)1699 ActivityRecord findActivityInHistory(ComponentName component) { 1700 final PooledPredicate p = PooledLambda.obtainPredicate(Task::matchesActivityInHistory, 1701 PooledLambda.__(ActivityRecord.class), component); 1702 final ActivityRecord r = getActivity(p); 1703 p.recycle(); 1704 return r; 1705 } 1706 matchesActivityInHistory( ActivityRecord r, ComponentName activityComponent)1707 private static boolean matchesActivityInHistory( 1708 ActivityRecord r, ComponentName activityComponent) { 1709 return !r.finishing && r.mActivityComponent.equals(activityComponent); 1710 } 1711 1712 /** Updates the last task description values. */ updateTaskDescription()1713 void updateTaskDescription() { 1714 final ActivityRecord root = getRootActivity(true); 1715 if (root == null) return; 1716 1717 final TaskDescription taskDescription = new TaskDescription(); 1718 final PooledFunction f = PooledLambda.obtainFunction( 1719 Task::setTaskDescriptionFromActivityAboveRoot, 1720 PooledLambda.__(ActivityRecord.class), root, taskDescription); 1721 forAllActivities(f); 1722 f.recycle(); 1723 taskDescription.setResizeMode(mResizeMode); 1724 taskDescription.setMinWidth(mMinWidth); 1725 taskDescription.setMinHeight(mMinHeight); 1726 setTaskDescription(taskDescription); 1727 // Update the task affiliation color if we are the parent of the group 1728 if (mTaskId == mAffiliatedTaskId) { 1729 mAffiliatedTaskColor = taskDescription.getPrimaryColor(); 1730 } 1731 mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged( 1732 getTaskInfo()); 1733 1734 final WindowContainer parent = getParent(); 1735 if (parent != null) { 1736 final Task t = parent.asTask(); 1737 if (t != null) { 1738 t.updateTaskDescription(); 1739 } 1740 } 1741 1742 if (isOrganized()) { 1743 mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */); 1744 } 1745 } 1746 setTaskDescriptionFromActivityAboveRoot( ActivityRecord r, ActivityRecord root, TaskDescription td)1747 private static boolean setTaskDescriptionFromActivityAboveRoot( 1748 ActivityRecord r, ActivityRecord root, TaskDescription td) { 1749 if (!r.isTaskOverlay() && r.taskDescription != null) { 1750 final TaskDescription atd = r.taskDescription; 1751 if (td.getLabel() == null) { 1752 td.setLabel(atd.getLabel()); 1753 } 1754 if (td.getRawIcon() == null) { 1755 td.setIcon(atd.getRawIcon()); 1756 } 1757 if (td.getIconFilename() == null) { 1758 td.setIconFilename(atd.getIconFilename()); 1759 } 1760 if (td.getPrimaryColor() == 0) { 1761 td.setPrimaryColor(atd.getPrimaryColor()); 1762 } 1763 if (td.getBackgroundColor() == 0) { 1764 td.setBackgroundColor(atd.getBackgroundColor()); 1765 } 1766 if (td.getStatusBarColor() == 0) { 1767 td.setStatusBarColor(atd.getStatusBarColor()); 1768 td.setEnsureStatusBarContrastWhenTransparent( 1769 atd.getEnsureStatusBarContrastWhenTransparent()); 1770 } 1771 if (td.getNavigationBarColor() == 0) { 1772 td.setNavigationBarColor(atd.getNavigationBarColor()); 1773 td.setEnsureNavigationBarContrastWhenTransparent( 1774 atd.getEnsureNavigationBarContrastWhenTransparent()); 1775 } 1776 1777 } 1778 1779 // End search once we get to root. 1780 return r == root; 1781 } 1782 1783 // TODO (AM refactor): Invoke automatically when there is a change in children 1784 @VisibleForTesting updateEffectiveIntent()1785 void updateEffectiveIntent() { 1786 final ActivityRecord root = getRootActivity(true /*setToBottomIfNone*/); 1787 if (root != null) { 1788 setIntent(root); 1789 // Update the task description when the activities change 1790 updateTaskDescription(); 1791 } 1792 } 1793 adjustForMinimalTaskDimensions(@onNull Rect bounds, @NonNull Rect previousBounds, @NonNull Configuration parentConfig)1794 void adjustForMinimalTaskDimensions(@NonNull Rect bounds, @NonNull Rect previousBounds, 1795 @NonNull Configuration parentConfig) { 1796 int minWidth = mMinWidth; 1797 int minHeight = mMinHeight; 1798 // If the task has no requested minimal size, we'd like to enforce a minimal size 1799 // so that the user can not render the task too small to manipulate. We don't need 1800 // to do this for the pinned stack as the bounds are controlled by the system. 1801 if (!inPinnedWindowingMode()) { 1802 final int defaultMinSizeDp = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp; 1803 final float density = (float) parentConfig.densityDpi / DisplayMetrics.DENSITY_DEFAULT; 1804 final int defaultMinSize = (int) (defaultMinSizeDp * density); 1805 1806 if (minWidth == INVALID_MIN_SIZE) { 1807 minWidth = defaultMinSize; 1808 } 1809 if (minHeight == INVALID_MIN_SIZE) { 1810 minHeight = defaultMinSize; 1811 } 1812 } 1813 if (bounds.isEmpty()) { 1814 // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they 1815 // do, we can just skip. 1816 final Rect parentBounds = parentConfig.windowConfiguration.getBounds(); 1817 if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) { 1818 return; 1819 } 1820 bounds.set(parentBounds); 1821 } 1822 final boolean adjustWidth = minWidth > bounds.width(); 1823 final boolean adjustHeight = minHeight > bounds.height(); 1824 if (!(adjustWidth || adjustHeight)) { 1825 return; 1826 } 1827 1828 if (adjustWidth) { 1829 if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) { 1830 bounds.left = bounds.right - minWidth; 1831 } else { 1832 // Either left bounds match, or neither match, or the previous bounds were 1833 // fullscreen and we default to keeping left. 1834 bounds.right = bounds.left + minWidth; 1835 } 1836 } 1837 if (adjustHeight) { 1838 if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) { 1839 bounds.top = bounds.bottom - minHeight; 1840 } else { 1841 // Either top bounds match, or neither match, or the previous bounds were 1842 // fullscreen and we default to keeping top. 1843 bounds.bottom = bounds.top + minHeight; 1844 } 1845 } 1846 } 1847 setLastNonFullscreenBounds(Rect bounds)1848 void setLastNonFullscreenBounds(Rect bounds) { 1849 if (mLastNonFullscreenBounds == null) { 1850 mLastNonFullscreenBounds = new Rect(bounds); 1851 } else { 1852 mLastNonFullscreenBounds.set(bounds); 1853 } 1854 } 1855 1856 /** 1857 * This should be called when an child activity changes state. This should only 1858 * be called from 1859 * {@link ActivityRecord#setState(ActivityState, String)} . 1860 * @param record The {@link ActivityRecord} whose state has changed. 1861 * @param state The new state. 1862 * @param reason The reason for the change. 1863 */ onActivityStateChanged(ActivityRecord record, ActivityState state, String reason)1864 void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) { 1865 final Task parentTask = getParent().asTask(); 1866 if (parentTask != null) { 1867 parentTask.onActivityStateChanged(record, state, reason); 1868 // We still want to update the resumed activity if the parent task is created by 1869 // organizer in order to keep the information synced once got reparented out from the 1870 // organized task. 1871 if (!parentTask.mCreatedByOrganizer) { 1872 return; 1873 } 1874 } 1875 1876 if (record == mResumedActivity && state != RESUMED) { 1877 setResumedActivity(null, reason + " - onActivityStateChanged"); 1878 } 1879 1880 if (state == RESUMED) { 1881 if (ActivityTaskManagerDebugConfig.DEBUG_STACK) { 1882 Slog.v(TAG_STACK, "set resumed activity to:" + record + " reason:" + reason); 1883 } 1884 setResumedActivity(record, reason + " - onActivityStateChanged"); 1885 if (record == mRootWindowContainer.getTopResumedActivity()) { 1886 mAtmService.setResumedActivityUncheckLocked(record, reason); 1887 } 1888 mStackSupervisor.mRecentTasks.add(record.getTask()); 1889 } 1890 } 1891 1892 @Override onConfigurationChanged(Configuration newParentConfig)1893 public void onConfigurationChanged(Configuration newParentConfig) { 1894 // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so 1895 // restore the last recorded non-fullscreen bounds. 1896 final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds(); 1897 boolean nextPersistTaskBounds = 1898 getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds(); 1899 if (getRequestedOverrideWindowingMode() == WINDOWING_MODE_UNDEFINED) { 1900 nextPersistTaskBounds = newParentConfig.windowConfiguration.persistTaskBounds(); 1901 } 1902 if (!prevPersistTaskBounds && nextPersistTaskBounds 1903 && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) { 1904 // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop. 1905 getRequestedOverrideConfiguration().windowConfiguration 1906 .setBounds(mLastNonFullscreenBounds); 1907 } 1908 1909 final int prevWinMode = getWindowingMode(); 1910 mTmpPrevBounds.set(getBounds()); 1911 final boolean wasInMultiWindowMode = inMultiWindowMode(); 1912 final boolean wasInPictureInPicture = inPinnedWindowingMode(); 1913 super.onConfigurationChanged(newParentConfig); 1914 // Only need to update surface size here since the super method will handle updating 1915 // surface position. 1916 updateSurfaceSize(getSyncTransaction()); 1917 1918 if (wasInPictureInPicture != inPinnedWindowingMode()) { 1919 mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, getStack()); 1920 } else if (wasInMultiWindowMode != inMultiWindowMode()) { 1921 mStackSupervisor.scheduleUpdateMultiWindowMode(this); 1922 } 1923 1924 final int newWinMode = getWindowingMode(); 1925 if ((prevWinMode != newWinMode) && (mDisplayContent != null) 1926 && shouldStartChangeTransition(prevWinMode, newWinMode)) { 1927 initializeChangeTransition(mTmpPrevBounds); 1928 } 1929 1930 // If the configuration supports persistent bounds (eg. Freeform), keep track of the 1931 // current (non-fullscreen) bounds for persistence. 1932 if (getWindowConfiguration().persistTaskBounds()) { 1933 final Rect currentBounds = getRequestedOverrideBounds(); 1934 if (!currentBounds.isEmpty()) { 1935 setLastNonFullscreenBounds(currentBounds); 1936 } 1937 } 1938 1939 saveLaunchingStateIfNeeded(); 1940 final boolean taskOrgChanged = updateTaskOrganizerState(false /* forceUpdate */); 1941 // If the task organizer has changed, then it will already be receiving taskAppeared with 1942 // the latest task-info thus the task-info won't have changed. 1943 if (!taskOrgChanged && isOrganized()) { 1944 mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */); 1945 } 1946 } 1947 1948 /** 1949 * Initializes a change transition. See {@link SurfaceFreezer} for more information. 1950 */ initializeChangeTransition(Rect startBounds)1951 private void initializeChangeTransition(Rect startBounds) { 1952 mDisplayContent.prepareAppTransition(TRANSIT_TASK_CHANGE_WINDOWING_MODE, 1953 false /* alwaysKeepCurrent */, 0, false /* forceOverride */); 1954 mDisplayContent.mChangingContainers.add(this); 1955 1956 mSurfaceFreezer.freeze(getPendingTransaction(), startBounds); 1957 } 1958 shouldStartChangeTransition(int prevWinMode, int newWinMode)1959 private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) { 1960 if (mWmService.mDisableTransitionAnimation 1961 || !isVisible() 1962 || getDisplayContent().mAppTransition.isTransitionSet() 1963 || getSurfaceControl() == null 1964 || !isLeafTask()) { 1965 return false; 1966 } 1967 // Only do an animation into and out-of freeform mode for now. Other mode 1968 // transition animations are currently handled by system-ui. 1969 return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM); 1970 } 1971 1972 @Override migrateToNewSurfaceControl()1973 void migrateToNewSurfaceControl() { 1974 super.migrateToNewSurfaceControl(); 1975 mLastSurfaceSize.x = 0; 1976 mLastSurfaceSize.y = 0; 1977 updateSurfaceSize(getPendingTransaction()); 1978 } 1979 updateSurfaceSize(SurfaceControl.Transaction transaction)1980 void updateSurfaceSize(SurfaceControl.Transaction transaction) { 1981 if (mSurfaceControl == null || isOrganized()) { 1982 return; 1983 } 1984 1985 // Apply crop to root tasks only and clear the crops of the descendant tasks. 1986 int width = 0; 1987 int height = 0; 1988 if (isRootTask()) { 1989 final Rect taskBounds = getBounds(); 1990 width = taskBounds.width(); 1991 height = taskBounds.height(); 1992 1993 final int outset = getTaskOutset(); 1994 width += 2 * outset; 1995 height += 2 * outset; 1996 } 1997 if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) { 1998 return; 1999 } 2000 transaction.setWindowCrop(mSurfaceControl, width, height); 2001 mLastSurfaceSize.set(width, height); 2002 } 2003 2004 /** 2005 * Calculate an amount by which to expand the task bounds in each direction. 2006 * Used to make room for shadows in the pinned windowing mode. 2007 */ getTaskOutset()2008 int getTaskOutset() { 2009 // If we are drawing shadows on the task then don't outset the stack. 2010 if (mWmService.mRenderShadowsInCompositor) { 2011 return 0; 2012 } 2013 DisplayContent displayContent = getDisplayContent(); 2014 if (inPinnedWindowingMode() && displayContent != null) { 2015 final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics(); 2016 2017 // We multiply by two to match the client logic for converting view elevation 2018 // to insets, as in {@link WindowManager.LayoutParams#setSurfaceInsets} 2019 return (int) Math.ceil( 2020 mWmService.dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP, displayMetrics) 2021 * 2); 2022 } 2023 return 0; 2024 } 2025 2026 @VisibleForTesting getLastSurfaceSize()2027 Point getLastSurfaceSize() { 2028 return mLastSurfaceSize; 2029 } 2030 2031 @VisibleForTesting isInChangeTransition()2032 boolean isInChangeTransition() { 2033 return mSurfaceFreezer.hasLeash() || AppTransition.isChangeTransit(mTransit); 2034 } 2035 2036 @Override getFreezeSnapshotTarget()2037 public SurfaceControl getFreezeSnapshotTarget() { 2038 final int transit = mDisplayContent.mAppTransition.getAppTransition(); 2039 if (!AppTransition.isChangeTransit(transit)) { 2040 return null; 2041 } 2042 // Skip creating snapshot if this transition is controlled by a remote animator which 2043 // doesn't need it. 2044 final ArraySet<Integer> activityTypes = new ArraySet<>(); 2045 activityTypes.add(getActivityType()); 2046 final RemoteAnimationAdapter adapter = 2047 mDisplayContent.mAppTransitionController.getRemoteAnimationOverride( 2048 this, transit, activityTypes); 2049 if (adapter != null && !adapter.getChangeNeedsSnapshot()) { 2050 return null; 2051 } 2052 return getSurfaceControl(); 2053 } 2054 2055 @Override writeIdentifierToProto(ProtoOutputStream proto, long fieldId)2056 void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { 2057 final long token = proto.start(fieldId); 2058 proto.write(HASH_CODE, System.identityHashCode(this)); 2059 proto.write(USER_ID, mUserId); 2060 proto.write(TITLE, intent != null && intent.getComponent() != null 2061 ? intent.getComponent().flattenToShortString() : "Task"); 2062 proto.end(token); 2063 } 2064 2065 /** 2066 * Saves launching state if necessary so that we can launch the activity to its latest state. 2067 * It only saves state if this task has been shown to user and it's in fullscreen or freeform 2068 * mode on freeform displays. 2069 */ saveLaunchingStateIfNeeded()2070 private void saveLaunchingStateIfNeeded() { 2071 saveLaunchingStateIfNeeded(getDisplayContent()); 2072 } 2073 saveLaunchingStateIfNeeded(DisplayContent display)2074 private void saveLaunchingStateIfNeeded(DisplayContent display) { 2075 if (!getHasBeenVisible()) { 2076 // Not ever visible to user. 2077 return; 2078 } 2079 2080 final int windowingMode = getWindowingMode(); 2081 if (windowingMode != WINDOWING_MODE_FULLSCREEN 2082 && windowingMode != WINDOWING_MODE_FREEFORM) { 2083 return; 2084 } 2085 2086 // Don't persist state if display isn't in freeform mode. Then the task will be launched 2087 // back to its last state in a freeform display when it's launched in a freeform display 2088 // next time. 2089 if (getWindowConfiguration().getDisplayWindowingMode() != WINDOWING_MODE_FREEFORM) { 2090 return; 2091 } 2092 2093 // Saves the new state so that we can launch the activity at the same location. 2094 mStackSupervisor.mLaunchParamsPersister.saveTask(this, display); 2095 } 2096 2097 /** 2098 * Adjust bounds to stay within stack bounds. 2099 * 2100 * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way 2101 * that keep them unchanged, but be contained within the stack bounds. 2102 * 2103 * @param bounds Bounds to be adjusted. 2104 * @param stackBounds Bounds within which the other bounds should remain. 2105 * @param overlapPxX The amount of px required to be visible in the X dimension. 2106 * @param overlapPxY The amount of px required to be visible in the Y dimension. 2107 */ fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX, int overlapPxY)2108 private static void fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX, 2109 int overlapPxY) { 2110 if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) { 2111 return; 2112 } 2113 2114 // For each side of the parent (eg. left), check if the opposing side of the window (eg. 2115 // right) is at least overlap pixels away. If less, offset the window by that difference. 2116 int horizontalDiff = 0; 2117 // If window is smaller than overlap, use it's smallest dimension instead 2118 int overlapLR = Math.min(overlapPxX, bounds.width()); 2119 if (bounds.right < (stackBounds.left + overlapLR)) { 2120 horizontalDiff = overlapLR - (bounds.right - stackBounds.left); 2121 } else if (bounds.left > (stackBounds.right - overlapLR)) { 2122 horizontalDiff = -(overlapLR - (stackBounds.right - bounds.left)); 2123 } 2124 int verticalDiff = 0; 2125 int overlapTB = Math.min(overlapPxY, bounds.width()); 2126 if (bounds.bottom < (stackBounds.top + overlapTB)) { 2127 verticalDiff = overlapTB - (bounds.bottom - stackBounds.top); 2128 } else if (bounds.top > (stackBounds.bottom - overlapTB)) { 2129 verticalDiff = -(overlapTB - (stackBounds.bottom - bounds.top)); 2130 } 2131 bounds.offset(horizontalDiff, verticalDiff); 2132 } 2133 2134 /** 2135 * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than 2136 * intersectBounds on a side, then the respective side will not be intersected. 2137 * 2138 * The assumption is that if inOutBounds is initially larger than intersectBounds, then the 2139 * inset on that side is no-longer applicable. This scenario happens when a task's minimal 2140 * bounds are larger than the provided parent/display bounds. 2141 * 2142 * @param inOutBounds the bounds to intersect. 2143 * @param intersectBounds the bounds to intersect with. 2144 * @param intersectInsets insets to apply to intersectBounds before intersecting. 2145 */ intersectWithInsetsIfFits( Rect inOutBounds, Rect intersectBounds, Rect intersectInsets)2146 static void intersectWithInsetsIfFits( 2147 Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) { 2148 if (inOutBounds.right <= intersectBounds.right) { 2149 inOutBounds.right = 2150 Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right); 2151 } 2152 if (inOutBounds.bottom <= intersectBounds.bottom) { 2153 inOutBounds.bottom = 2154 Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom); 2155 } 2156 if (inOutBounds.left >= intersectBounds.left) { 2157 inOutBounds.left = 2158 Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left); 2159 } 2160 if (inOutBounds.top >= intersectBounds.top) { 2161 inOutBounds.top = 2162 Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top); 2163 } 2164 } 2165 2166 /** 2167 * Gets bounds with non-decor and stable insets applied respectively. 2168 * 2169 * If bounds overhangs the display, those edges will not get insets. See 2170 * {@link #intersectWithInsetsIfFits} 2171 * 2172 * @param outNonDecorBounds where to place bounds with non-decor insets applied. 2173 * @param outStableBounds where to place bounds with stable insets applied. 2174 * @param bounds the bounds to inset. 2175 */ calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, DisplayInfo displayInfo)2176 private void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, 2177 DisplayInfo displayInfo) { 2178 outNonDecorBounds.set(bounds); 2179 outStableBounds.set(bounds); 2180 if (getStack() == null || getStack().getDisplay() == null) { 2181 return; 2182 } 2183 DisplayPolicy policy = getStack().getDisplay().mDisplayContent.getDisplayPolicy(); 2184 if (policy == null) { 2185 return; 2186 } 2187 mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); 2188 2189 policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth, 2190 displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets); 2191 intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets); 2192 2193 policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation); 2194 intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets); 2195 } 2196 2197 /** 2198 * Forces the app bounds related configuration can be computed by 2199 * {@link #computeConfigResourceOverrides(Configuration, Configuration, DisplayInfo, 2200 * ActivityRecord.CompatDisplayInsets)}. 2201 */ invalidateAppBoundsConfig(@onNull Configuration inOutConfig)2202 private static void invalidateAppBoundsConfig(@NonNull Configuration inOutConfig) { 2203 final Rect appBounds = inOutConfig.windowConfiguration.getAppBounds(); 2204 if (appBounds != null) { 2205 appBounds.setEmpty(); 2206 } 2207 inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED; 2208 inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED; 2209 } 2210 computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo)2211 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, 2212 @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) { 2213 if (overrideDisplayInfo != null) { 2214 // Make sure the screen related configs can be computed by the provided display info. 2215 inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED; 2216 invalidateAppBoundsConfig(inOutConfig); 2217 } 2218 computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo, 2219 null /* compatInsets */); 2220 } 2221 computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig)2222 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, 2223 @NonNull Configuration parentConfig) { 2224 computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */, 2225 null /* compatInsets */); 2226 } 2227 computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)2228 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, 2229 @NonNull Configuration parentConfig, 2230 @Nullable ActivityRecord.CompatDisplayInsets compatInsets) { 2231 if (compatInsets != null) { 2232 // Make sure the app bounds can be computed by the compat insets. 2233 invalidateAppBoundsConfig(inOutConfig); 2234 } 2235 computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */, 2236 compatInsets); 2237 } 2238 2239 /** 2240 * Calculates configuration values used by the client to get resources. This should be run 2241 * using app-facing bounds (bounds unmodified by animations or transient interactions). 2242 * 2243 * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely 2244 * configuring an "inherit-bounds" window which means that all configuration settings would 2245 * just be inherited from the parent configuration. 2246 **/ computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)2247 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, 2248 @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo, 2249 @Nullable ActivityRecord.CompatDisplayInsets compatInsets) { 2250 int windowingMode = inOutConfig.windowConfiguration.getWindowingMode(); 2251 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 2252 windowingMode = parentConfig.windowConfiguration.getWindowingMode(); 2253 } 2254 2255 float density = inOutConfig.densityDpi; 2256 if (density == Configuration.DENSITY_DPI_UNDEFINED) { 2257 density = parentConfig.densityDpi; 2258 } 2259 density *= DisplayMetrics.DENSITY_DEFAULT_SCALE; 2260 2261 // The bounds may have been overridden at this level. If the parent cannot cover these 2262 // bounds, the configuration is still computed according to the override bounds. 2263 final boolean insideParentBounds; 2264 2265 final Rect parentBounds = parentConfig.windowConfiguration.getBounds(); 2266 final Rect resolvedBounds = inOutConfig.windowConfiguration.getBounds(); 2267 if (resolvedBounds == null || resolvedBounds.isEmpty()) { 2268 mTmpFullBounds.set(parentBounds); 2269 insideParentBounds = true; 2270 } else { 2271 mTmpFullBounds.set(resolvedBounds); 2272 insideParentBounds = parentBounds.contains(resolvedBounds); 2273 } 2274 2275 // Non-null compatibility insets means the activity prefers to keep its original size, so 2276 // out bounds doesn't need to be restricted by the parent or current display 2277 final boolean customContainerPolicy = compatInsets != null; 2278 2279 Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); 2280 if (outAppBounds == null || outAppBounds.isEmpty()) { 2281 // App-bounds hasn't been overridden, so calculate a value for it. 2282 inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds); 2283 outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); 2284 2285 if (!customContainerPolicy && windowingMode != WINDOWING_MODE_FREEFORM) { 2286 final Rect containingAppBounds; 2287 if (insideParentBounds) { 2288 containingAppBounds = parentConfig.windowConfiguration.getAppBounds(); 2289 } else { 2290 // Restrict appBounds to display non-decor rather than parent because the 2291 // override bounds are beyond the parent. Otherwise, it won't match the 2292 // overridden bounds. 2293 final TaskDisplayArea displayArea = getDisplayArea(); 2294 containingAppBounds = displayArea != null 2295 ? displayArea.getWindowConfiguration().getAppBounds() : null; 2296 } 2297 if (containingAppBounds != null && !containingAppBounds.isEmpty()) { 2298 outAppBounds.intersect(containingAppBounds); 2299 } 2300 } 2301 } 2302 2303 if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED 2304 || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { 2305 if (!customContainerPolicy && WindowConfiguration.isFloating(windowingMode)) { 2306 mTmpNonDecorBounds.set(mTmpFullBounds); 2307 mTmpStableBounds.set(mTmpFullBounds); 2308 } else if (!customContainerPolicy 2309 && (overrideDisplayInfo != null || getDisplayContent() != null)) { 2310 final DisplayInfo di = overrideDisplayInfo != null 2311 ? overrideDisplayInfo 2312 : getDisplayContent().getDisplayInfo(); 2313 2314 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen 2315 // area, i.e. the screen area without the system bars. 2316 // The non decor inset are areas that could never be removed in Honeycomb. See 2317 // {@link WindowManagerPolicy#getNonDecorInsetsLw}. 2318 calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di); 2319 } else { 2320 // Apply the given non-decor and stable insets to calculate the corresponding bounds 2321 // for screen size of configuration. 2322 int rotation = inOutConfig.windowConfiguration.getRotation(); 2323 if (rotation == ROTATION_UNDEFINED) { 2324 rotation = parentConfig.windowConfiguration.getRotation(); 2325 } 2326 if (rotation != ROTATION_UNDEFINED && customContainerPolicy) { 2327 mTmpNonDecorBounds.set(mTmpFullBounds); 2328 mTmpStableBounds.set(mTmpFullBounds); 2329 compatInsets.getBoundsByRotation(mTmpBounds, rotation); 2330 intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds, 2331 compatInsets.mNonDecorInsets[rotation]); 2332 intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds, 2333 compatInsets.mStableInsets[rotation]); 2334 outAppBounds.set(mTmpNonDecorBounds); 2335 } else { 2336 // Set to app bounds because it excludes decor insets. 2337 mTmpNonDecorBounds.set(outAppBounds); 2338 mTmpStableBounds.set(outAppBounds); 2339 } 2340 } 2341 2342 if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) { 2343 final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density); 2344 inOutConfig.screenWidthDp = (insideParentBounds && !customContainerPolicy) 2345 ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp) 2346 : overrideScreenWidthDp; 2347 } 2348 if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { 2349 final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density); 2350 inOutConfig.screenHeightDp = (insideParentBounds && !customContainerPolicy) 2351 ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp) 2352 : overrideScreenHeightDp; 2353 } 2354 2355 if (inOutConfig.smallestScreenWidthDp 2356 == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { 2357 if (WindowConfiguration.isFloating(windowingMode)) { 2358 // For floating tasks, calculate the smallest width from the bounds of the task 2359 inOutConfig.smallestScreenWidthDp = (int) ( 2360 Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density); 2361 } 2362 // otherwise, it will just inherit 2363 } 2364 } 2365 2366 if (inOutConfig.orientation == ORIENTATION_UNDEFINED) { 2367 inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp) 2368 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; 2369 } 2370 if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) { 2371 // For calculating screen layout, we need to use the non-decor inset screen area for the 2372 // calculation for compatibility reasons, i.e. screen area without system bars that 2373 // could never go away in Honeycomb. 2374 final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density); 2375 final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density); 2376 // Reducing the screen layout starting from its parent config. 2377 inOutConfig.screenLayout = computeScreenLayoutOverride(parentConfig.screenLayout, 2378 compatScreenWidthDp, compatScreenHeightDp); 2379 } 2380 } 2381 2382 /** Computes LONG, SIZE and COMPAT parts of {@link Configuration#screenLayout}. */ computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp, int screenHeightDp)2383 static int computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp, 2384 int screenHeightDp) { 2385 sourceScreenLayout = sourceScreenLayout 2386 & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK); 2387 final int longSize = Math.max(screenWidthDp, screenHeightDp); 2388 final int shortSize = Math.min(screenWidthDp, screenHeightDp); 2389 return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize); 2390 } 2391 2392 @Override resolveOverrideConfiguration(Configuration newParentConfig)2393 void resolveOverrideConfiguration(Configuration newParentConfig) { 2394 mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds()); 2395 super.resolveOverrideConfiguration(newParentConfig); 2396 2397 int windowingMode = 2398 getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode(); 2399 2400 // Resolve override windowing mode to fullscreen for home task (even on freeform 2401 // display), or split-screen if in split-screen mode. 2402 if (getActivityType() == ACTIVITY_TYPE_HOME && windowingMode == WINDOWING_MODE_UNDEFINED) { 2403 final int parentWindowingMode = newParentConfig.windowConfiguration.getWindowingMode(); 2404 windowingMode = WindowConfiguration.isSplitScreenWindowingMode(parentWindowingMode) 2405 ? parentWindowingMode : WINDOWING_MODE_FULLSCREEN; 2406 getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode); 2407 } 2408 2409 if (isLeafTask()) { 2410 resolveLeafOnlyOverrideConfigs(newParentConfig, mTmpBounds /* previousBounds */); 2411 } 2412 computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig); 2413 } 2414 resolveLeafOnlyOverrideConfigs(Configuration newParentConfig, Rect previousBounds)2415 private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig, 2416 Rect previousBounds) { 2417 int windowingMode = 2418 getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode(); 2419 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 2420 windowingMode = newParentConfig.windowConfiguration.getWindowingMode(); 2421 } 2422 Rect outOverrideBounds = 2423 getResolvedOverrideConfiguration().windowConfiguration.getBounds(); 2424 2425 if (windowingMode == WINDOWING_MODE_FULLSCREEN) { 2426 computeFullscreenBounds(outOverrideBounds, null /* refActivity */, 2427 newParentConfig.windowConfiguration.getBounds(), 2428 newParentConfig.orientation); 2429 // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if 2430 // the parent or display is smaller than the size, the content may be cropped. 2431 return; 2432 } 2433 2434 adjustForMinimalTaskDimensions(outOverrideBounds, previousBounds, newParentConfig); 2435 if (windowingMode == WINDOWING_MODE_FREEFORM) { 2436 // by policy, make sure the window remains within parent somewhere 2437 final float density = 2438 ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT; 2439 final Rect parentBounds = 2440 new Rect(newParentConfig.windowConfiguration.getBounds()); 2441 final DisplayContent display = getDisplayContent(); 2442 if (display != null) { 2443 // If a freeform window moves below system bar, there is no way to move it again 2444 // by touch. Because its caption is covered by system bar. So we exclude them 2445 // from stack bounds. and then caption will be shown inside stable area. 2446 final Rect stableBounds = new Rect(); 2447 display.getStableRect(stableBounds); 2448 parentBounds.intersect(stableBounds); 2449 } 2450 2451 fitWithinBounds(outOverrideBounds, parentBounds, 2452 (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP), 2453 (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP)); 2454 2455 // Prevent to overlap caption with stable insets. 2456 final int offsetTop = parentBounds.top - outOverrideBounds.top; 2457 if (offsetTop > 0) { 2458 outOverrideBounds.offset(0, offsetTop); 2459 } 2460 } 2461 } 2462 2463 /** 2464 * Compute bounds (letterbox or pillarbox) for 2465 * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the 2466 * orientation change and the requested orientation is different from the parent. 2467 */ computeFullscreenBounds(@onNull Rect outBounds, @Nullable ActivityRecord refActivity, @NonNull Rect parentBounds, int parentOrientation)2468 void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity, 2469 @NonNull Rect parentBounds, int parentOrientation) { 2470 // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent". 2471 outBounds.setEmpty(); 2472 if (handlesOrientationChangeFromDescendant()) { 2473 return; 2474 } 2475 if (refActivity == null) { 2476 // Use the top activity as the reference of orientation. Don't include overlays because 2477 // it is usually not the actual content or just temporarily shown. 2478 // E.g. ForcedResizableInfoActivity. 2479 refActivity = getTopNonFinishingActivity(false /* includeOverlays */); 2480 } 2481 2482 // If the task or the reference activity requires a different orientation (either by 2483 // override or activityInfo), make it fit the available bounds by scaling down its bounds. 2484 final int overrideOrientation = getRequestedOverrideConfiguration().orientation; 2485 final int forcedOrientation = 2486 (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null) 2487 ? overrideOrientation : refActivity.getRequestedConfigurationOrientation(); 2488 if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) { 2489 return; 2490 } 2491 2492 final int parentWidth = parentBounds.width(); 2493 final int parentHeight = parentBounds.height(); 2494 final float aspect = ((float) parentHeight) / parentWidth; 2495 if (forcedOrientation == ORIENTATION_LANDSCAPE) { 2496 final int height = (int) (parentWidth / aspect); 2497 final int top = parentBounds.centerY() - height / 2; 2498 outBounds.set(parentBounds.left, top, parentBounds.right, top + height); 2499 } else { 2500 final int width = (int) (parentHeight * aspect); 2501 final int left = parentBounds.centerX() - width / 2; 2502 outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom); 2503 } 2504 } 2505 updateOverrideConfigurationFromLaunchBounds()2506 Rect updateOverrideConfigurationFromLaunchBounds() { 2507 // If the task is controlled by another organized task, do not set override 2508 // configurations and let its parent (organized task) to control it; 2509 final Task rootTask = getRootTask(); 2510 final Rect bounds = rootTask != this && rootTask.isOrganized() ? null : getLaunchBounds(); 2511 setBounds(bounds); 2512 if (bounds != null && !bounds.isEmpty()) { 2513 // TODO: Review if we actually want to do this - we are setting the launch bounds 2514 // directly here. 2515 bounds.set(getRequestedOverrideBounds()); 2516 } 2517 return bounds; 2518 } 2519 2520 /** Updates the task's bounds and override configuration to match what is expected for the 2521 * input stack. */ updateOverrideConfigurationForStack(ActivityStack inStack)2522 void updateOverrideConfigurationForStack(ActivityStack inStack) { 2523 final ActivityStack stack = getStack(); 2524 2525 if (stack != null && stack == inStack) { 2526 return; 2527 } 2528 2529 if (inStack.inFreeformWindowingMode()) { 2530 if (!isResizeable()) { 2531 throw new IllegalArgumentException("Can not position non-resizeable task=" 2532 + this + " in stack=" + inStack); 2533 } 2534 if (!matchParentBounds()) { 2535 return; 2536 } 2537 if (mLastNonFullscreenBounds != null) { 2538 setBounds(mLastNonFullscreenBounds); 2539 } else { 2540 mStackSupervisor.getLaunchParamsController().layoutTask(this, null); 2541 } 2542 } else { 2543 setBounds(inStack.getRequestedOverrideBounds()); 2544 } 2545 } 2546 2547 /** Returns the bounds that should be used to launch this task. */ getLaunchBounds()2548 Rect getLaunchBounds() { 2549 final ActivityStack stack = getStack(); 2550 if (stack == null) { 2551 return null; 2552 } 2553 2554 final int windowingMode = getWindowingMode(); 2555 if (!isActivityTypeStandardOrUndefined() 2556 || windowingMode == WINDOWING_MODE_FULLSCREEN 2557 || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) { 2558 return isResizeable() ? stack.getRequestedOverrideBounds() : null; 2559 } else if (!getWindowConfiguration().persistTaskBounds()) { 2560 return stack.getRequestedOverrideBounds(); 2561 } 2562 return mLastNonFullscreenBounds; 2563 } 2564 setRootProcess(WindowProcessController proc)2565 void setRootProcess(WindowProcessController proc) { 2566 clearRootProcess(); 2567 if (intent != null 2568 && (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) { 2569 mRootProcess = proc; 2570 mRootProcess.addRecentTask(this); 2571 } 2572 } 2573 clearRootProcess()2574 void clearRootProcess() { 2575 if (mRootProcess != null) { 2576 mRootProcess.removeRecentTask(this); 2577 mRootProcess = null; 2578 } 2579 } 2580 2581 @Override getDisplayContent()2582 DisplayContent getDisplayContent() { 2583 // TODO: Why aren't we just using our own display content vs. parent's??? 2584 final ActivityStack stack = getStack(); 2585 return stack != null && stack != this 2586 ? stack.getDisplayContent() : super.getDisplayContent(); 2587 } 2588 getDisplayId()2589 int getDisplayId() { 2590 final DisplayContent dc = getDisplayContent(); 2591 return dc != null ? dc.mDisplayId : INVALID_DISPLAY; 2592 } 2593 2594 // TODO: Migrate callers to getRootTask() getStack()2595 ActivityStack getStack() { 2596 return (ActivityStack) getRootTask(); 2597 } 2598 2599 /** @return Id of root task. */ getRootTaskId()2600 int getRootTaskId() { 2601 return getRootTask().mTaskId; 2602 } 2603 getRootTask()2604 Task getRootTask() { 2605 final WindowContainer parent = getParent(); 2606 if (parent == null) return this; 2607 2608 final Task parentTask = parent.asTask(); 2609 return parentTask == null ? this : parentTask.getRootTask(); 2610 } 2611 2612 // TODO(task-merge): Figure out what's the right thing to do for places that used it. isRootTask()2613 boolean isRootTask() { 2614 return getRootTask() == this; 2615 } 2616 isLeafTask()2617 boolean isLeafTask() { 2618 for (int i = mChildren.size() - 1; i >= 0; --i) { 2619 if (mChildren.get(i).asTask() != null) { 2620 return false; 2621 } 2622 } 2623 return true; 2624 } 2625 getDescendantTaskCount()2626 int getDescendantTaskCount() { 2627 final int[] currentCount = {0}; 2628 final PooledConsumer c = PooledLambda.obtainConsumer((t, count) -> { count[0]++; }, 2629 PooledLambda.__(Task.class), currentCount); 2630 forAllLeafTasks(c, false /* traverseTopToBottom */); 2631 c.recycle(); 2632 return currentCount[0]; 2633 } 2634 2635 /** 2636 * Find next proper focusable stack and make it focused. 2637 * @return The stack that now got the focus, {@code null} if none found. 2638 */ adjustFocusToNextFocusableTask(String reason)2639 ActivityStack adjustFocusToNextFocusableTask(String reason) { 2640 return adjustFocusToNextFocusableTask(reason, false /* allowFocusSelf */, 2641 true /* moveDisplayToTop */); 2642 } 2643 2644 /** Return the next focusable task by looking from the siblings and parent tasks */ getNextFocusableTask(boolean allowFocusSelf)2645 private Task getNextFocusableTask(boolean allowFocusSelf) { 2646 final WindowContainer parent = getParent(); 2647 if (parent == null) { 2648 return null; 2649 } 2650 2651 final Task focusableTask = parent.getTask((task) -> (allowFocusSelf || task != this) 2652 && ((ActivityStack) task).isFocusableAndVisible()); 2653 if (focusableTask == null && parent.asTask() != null) { 2654 return parent.asTask().getNextFocusableTask(allowFocusSelf); 2655 } else { 2656 return focusableTask; 2657 } 2658 } 2659 2660 /** 2661 * Find next proper focusable task and make it focused. 2662 * @param reason The reason of making the adjustment. 2663 * @param allowFocusSelf Is the focus allowed to remain on the same task. 2664 * @param moveDisplayToTop Whether to move display to top while making the task focused. 2665 * @return The root task that now got the focus, {@code null} if none found. 2666 */ adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf, boolean moveDisplayToTop)2667 ActivityStack adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf, 2668 boolean moveDisplayToTop) { 2669 ActivityStack focusableTask = (ActivityStack) getNextFocusableTask(allowFocusSelf); 2670 if (focusableTask == null) { 2671 focusableTask = mRootWindowContainer.getNextFocusableStack((ActivityStack) this, 2672 !allowFocusSelf); 2673 } 2674 if (focusableTask == null) { 2675 return null; 2676 } 2677 2678 final ActivityStack rootTask = (ActivityStack) focusableTask.getRootTask(); 2679 if (!moveDisplayToTop) { 2680 // There may be multiple task layers above this task, so when relocating the task to the 2681 // top, we should move this task and each of its parent task that below display area to 2682 // the top of each layer. 2683 WindowContainer parent = focusableTask.getParent(); 2684 WindowContainer next = focusableTask; 2685 do { 2686 parent.positionChildAt(POSITION_TOP, next, false /* includingParents */); 2687 next = parent; 2688 parent = next.getParent(); 2689 } while (next.asTask() != null && parent != null); 2690 return rootTask; 2691 } 2692 2693 final String myReason = reason + " adjustFocusToNextFocusableStack"; 2694 final ActivityRecord top = focusableTask.topRunningActivity(); 2695 if (focusableTask.isActivityTypeHome() && (top == null || !top.mVisibleRequested)) { 2696 // If we will be focusing on the home stack next and its current top activity isn't 2697 // visible, then use the move the home stack task to top to make the activity visible. 2698 focusableTask.getDisplayArea().moveHomeActivityToTop(myReason); 2699 return rootTask; 2700 } 2701 2702 // Move the entire hierarchy to top with updating global top resumed activity 2703 // and focused application if needed. 2704 focusableTask.moveToFront(myReason); 2705 // Top display focused stack is changed, update top resumed activity if needed. 2706 if (rootTask.mResumedActivity != null) { 2707 mStackSupervisor.updateTopResumedActivityIfNeeded(); 2708 // Set focused app directly because if the next focused activity is already resumed 2709 // (e.g. the next top activity is on a different display), there won't have activity 2710 // state change to update it. 2711 mAtmService.setResumedActivityUncheckLocked(rootTask.mResumedActivity, reason); 2712 } 2713 return rootTask; 2714 } 2715 2716 /** Calculate the minimum possible position for a task that can be shown to the user. 2717 * The minimum position will be above all other tasks that can't be shown. 2718 * @param minPosition The minimum position the caller is suggesting. 2719 * We will start adjusting up from here. 2720 * @param size The size of the current task list. 2721 */ 2722 // TODO: Move user to their own window container. computeMinUserPosition(int minPosition, int size)2723 private int computeMinUserPosition(int minPosition, int size) { 2724 while (minPosition < size) { 2725 final WindowContainer child = mChildren.get(minPosition); 2726 final boolean canShow = child.showToCurrentUser(); 2727 if (canShow) { 2728 break; 2729 } 2730 minPosition++; 2731 } 2732 return minPosition; 2733 } 2734 2735 /** Calculate the maximum possible position for a task that can't be shown to the user. 2736 * The maximum position will be below all other tasks that can be shown. 2737 * @param maxPosition The maximum position the caller is suggesting. 2738 * We will start adjusting down from here. 2739 */ 2740 // TODO: Move user to their own window container. computeMaxUserPosition(int maxPosition)2741 private int computeMaxUserPosition(int maxPosition) { 2742 while (maxPosition > 0) { 2743 final WindowContainer child = mChildren.get(maxPosition); 2744 final boolean canShow = child.showToCurrentUser(); 2745 if (!canShow) { 2746 break; 2747 } 2748 maxPosition--; 2749 } 2750 return maxPosition; 2751 } 2752 getAdjustedChildPosition(WindowContainer wc, int suggestedPosition)2753 private int getAdjustedChildPosition(WindowContainer wc, int suggestedPosition) { 2754 final boolean canShowChild = wc.showToCurrentUser(); 2755 2756 final int size = mChildren.size(); 2757 2758 // Figure-out min/max possible position depending on if child can show for current user. 2759 int minPosition = (canShowChild) ? computeMinUserPosition(0, size) : 0; 2760 int maxPosition = (canShowChild) ? size : computeMaxUserPosition(size - 1); 2761 2762 // Factor in always-on-top children in max possible position. 2763 if (!wc.isAlwaysOnTop()) { 2764 2765 // We want to place all non-always-on-top containers below always-on-top ones. 2766 while (maxPosition > minPosition) { 2767 if (!mChildren.get(maxPosition - 1).isAlwaysOnTop()) break; 2768 --maxPosition; 2769 } 2770 } 2771 2772 // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid. 2773 if (suggestedPosition == POSITION_BOTTOM && minPosition == 0) { 2774 return POSITION_BOTTOM; 2775 } else if (suggestedPosition == POSITION_TOP && maxPosition >= (size - 1)) { 2776 return POSITION_TOP; 2777 } 2778 // Reset position based on minimum/maximum possible positions. 2779 return Math.min(Math.max(suggestedPosition, minPosition), maxPosition); 2780 } 2781 2782 @Override positionChildAt(int position, WindowContainer child, boolean includingParents)2783 void positionChildAt(int position, WindowContainer child, boolean includingParents) { 2784 position = getAdjustedChildPosition(child, position); 2785 super.positionChildAt(position, child, includingParents); 2786 2787 // Log positioning. 2788 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "positionChildAt: child=" + child 2789 + " position=" + position + " parent=" + this); 2790 2791 final int toTop = position >= (mChildren.size() - 1) ? 1 : 0; 2792 final Task task = child.asTask(); 2793 if (task != null) { 2794 EventLogTags.writeWmTaskMoved(task.mTaskId, toTop, position); 2795 } 2796 } 2797 2798 @VisibleForTesting hasWindowsAlive()2799 boolean hasWindowsAlive() { 2800 return getActivity(ActivityRecord::hasWindowsAlive) != null; 2801 } 2802 2803 @VisibleForTesting shouldDeferRemoval()2804 boolean shouldDeferRemoval() { 2805 if (mChildren.isEmpty()) { 2806 // No reason to defer removal of a Task that doesn't have any child. 2807 return false; 2808 } 2809 return hasWindowsAlive() && getStack().isAnimating(TRANSITION | CHILDREN); 2810 } 2811 2812 @Override removeImmediately()2813 void removeImmediately() { 2814 if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId); 2815 EventLogTags.writeWmTaskRemoved(mTaskId, "removeTask"); 2816 2817 if (mDisplayContent != null && mDisplayContent.isSingleTaskInstance()) { 2818 mAtmService.notifySingleTaskDisplayEmpty(mDisplayContent.mDisplayId); 2819 } 2820 2821 // If applicable let the TaskOrganizer know the Task is vanishing. 2822 setTaskOrganizer(null); 2823 2824 super.removeImmediately(); 2825 } 2826 2827 // TODO: Consolidate this with Task.reparent() reparent(ActivityStack stack, int position, boolean moveParents, String reason)2828 void reparent(ActivityStack stack, int position, boolean moveParents, String reason) { 2829 if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId 2830 + " from stack=" + getStack()); 2831 EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask:" + reason); 2832 2833 reparent(stack, position); 2834 2835 stack.positionChildAt(position, this, moveParents); 2836 2837 // If we are moving from the fullscreen stack to the pinned stack then we want to preserve 2838 // our insets so that there will not be a jump in the area covered by system decorations. 2839 // We rely on the pinned animation to later unset this value. 2840 mPreserveNonFloatingState = stack.inPinnedWindowingMode(); 2841 } 2842 setBounds(Rect bounds, boolean forceResize)2843 public int setBounds(Rect bounds, boolean forceResize) { 2844 final int boundsChanged = setBounds(bounds); 2845 2846 if (forceResize && (boundsChanged & BOUNDS_CHANGE_SIZE) != BOUNDS_CHANGE_SIZE) { 2847 onResize(); 2848 return BOUNDS_CHANGE_SIZE | boundsChanged; 2849 } 2850 2851 return boundsChanged; 2852 } 2853 2854 /** Set the task bounds. Passing in null sets the bounds to fullscreen. */ 2855 @Override setBounds(Rect bounds)2856 public int setBounds(Rect bounds) { 2857 int rotation = Surface.ROTATION_0; 2858 final DisplayContent displayContent = getStack() != null 2859 ? getStack().getDisplayContent() : null; 2860 if (displayContent != null) { 2861 rotation = displayContent.getDisplayInfo().rotation; 2862 } 2863 2864 final int boundsChange = super.setBounds(bounds); 2865 mRotation = rotation; 2866 updateSurfacePosition(); 2867 return boundsChange; 2868 } 2869 2870 @Override onDescendantOrientationChanged(IBinder freezeDisplayToken, ConfigurationContainer requestingContainer)2871 public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken, 2872 ConfigurationContainer requestingContainer) { 2873 if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) { 2874 return true; 2875 } 2876 2877 // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill 2878 // it if possible. 2879 if (getParent() != null) { 2880 onConfigurationChanged(getParent().getConfiguration()); 2881 return true; 2882 } 2883 return false; 2884 } 2885 resize(boolean relayout, boolean forced)2886 void resize(boolean relayout, boolean forced) { 2887 if (setBounds(getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE && relayout) { 2888 getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); 2889 } 2890 } 2891 2892 @Override onDisplayChanged(DisplayContent dc)2893 void onDisplayChanged(DisplayContent dc) { 2894 final boolean isRootTask = isRootTask(); 2895 if (!isRootTask) { 2896 adjustBoundsForDisplayChangeIfNeeded(dc); 2897 } 2898 super.onDisplayChanged(dc); 2899 if (isLeafTask()) { 2900 final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY; 2901 mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged( 2902 mTaskId, displayId); 2903 } 2904 } 2905 isResizeable(boolean checkSupportsPip)2906 boolean isResizeable(boolean checkSupportsPip) { 2907 return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode) 2908 || (checkSupportsPip && mSupportsPictureInPicture)); 2909 } 2910 isResizeable()2911 boolean isResizeable() { 2912 return isResizeable(true /* checkSupportsPip */); 2913 } 2914 2915 /** 2916 * Tests if the orientation should be preserved upon user interactive resizig operations. 2917 2918 * @return true if orientation should not get changed upon resizing operation. 2919 */ preserveOrientationOnResize()2920 boolean preserveOrientationOnResize() { 2921 return mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY 2922 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY 2923 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; 2924 } 2925 cropWindowsToStackBounds()2926 boolean cropWindowsToStackBounds() { 2927 // Don't crop HOME/RECENTS windows to stack bounds. This is because in split-screen 2928 // they extend past their stack and sysui uses the stack surface to control cropping. 2929 // TODO(b/158242495): get rid of this when drag/drop can use surface bounds. 2930 if (isActivityTypeHome() || isActivityTypeRecents()) { 2931 // Make sure this is the top-most non-organizer root task (if not top-most, it means 2932 // another translucent task could be above this, so this needs to stay cropped. 2933 final Task rootTask = getRootTask(); 2934 final Task topNonOrgTask = 2935 rootTask.mCreatedByOrganizer ? rootTask.getTopMostTask() : rootTask; 2936 if (this == topNonOrgTask || isDescendantOf(topNonOrgTask)) { 2937 return false; 2938 } 2939 } 2940 return isResizeable(); 2941 } 2942 2943 /** 2944 * Prepares the task bounds to be frozen with the current size. See 2945 * {@link ActivityRecord#freezeBounds}. 2946 */ prepareFreezingBounds()2947 void prepareFreezingBounds() { 2948 mPreparedFrozenBounds.set(getBounds()); 2949 mPreparedFrozenMergedConfig.setTo(getConfiguration()); 2950 } 2951 2952 @Override getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, Rect outSurfaceInsets)2953 void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, 2954 Rect outSurfaceInsets) { 2955 final WindowState windowState = getTopVisibleAppMainWindow(); 2956 if (windowState != null) { 2957 windowState.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); 2958 } else { 2959 super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); 2960 } 2961 } 2962 2963 /** 2964 * Calculate the maximum visible area of this task. If the task has only one app, 2965 * the result will be visible frame of that app. If the task has more than one apps, 2966 * we search from top down if the next app got different visible area. 2967 * 2968 * This effort is to handle the case where some task (eg. GMail composer) might pop up 2969 * a dialog that's different in size from the activity below, in which case we should 2970 * be dimming the entire task area behind the dialog. 2971 * 2972 * @param out Rect containing the max visible bounds. 2973 * @return true if the task has some visible app windows; false otherwise. 2974 */ getMaxVisibleBounds(ActivityRecord token, Rect out, boolean[] foundTop)2975 private static void getMaxVisibleBounds(ActivityRecord token, Rect out, boolean[] foundTop) { 2976 // skip hidden (or about to hide) apps 2977 if (token.mIsExiting || !token.isClientVisible() || !token.mVisibleRequested) { 2978 return; 2979 } 2980 final WindowState win = token.findMainWindow(); 2981 if (win == null) { 2982 return; 2983 } 2984 if (!foundTop[0]) { 2985 foundTop[0] = true; 2986 out.setEmpty(); 2987 } 2988 2989 win.getMaxVisibleBounds(out); 2990 } 2991 2992 /** Bounds of the task to be used for dimming, as well as touch related tests. */ getDimBounds(Rect out)2993 void getDimBounds(Rect out) { 2994 final DisplayContent displayContent = getStack().getDisplayContent(); 2995 // It doesn't matter if we in particular are part of the resize, since we couldn't have 2996 // a DimLayer anyway if we weren't visible. 2997 final boolean dockedResizing = displayContent != null 2998 && displayContent.mDividerControllerLocked.isResizing(); 2999 if (inFreeformWindowingMode()) { 3000 boolean[] foundTop = { false }; 3001 final PooledConsumer c = PooledLambda.obtainConsumer(Task::getMaxVisibleBounds, 3002 PooledLambda.__(ActivityRecord.class), out, foundTop); 3003 forAllActivities(c); 3004 c.recycle(); 3005 if (foundTop[0]) { 3006 return; 3007 } 3008 } 3009 3010 if (!matchParentBounds()) { 3011 // When minimizing the docked stack when going home, we don't adjust the task bounds 3012 // so we need to intersect the task bounds with the stack bounds here. 3013 // 3014 // If we are Docked Resizing with snap points, the task bounds could be smaller than the 3015 // stack bounds and so we don't even want to use them. Even if the app should not be 3016 // resized the Dim should keep up with the divider. 3017 if (dockedResizing) { 3018 getStack().getBounds(out); 3019 } else { 3020 getStack().getBounds(mTmpRect); 3021 mTmpRect.intersect(getBounds()); 3022 out.set(mTmpRect); 3023 } 3024 } else { 3025 out.set(getBounds()); 3026 } 3027 return; 3028 } 3029 setDragResizing(boolean dragResizing, int dragResizeMode)3030 void setDragResizing(boolean dragResizing, int dragResizeMode) { 3031 if (mDragResizing != dragResizing) { 3032 // No need to check if the mode is allowed if it's leaving dragResize 3033 if (dragResizing && !DragResizeMode.isModeAllowedForStack(getStack(), dragResizeMode)) { 3034 throw new IllegalArgumentException("Drag resize mode not allow for stack stackId=" 3035 + getRootTaskId() + " dragResizeMode=" + dragResizeMode); 3036 } 3037 mDragResizing = dragResizing; 3038 mDragResizeMode = dragResizeMode; 3039 resetDragResizingChangeReported(); 3040 } 3041 } 3042 isDragResizing()3043 boolean isDragResizing() { 3044 return mDragResizing; 3045 } 3046 getDragResizeMode()3047 int getDragResizeMode() { 3048 return mDragResizeMode; 3049 } 3050 adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent)3051 void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) { 3052 if (displayContent == null) { 3053 return; 3054 } 3055 if (matchParentBounds()) { 3056 // TODO: Yeah...not sure if this works with WindowConfiguration, but shouldn't be a 3057 // problem once we move mBounds into WindowConfiguration. 3058 setBounds(null); 3059 return; 3060 } 3061 final int displayId = displayContent.getDisplayId(); 3062 final int newRotation = displayContent.getDisplayInfo().rotation; 3063 if (displayId != mLastRotationDisplayId) { 3064 // This task is on a display that it wasn't on. There is no point to keep the relative 3065 // position if display rotations for old and new displays are different. Just keep these 3066 // values. 3067 mLastRotationDisplayId = displayId; 3068 mRotation = newRotation; 3069 return; 3070 } 3071 3072 if (mRotation == newRotation) { 3073 // Rotation didn't change. We don't need to adjust the bounds to keep the relative 3074 // position. 3075 return; 3076 } 3077 3078 // Device rotation changed. 3079 // - We don't want the task to move around on the screen when this happens, so update the 3080 // task bounds so it stays in the same place. 3081 // - Rotate the bounds and notify activity manager if the task can be resized independently 3082 // from its stack. The stack will take care of task rotation for the other case. 3083 mTmpRect2.set(getBounds()); 3084 3085 if (!getWindowConfiguration().canResizeTask()) { 3086 setBounds(mTmpRect2); 3087 return; 3088 } 3089 3090 displayContent.rotateBounds(mRotation, newRotation, mTmpRect2); 3091 if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) { 3092 mAtmService.resizeTask(mTaskId, getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION); 3093 } 3094 } 3095 3096 /** Cancels any running app transitions associated with the task. */ cancelTaskWindowTransition()3097 void cancelTaskWindowTransition() { 3098 for (int i = mChildren.size() - 1; i >= 0; --i) { 3099 mChildren.get(i).cancelAnimation(); 3100 } 3101 } 3102 showForAllUsers()3103 boolean showForAllUsers() { 3104 if (mChildren.isEmpty()) return false; 3105 final ActivityRecord r = getTopNonFinishingActivity(); 3106 return r != null && r.mShowForAllUsers; 3107 } 3108 3109 @Override showToCurrentUser()3110 boolean showToCurrentUser() { 3111 return mForceShowForAllUsers || showForAllUsers() 3112 || mWmService.isCurrentProfile(getTopMostTask().mUserId); 3113 } 3114 setForceShowForAllUsers(boolean forceShowForAllUsers)3115 void setForceShowForAllUsers(boolean forceShowForAllUsers) { 3116 mForceShowForAllUsers = forceShowForAllUsers; 3117 } 3118 3119 @Override isAttached()3120 public boolean isAttached() { 3121 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 3122 return taskDisplayArea != null && !taskDisplayArea.isRemoved(); 3123 } 3124 3125 @Override 3126 @Nullable getDisplayArea()3127 TaskDisplayArea getDisplayArea() { 3128 return (TaskDisplayArea) super.getDisplayArea(); 3129 } 3130 3131 /** 3132 * When we are in a floating stack (Freeform, Pinned, ...) we calculate 3133 * insets differently. However if we are animating to the fullscreen stack 3134 * we need to begin calculating insets as if we were fullscreen, otherwise 3135 * we will have a jump at the end. 3136 */ isFloating()3137 boolean isFloating() { 3138 return getWindowConfiguration().tasksAreFloating() && !mPreserveNonFloatingState; 3139 } 3140 3141 /** 3142 * Returns true if the stack is translucent and can have other contents visible behind it if 3143 * needed. A stack is considered translucent if it don't contain a visible or 3144 * starting (about to be visible) activity that is fullscreen (opaque). 3145 * @param starting The currently starting activity or null if there is none. 3146 */ 3147 @VisibleForTesting isTranslucent(ActivityRecord starting)3148 boolean isTranslucent(ActivityRecord starting) { 3149 if (!isAttached() || isForceHidden()) { 3150 return true; 3151 } 3152 final PooledPredicate p = PooledLambda.obtainPredicate(Task::isOpaqueActivity, 3153 PooledLambda.__(ActivityRecord.class), starting); 3154 final ActivityRecord opaque = getActivity(p); 3155 p.recycle(); 3156 return opaque == null; 3157 } 3158 isOpaqueActivity(ActivityRecord r, ActivityRecord starting)3159 private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) { 3160 if (r.finishing) { 3161 // We don't factor in finishing activities when determining translucency since 3162 // they will be gone soon. 3163 return false; 3164 } 3165 3166 if (!r.visibleIgnoringKeyguard && r != starting) { 3167 // Also ignore invisible activities that are not the currently starting 3168 // activity (about to be visible). 3169 return false; 3170 } 3171 3172 if (r.occludesParent() || r.hasWallpaper) { 3173 // Stack isn't translucent if it has at least one fullscreen activity 3174 // that is visible. 3175 return true; 3176 } 3177 return false; 3178 } 3179 3180 @Override makeAnimationLeash()3181 public SurfaceControl.Builder makeAnimationLeash() { 3182 return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId); 3183 } 3184 3185 @Override getAnimationLeashParent()3186 public SurfaceControl getAnimationLeashParent() { 3187 if (WindowManagerService.sHierarchicalAnimations) { 3188 return super.getAnimationLeashParent(); 3189 } 3190 // Currently, only the recents animation will create animation leashes for tasks. In this 3191 // case, reparent the task to the home animation layer while it is being animated to allow 3192 // the home activity to reorder the app windows relative to its own. 3193 return getAppAnimationLayer(ANIMATION_LAYER_HOME); 3194 } 3195 3196 @Override getAnimationBounds(int appStackClipMode)3197 Rect getAnimationBounds(int appStackClipMode) { 3198 // TODO(b/131661052): we should remove appStackClipMode with hierarchical animations. 3199 if (appStackClipMode == STACK_CLIP_BEFORE_ANIM && getStack() != null) { 3200 // Using the stack bounds here effectively applies the clipping before animation. 3201 return getStack().getBounds(); 3202 } 3203 return super.getAnimationBounds(appStackClipMode); 3204 } 3205 shouldAnimate()3206 boolean shouldAnimate() { 3207 /** 3208 * Animations are handled by the TaskOrganizer implementation. 3209 */ 3210 if (isOrganized()) { 3211 return false; 3212 } 3213 // Don't animate while the task runs recents animation but only if we are in the mode 3214 // where we cancel with deferred screenshot, which means that the controller has 3215 // transformed the task. 3216 final RecentsAnimationController controller = mWmService.getRecentsAnimationController(); 3217 if (controller != null && controller.isAnimatingTask(this) 3218 && controller.shouldDeferCancelUntilNextTransition()) { 3219 return false; 3220 } 3221 return true; 3222 } 3223 3224 @Override setInitialSurfaceControlProperties(SurfaceControl.Builder b)3225 void setInitialSurfaceControlProperties(SurfaceControl.Builder b) { 3226 b.setEffectLayer().setMetadata(METADATA_TASK_ID, mTaskId); 3227 super.setInitialSurfaceControlProperties(b); 3228 } 3229 isTaskAnimating()3230 boolean isTaskAnimating() { 3231 final RecentsAnimationController recentsAnim = mWmService.getRecentsAnimationController(); 3232 if (recentsAnim != null) { 3233 if (recentsAnim.isAnimatingTask(this)) { 3234 return true; 3235 } 3236 } 3237 return forAllTasks((t) -> { return t != this && t.isTaskAnimating(); }); 3238 } 3239 3240 @Override createRemoteAnimationTarget( RemoteAnimationController.RemoteAnimationRecord record)3241 RemoteAnimationTarget createRemoteAnimationTarget( 3242 RemoteAnimationController.RemoteAnimationRecord record) { 3243 final ActivityRecord activity = getTopMostActivity(); 3244 return activity != null ? activity.createRemoteAnimationTarget(record) : null; 3245 } 3246 3247 @Override canCreateRemoteAnimationTarget()3248 boolean canCreateRemoteAnimationTarget() { 3249 return true; 3250 } 3251 getTopVisibleAppMainWindow()3252 WindowState getTopVisibleAppMainWindow() { 3253 final ActivityRecord activity = getTopVisibleActivity(); 3254 return activity != null ? activity.findMainWindow() : null; 3255 } 3256 topRunningActivity()3257 ActivityRecord topRunningActivity() { 3258 return topRunningActivity(false /* focusableOnly */); 3259 } 3260 topRunningActivity(boolean focusableOnly)3261 ActivityRecord topRunningActivity(boolean focusableOnly) { 3262 // Split into 2 to avoid object creation due to variable capture. 3263 if (focusableOnly) { 3264 return getActivity((r) -> r.canBeTopRunning() && r.isFocusable()); 3265 } else { 3266 return getActivity(ActivityRecord::canBeTopRunning); 3267 } 3268 } 3269 topRunningNonDelayedActivityLocked(ActivityRecord notTop)3270 ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) { 3271 final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunningNonDelayed 3272 , PooledLambda.__(ActivityRecord.class), notTop); 3273 final ActivityRecord r = getActivity(p); 3274 p.recycle(); 3275 return r; 3276 } 3277 isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop)3278 private static boolean isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop) { 3279 return !r.delayedResume && r != notTop && r.canBeTopRunning(); 3280 } 3281 3282 /** 3283 * This is a simplified version of topRunningActivity that provides a number of 3284 * optional skip-over modes. It is intended for use with the ActivityController hook only. 3285 * 3286 * @param token If non-null, any history records matching this token will be skipped. 3287 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID. 3288 * 3289 * @return Returns the HistoryRecord of the next activity on the stack. 3290 */ topRunningActivity(IBinder token, int taskId)3291 ActivityRecord topRunningActivity(IBinder token, int taskId) { 3292 final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunning, 3293 PooledLambda.__(ActivityRecord.class), taskId, token); 3294 final ActivityRecord r = getActivity(p); 3295 p.recycle(); 3296 return r; 3297 } 3298 isTopRunning(ActivityRecord r, int taskId, IBinder notTop)3299 private static boolean isTopRunning(ActivityRecord r, int taskId, IBinder notTop) { 3300 return r.getTask().mTaskId != taskId && r.appToken != notTop && r.canBeTopRunning(); 3301 } 3302 getTopFullscreenActivity()3303 ActivityRecord getTopFullscreenActivity() { 3304 return getActivity((r) -> { 3305 final WindowState win = r.findMainWindow(); 3306 return (win != null && win.mAttrs.isFullscreen()); 3307 }); 3308 } 3309 3310 ActivityRecord getTopVisibleActivity() { 3311 return getActivity((r) -> { 3312 // skip hidden (or about to hide) apps 3313 return !r.mIsExiting && r.isClientVisible() && r.mVisibleRequested; 3314 }); 3315 } 3316 3317 boolean isTopActivityFocusable() { 3318 final ActivityRecord r = topRunningActivity(); 3319 return r != null ? r.isFocusable() 3320 : (isFocusable() && getWindowConfiguration().canReceiveKeys()); 3321 } 3322 3323 boolean isFocusableAndVisible() { 3324 return isTopActivityFocusable() && shouldBeVisible(null /* starting */); 3325 } 3326 3327 void positionChildAtTop(ActivityRecord child) { 3328 positionChildAt(child, POSITION_TOP); 3329 } 3330 3331 void positionChildAt(ActivityRecord child, int position) { 3332 if (child == null) { 3333 Slog.w(TAG_WM, 3334 "Attempted to position of non-existing app"); 3335 return; 3336 } 3337 3338 positionChildAt(position, child, false /* includeParents */); 3339 } 3340 3341 void forceWindowsScaleable(boolean force) { 3342 mWmService.openSurfaceTransaction(); 3343 try { 3344 for (int i = mChildren.size() - 1; i >= 0; i--) { 3345 mChildren.get(i).forceWindowsScaleableInTransaction(force); 3346 } 3347 } finally { 3348 mWmService.closeSurfaceTransaction("forceWindowsScaleable"); 3349 } 3350 } 3351 3352 void setTaskDescription(TaskDescription taskDescription) { 3353 mTaskDescription = taskDescription; 3354 } 3355 3356 void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) { 3357 mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged( 3358 mTaskId, snapshot); 3359 } 3360 3361 TaskDescription getTaskDescription() { 3362 return mTaskDescription; 3363 } 3364 3365 @Override 3366 int getOrientation(int candidate) { 3367 return canSpecifyOrientation() ? super.getOrientation(candidate) : SCREEN_ORIENTATION_UNSET; 3368 } 3369 3370 private boolean canSpecifyOrientation() { 3371 final int windowingMode = getWindowingMode(); 3372 final int activityType = getActivityType(); 3373 return windowingMode == WINDOWING_MODE_FULLSCREEN 3374 || activityType == ACTIVITY_TYPE_HOME 3375 || activityType == ACTIVITY_TYPE_RECENTS 3376 || activityType == ACTIVITY_TYPE_ASSISTANT; 3377 } 3378 3379 @Override 3380 boolean fillsParent() { 3381 return matchParentBounds(); 3382 } 3383 3384 @Override 3385 void forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom) { 3386 final int count = mChildren.size(); 3387 boolean isLeafTask = true; 3388 if (traverseTopToBottom) { 3389 for (int i = count - 1; i >= 0; --i) { 3390 final Task child = mChildren.get(i).asTask(); 3391 if (child != null) { 3392 isLeafTask = false; 3393 child.forAllLeafTasks(callback, traverseTopToBottom); 3394 } 3395 } 3396 } else { 3397 for (int i = 0; i < count; i++) { 3398 final Task child = mChildren.get(i).asTask(); 3399 if (child != null) { 3400 isLeafTask = false; 3401 child.forAllLeafTasks(callback, traverseTopToBottom); 3402 } 3403 } 3404 } 3405 if (isLeafTask) callback.accept(this); 3406 } 3407 3408 @Override 3409 void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom) { 3410 super.forAllTasks(callback, traverseTopToBottom); 3411 callback.accept(this); 3412 } 3413 3414 @Override 3415 boolean forAllTasks(Function<Task, Boolean> callback) { 3416 if (super.forAllTasks(callback)) return true; 3417 return callback.apply(this); 3418 } 3419 3420 @Override 3421 boolean forAllLeafTasks(Function<Task, Boolean> callback) { 3422 boolean isLeafTask = true; 3423 for (int i = mChildren.size() - 1; i >= 0; --i) { 3424 final Task child = mChildren.get(i).asTask(); 3425 if (child != null) { 3426 isLeafTask = false; 3427 if (child.forAllLeafTasks(callback)) { 3428 return true; 3429 } 3430 } 3431 } 3432 if (isLeafTask) { 3433 return callback.apply(this); 3434 } 3435 return false; 3436 } 3437 3438 @Override 3439 Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) { 3440 final Task t = super.getTask(callback, traverseTopToBottom); 3441 if (t != null) return t; 3442 return callback.test(this) ? this : null; 3443 } 3444 3445 /** 3446 * @param canAffectSystemUiFlags If false, all windows in this task can not affect SystemUI 3447 * flags. See {@link WindowState#canAffectSystemUiFlags()}. 3448 */ 3449 void setCanAffectSystemUiFlags(boolean canAffectSystemUiFlags) { 3450 mCanAffectSystemUiFlags = canAffectSystemUiFlags; 3451 } 3452 3453 /** 3454 * @see #setCanAffectSystemUiFlags 3455 */ 3456 boolean canAffectSystemUiFlags() { 3457 return mCanAffectSystemUiFlags; 3458 } 3459 3460 void dontAnimateDimExit() { 3461 mDimmer.dontAnimateExit(); 3462 } 3463 3464 String getName() { 3465 return "Task=" + mTaskId; 3466 } 3467 3468 void clearPreserveNonFloatingState() { 3469 mPreserveNonFloatingState = false; 3470 } 3471 3472 @Override 3473 Dimmer getDimmer() { 3474 // If the window is in multi-window mode, we want to dim at the Task level to ensure the dim 3475 // bounds match the area the app lives in 3476 if (inMultiWindowMode()) { 3477 return mDimmer; 3478 } 3479 3480 // If we're not at the root task level, we want to keep traversing through the parents to 3481 // find the root. 3482 // Once at the root task level, we want to check {@link #isTranslucent(ActivityRecord)}. 3483 // If true, we want to get the Dimmer from the level above since we don't want to animate 3484 // the dim with the Task. 3485 if (!isRootTask() || isTranslucent(null)) { 3486 return super.getDimmer(); 3487 } 3488 3489 return mDimmer; 3490 } 3491 3492 @Override 3493 void prepareSurfaces() { 3494 mDimmer.resetDimStates(); 3495 super.prepareSurfaces(); 3496 getDimBounds(mTmpDimBoundsRect); 3497 3498 // Bounds need to be relative, as the dim layer is a child. 3499 if (inFreeformWindowingMode()) { 3500 getBounds(mTmpRect); 3501 mTmpDimBoundsRect.offsetTo(mTmpDimBoundsRect.left - mTmpRect.left, 3502 mTmpDimBoundsRect.top - mTmpRect.top); 3503 } else { 3504 mTmpDimBoundsRect.offsetTo(0, 0); 3505 } 3506 3507 updateShadowsRadius(isFocused(), getSyncTransaction()); 3508 3509 if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) { 3510 scheduleAnimation(); 3511 } 3512 } 3513 3514 @Override 3515 protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter, 3516 int transit, boolean isVoiceInteraction, 3517 @Nullable ArrayList<WindowContainer> sources) { 3518 final RecentsAnimationController control = mWmService.getRecentsAnimationController(); 3519 if (control != null) { 3520 // We let the transition to be controlled by RecentsAnimation, and callback task's 3521 // RemoteAnimationTarget for remote runner to animate. 3522 if (enter) { 3523 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, 3524 "applyAnimationUnchecked, control: %s, task: %s, transit: %s", 3525 control, asTask(), AppTransition.appTransitionToString(transit)); 3526 control.addTaskToTargets(this, (type, anim) -> { 3527 for (int i = 0; i < sources.size(); ++i) { 3528 sources.get(i).onAnimationFinished(type, anim); 3529 } 3530 }); 3531 } 3532 } else { 3533 super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources); 3534 } 3535 } 3536 3537 @Override 3538 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 3539 super.dump(pw, prefix, dumpAll); 3540 pw.println(prefix + "bounds=" + getBounds().toShortString()); 3541 final String doublePrefix = prefix + " "; 3542 for (int i = mChildren.size() - 1; i >= 0; i--) { 3543 final WindowContainer<?> child = mChildren.get(i); 3544 pw.println(prefix + "* " + child); 3545 // Only dump non-activity because full activity info is already printed by 3546 // RootWindowContainer#dumpActivities. 3547 if (child.asActivityRecord() == null) { 3548 child.dump(pw, doublePrefix, dumpAll); 3549 } 3550 } 3551 } 3552 3553 3554 /** 3555 * Fills in a {@link TaskInfo} with information from this task. Note that the base intent in the 3556 * task info will not include any extras or clip data. 3557 */ 3558 void fillTaskInfo(TaskInfo info) { 3559 fillTaskInfo(info, true /* stripExtras */); 3560 } 3561 3562 /** 3563 * Fills in a {@link TaskInfo} with information from this task. 3564 */ 3565 void fillTaskInfo(TaskInfo info, boolean stripExtras) { 3566 getNumRunningActivities(mReuseActivitiesReport); 3567 info.userId = mUserId; 3568 info.stackId = getRootTaskId(); 3569 info.taskId = mTaskId; 3570 info.displayId = getDisplayId(); 3571 info.isRunning = getTopNonFinishingActivity() != null; 3572 final Intent baseIntent = getBaseIntent(); 3573 // Make a copy of base intent because this is like a snapshot info. 3574 // Besides, {@link RecentTasks#getRecentTasksImpl} may modify it. 3575 final int baseIntentFlags = baseIntent == null ? 0 : baseIntent.getFlags(); 3576 info.baseIntent = baseIntent == null 3577 ? new Intent() 3578 : stripExtras ? baseIntent.cloneFilter() : new Intent(baseIntent); 3579 info.baseIntent.setFlags(baseIntentFlags); 3580 info.baseActivity = mReuseActivitiesReport.base != null 3581 ? mReuseActivitiesReport.base.intent.getComponent() 3582 : null; 3583 info.topActivity = mReuseActivitiesReport.top != null 3584 ? mReuseActivitiesReport.top.mActivityComponent 3585 : null; 3586 info.origActivity = origActivity; 3587 info.realActivity = realActivity; 3588 info.numActivities = mReuseActivitiesReport.numActivities; 3589 info.lastActiveTime = lastActiveTime; 3590 info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription()); 3591 info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode(); 3592 info.configuration.setTo(getConfiguration()); 3593 info.token = mRemoteToken.toWindowContainerToken(); 3594 3595 //TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child 3596 // order changes. 3597 final Task top = getTopMostTask(); 3598 info.resizeMode = top != null ? top.mResizeMode : mResizeMode; 3599 info.topActivityType = top.getActivityType(); 3600 info.isResizeable = isResizeable(); 3601 3602 ActivityRecord rootActivity = top.getRootActivity(); 3603 if (rootActivity == null || rootActivity.pictureInPictureArgs.empty()) { 3604 info.pictureInPictureParams = null; 3605 } else { 3606 info.pictureInPictureParams = rootActivity.pictureInPictureArgs; 3607 } 3608 info.topActivityInfo = mReuseActivitiesReport.top != null 3609 ? mReuseActivitiesReport.top.info 3610 : null; 3611 } 3612 3613 /** 3614 * Returns a {@link TaskInfo} with information from this task. 3615 */ 3616 ActivityManager.RunningTaskInfo getTaskInfo() { 3617 ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo(); 3618 fillTaskInfo(info); 3619 return info; 3620 } 3621 3622 boolean isTaskId(int taskId) { 3623 return mTaskId == taskId; 3624 } 3625 3626 @Override 3627 Task asTask() { 3628 // I'm a task! 3629 return this; 3630 } 3631 3632 /** 3633 * Returns true if the task should be visible. 3634 * 3635 * @param starting The currently starting activity or null if there is none. 3636 */ 3637 boolean shouldBeVisible(ActivityRecord starting) { 3638 return getVisibility(starting) != STACK_VISIBILITY_INVISIBLE; 3639 } 3640 3641 /** 3642 * Returns true if the task should be visible. 3643 * 3644 * @param starting The currently starting activity or null if there is none. 3645 */ 3646 @ActivityStack.StackVisibility 3647 int getVisibility(ActivityRecord starting) { 3648 if (!isAttached() || isForceHidden()) { 3649 return STACK_VISIBILITY_INVISIBLE; 3650 } 3651 3652 boolean gotSplitScreenStack = false; 3653 boolean gotOpaqueSplitScreenPrimary = false; 3654 boolean gotOpaqueSplitScreenSecondary = false; 3655 boolean gotTranslucentFullscreen = false; 3656 boolean gotTranslucentSplitScreenPrimary = false; 3657 boolean gotTranslucentSplitScreenSecondary = false; 3658 boolean shouldBeVisible = true; 3659 3660 // This stack is only considered visible if all its parent stacks are considered visible, 3661 // so check the visibility of all ancestor stacks first. 3662 final WindowContainer parent = getParent(); 3663 if (parent.asTask() != null) { 3664 final int parentVisibility = parent.asTask().getVisibility(starting); 3665 if (parentVisibility == STACK_VISIBILITY_INVISIBLE) { 3666 // Can't be visible if parent isn't visible 3667 return STACK_VISIBILITY_INVISIBLE; 3668 } else if (parentVisibility == STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) { 3669 // Parent is behind a translucent container so the highest visibility this container 3670 // can get is that. 3671 gotTranslucentFullscreen = true; 3672 } 3673 } 3674 3675 final int windowingMode = getWindowingMode(); 3676 final boolean isAssistantType = isActivityTypeAssistant(); 3677 for (int i = parent.getChildCount() - 1; i >= 0; --i) { 3678 final WindowContainer wc = parent.getChildAt(i); 3679 final Task other = wc.asTask(); 3680 if (other == null) continue; 3681 3682 final boolean hasRunningActivities = other.topRunningActivity() != null; 3683 if (other == this) { 3684 // Should be visible if there is no other stack occluding it, unless it doesn't 3685 // have any running activities, not starting one and not home stack. 3686 shouldBeVisible = hasRunningActivities || isInTask(starting) != null 3687 || isActivityTypeHome(); 3688 break; 3689 } 3690 3691 if (!hasRunningActivities) { 3692 continue; 3693 } 3694 3695 final int otherWindowingMode = other.getWindowingMode(); 3696 3697 if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) { 3698 if (other.isTranslucent(starting)) { 3699 // Can be visible behind a translucent fullscreen stack. 3700 gotTranslucentFullscreen = true; 3701 continue; 3702 } 3703 return STACK_VISIBILITY_INVISIBLE; 3704 } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY 3705 && !gotOpaqueSplitScreenPrimary) { 3706 gotSplitScreenStack = true; 3707 gotTranslucentSplitScreenPrimary = other.isTranslucent(starting); 3708 gotOpaqueSplitScreenPrimary = !gotTranslucentSplitScreenPrimary; 3709 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY 3710 && gotOpaqueSplitScreenPrimary) { 3711 // Can not be visible behind another opaque stack in split-screen-primary mode. 3712 return STACK_VISIBILITY_INVISIBLE; 3713 } 3714 } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY 3715 && !gotOpaqueSplitScreenSecondary) { 3716 gotSplitScreenStack = true; 3717 gotTranslucentSplitScreenSecondary = other.isTranslucent(starting); 3718 gotOpaqueSplitScreenSecondary = !gotTranslucentSplitScreenSecondary; 3719 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY 3720 && gotOpaqueSplitScreenSecondary) { 3721 // Can not be visible behind another opaque stack in split-screen-secondary mode. 3722 return STACK_VISIBILITY_INVISIBLE; 3723 } 3724 } 3725 if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) { 3726 // Can not be visible if we are in split-screen windowing mode and both halves of 3727 // the screen are opaque. 3728 return STACK_VISIBILITY_INVISIBLE; 3729 } 3730 if (isAssistantType && gotSplitScreenStack) { 3731 // Assistant stack can't be visible behind split-screen. In addition to this not 3732 // making sense, it also works around an issue here we boost the z-order of the 3733 // assistant window surfaces in window manager whenever it is visible. 3734 return STACK_VISIBILITY_INVISIBLE; 3735 } 3736 } 3737 3738 if (!shouldBeVisible) { 3739 return STACK_VISIBILITY_INVISIBLE; 3740 } 3741 3742 // Handle cases when there can be a translucent split-screen stack on top. 3743 switch (windowingMode) { 3744 case WINDOWING_MODE_FULLSCREEN: 3745 if (gotTranslucentSplitScreenPrimary || gotTranslucentSplitScreenSecondary) { 3746 // At least one of the split-screen stacks that covers this one is translucent. 3747 return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; 3748 } 3749 break; 3750 case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: 3751 if (gotTranslucentSplitScreenPrimary) { 3752 // Covered by translucent primary split-screen on top. 3753 return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; 3754 } 3755 break; 3756 case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: 3757 if (gotTranslucentSplitScreenSecondary) { 3758 // Covered by translucent secondary split-screen on top. 3759 return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; 3760 } 3761 break; 3762 } 3763 3764 // Lastly - check if there is a translucent fullscreen stack on top. 3765 return gotTranslucentFullscreen ? STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT 3766 : STACK_VISIBILITY_VISIBLE; 3767 } 3768 3769 ActivityRecord isInTask(ActivityRecord r) { 3770 if (r == null) { 3771 return null; 3772 } 3773 if (r.isDescendantOf(this)) { 3774 return r; 3775 } 3776 return null; 3777 } 3778 3779 void dump(PrintWriter pw, String prefix) { 3780 pw.print(prefix); pw.print("userId="); pw.print(mUserId); 3781 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid); 3782 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid); 3783 pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete); 3784 pw.print(" mCallingPackage="); pw.print(mCallingPackage); 3785 pw.print(" mCallingFeatureId="); pw.println(mCallingFeatureId); 3786 if (affinity != null || rootAffinity != null) { 3787 pw.print(prefix); pw.print("affinity="); pw.print(affinity); 3788 if (affinity == null || !affinity.equals(rootAffinity)) { 3789 pw.print(" root="); pw.println(rootAffinity); 3790 } else { 3791 pw.println(); 3792 } 3793 } 3794 if (mWindowLayoutAffinity != null) { 3795 pw.print(prefix); pw.print("windowLayoutAffinity="); pw.println(mWindowLayoutAffinity); 3796 } 3797 if (voiceSession != null || voiceInteractor != null) { 3798 pw.print(prefix); pw.print("VOICE: session=0x"); 3799 pw.print(Integer.toHexString(System.identityHashCode(voiceSession))); 3800 pw.print(" interactor=0x"); 3801 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor))); 3802 } 3803 if (intent != null) { 3804 StringBuilder sb = new StringBuilder(128); 3805 sb.append(prefix); sb.append("intent={"); 3806 intent.toShortString(sb, false, true, false, false); 3807 sb.append('}'); 3808 pw.println(sb.toString()); 3809 } 3810 if (affinityIntent != null) { 3811 StringBuilder sb = new StringBuilder(128); 3812 sb.append(prefix); sb.append("affinityIntent={"); 3813 affinityIntent.toShortString(sb, false, true, false, false); 3814 sb.append('}'); 3815 pw.println(sb.toString()); 3816 } 3817 if (origActivity != null) { 3818 pw.print(prefix); pw.print("origActivity="); 3819 pw.println(origActivity.flattenToShortString()); 3820 } 3821 if (realActivity != null) { 3822 pw.print(prefix); pw.print("mActivityComponent="); 3823 pw.println(realActivity.flattenToShortString()); 3824 } 3825 if (autoRemoveRecents || isPersistable || !isActivityTypeStandard()) { 3826 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents); 3827 pw.print(" isPersistable="); pw.print(isPersistable); 3828 pw.print(" activityType="); pw.println(getActivityType()); 3829 } 3830 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask 3831 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) { 3832 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset); 3833 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity); 3834 pw.print(" mReuseTask="); pw.print(mReuseTask); 3835 pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString()); 3836 } 3837 if (mAffiliatedTaskId != mTaskId || mPrevAffiliateTaskId != INVALID_TASK_ID 3838 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID 3839 || mNextAffiliate != null) { 3840 pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId); 3841 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId); 3842 pw.print(" ("); 3843 if (mPrevAffiliate == null) { 3844 pw.print("null"); 3845 } else { 3846 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate))); 3847 } 3848 pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId); 3849 pw.print(" ("); 3850 if (mNextAffiliate == null) { 3851 pw.print("null"); 3852 } else { 3853 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate))); 3854 } 3855 pw.println(")"); 3856 } 3857 pw.print(prefix); pw.print("Activities="); pw.println(mChildren); 3858 if (!askedCompatMode || !inRecents || !isAvailable) { 3859 pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode); 3860 pw.print(" inRecents="); pw.print(inRecents); 3861 pw.print(" isAvailable="); pw.println(isAvailable); 3862 } 3863 if (lastDescription != null) { 3864 pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription); 3865 } 3866 if (mRootProcess != null) { 3867 pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess); 3868 } 3869 pw.print(prefix); pw.print("taskId=" + mTaskId); pw.println(" stackId=" + getRootTaskId()); 3870 pw.print(prefix); pw.print("mHasBeenVisible="); pw.println(getHasBeenVisible()); 3871 pw.print(prefix); pw.print("mResizeMode="); 3872 pw.print(ActivityInfo.resizeModeToString(mResizeMode)); 3873 pw.print(" mSupportsPictureInPicture="); pw.print(mSupportsPictureInPicture); 3874 pw.print(" isResizeable="); pw.println(isResizeable()); 3875 pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime); 3876 pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)"); 3877 } 3878 3879 @Override 3880 public String toString() { 3881 StringBuilder sb = new StringBuilder(128); 3882 if (stringName != null) { 3883 sb.append(stringName); 3884 sb.append(" U="); 3885 sb.append(mUserId); 3886 sb.append(" StackId="); 3887 sb.append(getRootTaskId()); 3888 sb.append(" sz="); 3889 sb.append(getChildCount()); 3890 sb.append('}'); 3891 return sb.toString(); 3892 } 3893 sb.append("Task{"); 3894 sb.append(Integer.toHexString(System.identityHashCode(this))); 3895 sb.append(" #"); 3896 sb.append(mTaskId); 3897 sb.append(" visible=" + shouldBeVisible(null /* starting */)); 3898 sb.append(" type=" + activityTypeToString(getActivityType())); 3899 sb.append(" mode=" + windowingModeToString(getWindowingMode())); 3900 sb.append(" translucent=" + isTranslucent(null /* starting */)); 3901 if (affinity != null) { 3902 sb.append(" A="); 3903 sb.append(affinity); 3904 } else if (intent != null && intent.getComponent() != null) { 3905 sb.append(" I="); 3906 sb.append(intent.getComponent().flattenToShortString()); 3907 } else if (affinityIntent != null && affinityIntent.getComponent() != null) { 3908 sb.append(" aI="); 3909 sb.append(affinityIntent.getComponent().flattenToShortString()); 3910 } else { 3911 sb.append(" ??"); 3912 } 3913 stringName = sb.toString(); 3914 return toString(); 3915 } 3916 3917 /** @see #getNumRunningActivities(TaskActivitiesReport) */ 3918 static class TaskActivitiesReport implements Consumer<ActivityRecord> { 3919 int numRunning; 3920 int numActivities; 3921 ActivityRecord top; 3922 ActivityRecord base; 3923 3924 void reset() { 3925 numRunning = numActivities = 0; 3926 top = base = null; 3927 } 3928 3929 @Override 3930 public void accept(ActivityRecord r) { 3931 if (r.finishing) { 3932 return; 3933 } 3934 3935 base = r; 3936 3937 // Increment the total number of non-finishing activities 3938 numActivities++; 3939 3940 if (top == null || (top.isState(ActivityState.INITIALIZING))) { 3941 top = r; 3942 // Reset the number of running activities until we hit the first non-initializing 3943 // activity 3944 numRunning = 0; 3945 } 3946 if (r.attachedToProcess()) { 3947 // Increment the number of actually running activities 3948 numRunning++; 3949 } 3950 } 3951 } 3952 3953 /** 3954 * Saves this {@link Task} to XML using given serializer. 3955 */ 3956 void saveToXml(XmlSerializer out) throws Exception { 3957 if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this); 3958 3959 out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId)); 3960 if (realActivity != null) { 3961 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString()); 3962 } 3963 out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended)); 3964 if (origActivity != null) { 3965 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString()); 3966 } 3967 // Write affinity, and root affinity if it is different from affinity. 3968 // We use the special string "@" for a null root affinity, so we can identify 3969 // later whether we were given a root affinity or should just make it the 3970 // same as the affinity. 3971 if (affinity != null) { 3972 out.attribute(null, ATTR_AFFINITY, affinity); 3973 if (!affinity.equals(rootAffinity)) { 3974 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 3975 } 3976 } else if (rootAffinity != null) { 3977 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 3978 } 3979 if (mWindowLayoutAffinity != null) { 3980 out.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity); 3981 } 3982 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset)); 3983 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents)); 3984 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode)); 3985 out.attribute(null, ATTR_USERID, String.valueOf(mUserId)); 3986 out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete)); 3987 out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid)); 3988 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved)); 3989 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity)); 3990 if (lastDescription != null) { 3991 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); 3992 } 3993 if (getTaskDescription() != null) { 3994 getTaskDescription().saveToXml(out); 3995 } 3996 out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); 3997 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); 3998 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId)); 3999 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId)); 4000 out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid)); 4001 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage); 4002 out.attribute(null, ATTR_CALLING_FEATURE_ID, 4003 mCallingFeatureId == null ? "" : mCallingFeatureId); 4004 out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode)); 4005 out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE, 4006 String.valueOf(mSupportsPictureInPicture)); 4007 if (mLastNonFullscreenBounds != null) { 4008 out.attribute( 4009 null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString()); 4010 } 4011 out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth)); 4012 out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight)); 4013 out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION)); 4014 4015 if (affinityIntent != null) { 4016 out.startTag(null, TAG_AFFINITYINTENT); 4017 affinityIntent.saveToXml(out); 4018 out.endTag(null, TAG_AFFINITYINTENT); 4019 } 4020 4021 if (intent != null) { 4022 out.startTag(null, TAG_INTENT); 4023 intent.saveToXml(out); 4024 out.endTag(null, TAG_INTENT); 4025 } 4026 4027 sTmpException = null; 4028 final PooledFunction f = PooledLambda.obtainFunction(Task::saveActivityToXml, 4029 PooledLambda.__(ActivityRecord.class), getBottomMostActivity(), out); 4030 forAllActivities(f); 4031 f.recycle(); 4032 if (sTmpException != null) { 4033 throw sTmpException; 4034 } 4035 } 4036 4037 private static boolean saveActivityToXml( 4038 ActivityRecord r, ActivityRecord first, XmlSerializer out) { 4039 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() 4040 || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT 4041 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) 4042 && r != first) { 4043 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET). 4044 return true; 4045 } 4046 try { 4047 out.startTag(null, TAG_ACTIVITY); 4048 r.saveToXml(out); 4049 out.endTag(null, TAG_ACTIVITY); 4050 return false; 4051 } catch (Exception e) { 4052 sTmpException = e; 4053 return true; 4054 } 4055 } 4056 4057 static Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) 4058 throws IOException, XmlPullParserException { 4059 Intent intent = null; 4060 Intent affinityIntent = null; 4061 ArrayList<ActivityRecord> activities = new ArrayList<>(); 4062 ComponentName realActivity = null; 4063 boolean realActivitySuspended = false; 4064 ComponentName origActivity = null; 4065 String affinity = null; 4066 String rootAffinity = null; 4067 boolean hasRootAffinity = false; 4068 String windowLayoutAffinity = null; 4069 boolean rootHasReset = false; 4070 boolean autoRemoveRecents = false; 4071 boolean askedCompatMode = false; 4072 int taskType = 0; 4073 int userId = 0; 4074 boolean userSetupComplete = true; 4075 int effectiveUid = -1; 4076 String lastDescription = null; 4077 long lastTimeOnTop = 0; 4078 boolean neverRelinquishIdentity = true; 4079 int taskId = INVALID_TASK_ID; 4080 final int outerDepth = in.getDepth(); 4081 TaskDescription taskDescription = new TaskDescription(); 4082 int taskAffiliation = INVALID_TASK_ID; 4083 int taskAffiliationColor = 0; 4084 int prevTaskId = INVALID_TASK_ID; 4085 int nextTaskId = INVALID_TASK_ID; 4086 int callingUid = -1; 4087 String callingPackage = ""; 4088 String callingFeatureId = null; 4089 int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; 4090 boolean supportsPictureInPicture = false; 4091 Rect lastNonFullscreenBounds = null; 4092 int minWidth = INVALID_MIN_SIZE; 4093 int minHeight = INVALID_MIN_SIZE; 4094 int persistTaskVersion = 0; 4095 4096 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { 4097 final String attrName = in.getAttributeName(attrNdx); 4098 final String attrValue = in.getAttributeValue(attrNdx); 4099 if (TaskPersister.DEBUG) { 4100 Slog.d(TaskPersister.TAG, "Task: attribute name=" + attrName + " value=" 4101 + attrValue); 4102 } 4103 switch (attrName) { 4104 case ATTR_TASKID: 4105 if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue); 4106 break; 4107 case ATTR_REALACTIVITY: 4108 realActivity = ComponentName.unflattenFromString(attrValue); 4109 break; 4110 case ATTR_REALACTIVITY_SUSPENDED: 4111 realActivitySuspended = Boolean.valueOf(attrValue); 4112 break; 4113 case ATTR_ORIGACTIVITY: 4114 origActivity = ComponentName.unflattenFromString(attrValue); 4115 break; 4116 case ATTR_AFFINITY: 4117 affinity = attrValue; 4118 break; 4119 case ATTR_ROOT_AFFINITY: 4120 rootAffinity = attrValue; 4121 hasRootAffinity = true; 4122 break; 4123 case ATTR_WINDOW_LAYOUT_AFFINITY: 4124 windowLayoutAffinity = attrValue; 4125 break; 4126 case ATTR_ROOTHASRESET: 4127 rootHasReset = Boolean.parseBoolean(attrValue); 4128 break; 4129 case ATTR_AUTOREMOVERECENTS: 4130 autoRemoveRecents = Boolean.parseBoolean(attrValue); 4131 break; 4132 case ATTR_ASKEDCOMPATMODE: 4133 askedCompatMode = Boolean.parseBoolean(attrValue); 4134 break; 4135 case ATTR_USERID: 4136 userId = Integer.parseInt(attrValue); 4137 break; 4138 case ATTR_USER_SETUP_COMPLETE: 4139 userSetupComplete = Boolean.parseBoolean(attrValue); 4140 break; 4141 case ATTR_EFFECTIVE_UID: 4142 effectiveUid = Integer.parseInt(attrValue); 4143 break; 4144 case ATTR_TASKTYPE: 4145 taskType = Integer.parseInt(attrValue); 4146 break; 4147 case ATTR_LASTDESCRIPTION: 4148 lastDescription = attrValue; 4149 break; 4150 case ATTR_LASTTIMEMOVED: 4151 lastTimeOnTop = Long.parseLong(attrValue); 4152 break; 4153 case ATTR_NEVERRELINQUISH: 4154 neverRelinquishIdentity = Boolean.parseBoolean(attrValue); 4155 break; 4156 case ATTR_TASK_AFFILIATION: 4157 taskAffiliation = Integer.parseInt(attrValue); 4158 break; 4159 case ATTR_PREV_AFFILIATION: 4160 prevTaskId = Integer.parseInt(attrValue); 4161 break; 4162 case ATTR_NEXT_AFFILIATION: 4163 nextTaskId = Integer.parseInt(attrValue); 4164 break; 4165 case ATTR_TASK_AFFILIATION_COLOR: 4166 taskAffiliationColor = Integer.parseInt(attrValue); 4167 break; 4168 case ATTR_CALLING_UID: 4169 callingUid = Integer.parseInt(attrValue); 4170 break; 4171 case ATTR_CALLING_PACKAGE: 4172 callingPackage = attrValue; 4173 break; 4174 case ATTR_CALLING_FEATURE_ID: 4175 callingFeatureId = attrValue; 4176 break; 4177 case ATTR_RESIZE_MODE: 4178 resizeMode = Integer.parseInt(attrValue); 4179 break; 4180 case ATTR_SUPPORTS_PICTURE_IN_PICTURE: 4181 supportsPictureInPicture = Boolean.parseBoolean(attrValue); 4182 break; 4183 case ATTR_NON_FULLSCREEN_BOUNDS: 4184 lastNonFullscreenBounds = Rect.unflattenFromString(attrValue); 4185 break; 4186 case ATTR_MIN_WIDTH: 4187 minWidth = Integer.parseInt(attrValue); 4188 break; 4189 case ATTR_MIN_HEIGHT: 4190 minHeight = Integer.parseInt(attrValue); 4191 break; 4192 case ATTR_PERSIST_TASK_VERSION: 4193 persistTaskVersion = Integer.parseInt(attrValue); 4194 break; 4195 default: 4196 if (!attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) { 4197 Slog.w(TAG, "Task: Unknown attribute=" + attrName); 4198 } 4199 } 4200 } 4201 taskDescription.restoreFromXml(in); 4202 4203 int event; 4204 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) 4205 && (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) { 4206 if (event == XmlPullParser.START_TAG) { 4207 final String name = in.getName(); 4208 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: START_TAG name=" + name); 4209 if (TAG_AFFINITYINTENT.equals(name)) { 4210 affinityIntent = Intent.restoreFromXml(in); 4211 } else if (TAG_INTENT.equals(name)) { 4212 intent = Intent.restoreFromXml(in); 4213 } else if (TAG_ACTIVITY.equals(name)) { 4214 ActivityRecord activity = 4215 ActivityRecord.restoreFromXml(in, stackSupervisor); 4216 if (TaskPersister.DEBUG) { 4217 Slog.d(TaskPersister.TAG, "Task: activity=" + activity); 4218 } 4219 if (activity != null) { 4220 activities.add(activity); 4221 } 4222 } else { 4223 Slog.e(TAG, "restoreTask: Unexpected name=" + name); 4224 XmlUtils.skipCurrentTag(in); 4225 } 4226 } 4227 } 4228 if (!hasRootAffinity) { 4229 rootAffinity = affinity; 4230 } else if ("@".equals(rootAffinity)) { 4231 rootAffinity = null; 4232 } 4233 if (effectiveUid <= 0) { 4234 Intent checkIntent = intent != null ? intent : affinityIntent; 4235 effectiveUid = 0; 4236 if (checkIntent != null) { 4237 IPackageManager pm = AppGlobals.getPackageManager(); 4238 try { 4239 ApplicationInfo ai = pm.getApplicationInfo( 4240 checkIntent.getComponent().getPackageName(), 4241 PackageManager.MATCH_UNINSTALLED_PACKAGES 4242 | PackageManager.MATCH_DISABLED_COMPONENTS, userId); 4243 if (ai != null) { 4244 effectiveUid = ai.uid; 4245 } 4246 } catch (RemoteException e) { 4247 } 4248 } 4249 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent 4250 + ": effectiveUid=" + effectiveUid); 4251 } 4252 4253 if (persistTaskVersion < 1) { 4254 // We need to convert the resize mode of home activities saved before version one if 4255 // they are marked as RESIZE_MODE_RESIZEABLE to 4256 // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation 4257 // before version 1 and the system didn't resize home activities before then. 4258 if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) { 4259 resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 4260 } 4261 } else { 4262 // This activity has previously marked itself explicitly as both resizeable and 4263 // supporting picture-in-picture. Since there is no longer a requirement for 4264 // picture-in-picture activities to be resizeable, we can mark this simply as 4265 // resizeable and supporting picture-in-picture separately. 4266 if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) { 4267 resizeMode = RESIZE_MODE_RESIZEABLE; 4268 supportsPictureInPicture = true; 4269 } 4270 } 4271 4272 final Task task = new ActivityStack(stackSupervisor.mService, taskId, intent, 4273 affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, 4274 autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription, 4275 lastTimeOnTop, neverRelinquishIdentity, taskDescription, taskAffiliation, 4276 prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage, 4277 callingFeatureId, resizeMode, supportsPictureInPicture, realActivitySuspended, 4278 userSetupComplete, minWidth, minHeight, null /*ActivityInfo*/, 4279 null /*_voiceSession*/, null /*_voiceInteractor*/, null /* stack */); 4280 task.mLastNonFullscreenBounds = lastNonFullscreenBounds; 4281 task.setBounds(lastNonFullscreenBounds); 4282 task.mWindowLayoutAffinity = windowLayoutAffinity; 4283 4284 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { 4285 task.addChild(activities.get(activityNdx)); 4286 } 4287 4288 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task); 4289 return task; 4290 } 4291 4292 @Override 4293 boolean isOrganized() { 4294 return mTaskOrganizer != null; 4295 } 4296 4297 @Override 4298 protected void reparentSurfaceControl(SurfaceControl.Transaction t, SurfaceControl newParent) { 4299 /** 4300 * Avoid reparenting SurfaceControl of the organized tasks that are always on top, since 4301 * the surfaces should be controlled by the organizer itself, like bubbles. 4302 */ 4303 if (isOrganized() && isAlwaysOnTop()) { 4304 return; 4305 } 4306 super.reparentSurfaceControl(t, newParent); 4307 } 4308 4309 void setHasBeenVisible(boolean hasBeenVisible) { 4310 final boolean prevHasBeenVisible = mHasBeenVisible; 4311 mHasBeenVisible = hasBeenVisible; 4312 if (hasBeenVisible) { 4313 // If the task is not yet visible when it is added to the task organizer, then we should 4314 // hide it to allow the task organizer to show it when it is properly reparented. We 4315 // skip this for tasks created by the organizer because they can synchronously update 4316 // the leash before new children are added to the task. 4317 if (!mCreatedByOrganizer && mTaskOrganizer != null && !prevHasBeenVisible) { 4318 getSyncTransaction().hide(getSurfaceControl()); 4319 commitPendingTransaction(); 4320 } 4321 4322 sendTaskAppeared(); 4323 if (!isRootTask()) { 4324 getRootTask().setHasBeenVisible(true); 4325 } 4326 } 4327 } 4328 4329 boolean getHasBeenVisible() { 4330 return mHasBeenVisible; 4331 } 4332 4333 /** In the case that these conditions are true, we want to send the Task to the organizer: 4334 * 1. An organizer has been set 4335 * 2. The Task was created by the organizer 4336 * or 4337 * 2a. We have a SurfaceControl 4338 * 2b. We have finished drawing 4339 * Any time any of these conditions are updated, the updating code should call 4340 * sendTaskAppeared. 4341 */ 4342 boolean taskAppearedReady() { 4343 if (mTaskOrganizer == null) { 4344 return false; 4345 } 4346 4347 if (mCreatedByOrganizer) { 4348 return true; 4349 } 4350 4351 return mSurfaceControl != null && getHasBeenVisible(); 4352 } 4353 4354 private void sendTaskAppeared() { 4355 if (mTaskOrganizer != null) { 4356 mAtmService.mTaskOrganizerController.onTaskAppeared(mTaskOrganizer, this); 4357 } 4358 } 4359 4360 private void sendTaskVanished(ITaskOrganizer organizer) { 4361 if (organizer != null) { 4362 mAtmService.mTaskOrganizerController.onTaskVanished(organizer, this); 4363 } 4364 } 4365 4366 @VisibleForTesting 4367 boolean setTaskOrganizer(ITaskOrganizer organizer) { 4368 if (mTaskOrganizer == organizer) { 4369 return false; 4370 } 4371 4372 ITaskOrganizer previousOrganizer = mTaskOrganizer; 4373 // Update the new task organizer before calling sendTaskVanished since it could result in 4374 // a new SurfaceControl getting created that would notify the old organizer about it. 4375 mTaskOrganizer = organizer; 4376 // Let the old organizer know it has lost control. 4377 sendTaskVanished(previousOrganizer); 4378 4379 if (mTaskOrganizer != null) { 4380 sendTaskAppeared(); 4381 } else { 4382 // No longer managed by any organizer. 4383 mTaskAppearedSent = false; 4384 mLastTaskOrganizerWindowingMode = -1; 4385 setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */); 4386 if (mCreatedByOrganizer) { 4387 removeImmediately(); 4388 } 4389 } 4390 4391 return true; 4392 } 4393 4394 /** 4395 * Called when the task state changes (ie. from windowing mode change) an the task organizer 4396 * state should also be updated. 4397 * 4398 * @param forceUpdate Updates the task organizer to the one currently specified in the task 4399 * org controller for the task's windowing mode, ignoring the cached 4400 * windowing mode checks. 4401 * @return {@code true} if task organizer changed. 4402 */ 4403 boolean updateTaskOrganizerState(boolean forceUpdate) { 4404 if (!isRootTask()) { 4405 return false; 4406 } 4407 4408 final int windowingMode = getWindowingMode(); 4409 if (!forceUpdate && windowingMode == mLastTaskOrganizerWindowingMode) { 4410 // If our windowing mode hasn't actually changed, then just stick 4411 // with our old organizer. This lets us implement the semantic 4412 // where SysUI can continue to manage it's old tasks 4413 // while CTS temporarily takes over the registration. 4414 return false; 4415 } 4416 /* 4417 * Different windowing modes may be managed by different task organizers. If 4418 * getTaskOrganizer returns null, we still call setTaskOrganizer to 4419 * make sure we clear it. 4420 */ 4421 final ITaskOrganizer org = 4422 mWmService.mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode); 4423 final boolean result = setTaskOrganizer(org); 4424 mLastTaskOrganizerWindowingMode = windowingMode; 4425 return result; 4426 } 4427 4428 @Override 4429 void setSurfaceControl(SurfaceControl sc) { 4430 super.setSurfaceControl(sc); 4431 // If the TaskOrganizer was set before we created the SurfaceControl, we need to 4432 // emit the callbacks now. 4433 sendTaskAppeared(); 4434 } 4435 4436 /** 4437 * @return true if the task is currently focused. 4438 */ 4439 private boolean isFocused() { 4440 if (mDisplayContent == null || mDisplayContent.mCurrentFocus == null) { 4441 return false; 4442 } 4443 return mDisplayContent.mCurrentFocus.getTask() == this; 4444 } 4445 4446 /** 4447 * @return true if the task is visible and has at least one visible child. 4448 */ 4449 private boolean hasVisibleChildren() { 4450 if (!isAttached() || isForceHidden()) { 4451 return false; 4452 } 4453 4454 return getActivity(ActivityRecord::isVisible) != null; 4455 } 4456 4457 /** 4458 * @return the desired shadow radius in pixels for the current task. 4459 */ 4460 private float getShadowRadius(boolean taskIsFocused) { 4461 int elevation = 0; 4462 4463 // Get elevation for a specific windowing mode. 4464 if (inPinnedWindowingMode()) { 4465 elevation = PINNED_WINDOWING_MODE_ELEVATION_IN_DIP; 4466 } else if (inFreeformWindowingMode()) { 4467 elevation = taskIsFocused 4468 ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; 4469 } else { 4470 // For all other windowing modes, do not draw a shadow. 4471 return 0; 4472 } 4473 4474 // If the task has no visible children, do not draw a shadow. 4475 if (!hasVisibleChildren()) { 4476 return 0; 4477 } 4478 4479 return dipToPixel(elevation, getDisplayContent().getDisplayMetrics()); 4480 } 4481 4482 /** 4483 * Update the length of the shadow if needed based on windowing mode and task focus state. 4484 */ 4485 private void updateShadowsRadius(boolean taskIsFocused, 4486 SurfaceControl.Transaction pendingTransaction) { 4487 if (!mWmService.mRenderShadowsInCompositor || !isRootTask()) return; 4488 4489 final float newShadowRadius = getShadowRadius(taskIsFocused); 4490 if (mShadowRadius != newShadowRadius) { 4491 mShadowRadius = newShadowRadius; 4492 pendingTransaction.setShadowRadius(getSurfaceControl(), mShadowRadius); 4493 } 4494 } 4495 4496 /** 4497 * Called on the task of a window which gained or lost focus. 4498 * @param hasFocus 4499 */ 4500 void onWindowFocusChanged(boolean hasFocus) { 4501 updateShadowsRadius(hasFocus, getSyncTransaction()); 4502 } 4503 4504 void onPictureInPictureParamsChanged() { 4505 if (isOrganized()) { 4506 mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, true /* force */); 4507 } 4508 } 4509 4510 /** 4511 * See {@link WindowContainerTransaction#setBoundsChangeTransaction}. In short this 4512 * transaction will be consumed by the next BASE_APPLICATION window within our hierarchy 4513 * to resize, and it will defer the transaction until that resize frame completes. 4514 */ 4515 void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t) { 4516 setMainWindowSizeChangeTransaction(t, this); 4517 forAllWindows(WindowState::requestRedrawForSync, true); 4518 } 4519 4520 private void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t, Task origin) { 4521 // This is only meaningful on an activity's task, so put it on the top one. 4522 ActivityRecord topActivity = getTopNonFinishingActivity(); 4523 Task leaf = topActivity != null ? topActivity.getTask() : null; 4524 if (leaf == null) { 4525 return; 4526 } 4527 if (leaf != this) { 4528 leaf.setMainWindowSizeChangeTransaction(t, origin); 4529 return; 4530 } 4531 mMainWindowSizeChangeTransaction = t; 4532 mMainWindowSizeChangeTask = t == null ? null : origin; 4533 } 4534 4535 SurfaceControl.Transaction getMainWindowSizeChangeTransaction() { 4536 return mMainWindowSizeChangeTransaction; 4537 } 4538 4539 Task getMainWindowSizeChangeTask() { 4540 return mMainWindowSizeChangeTask; 4541 } 4542 4543 void setActivityWindowingMode(int windowingMode) { 4544 PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setWindowingMode, 4545 PooledLambda.__(ActivityRecord.class), windowingMode); 4546 forAllActivities(c); 4547 c.recycle(); 4548 } 4549 4550 /** 4551 * Sets/unsets the forced-hidden state flag for this task depending on {@param set}. 4552 * @return Whether the force hidden state changed 4553 */ 4554 boolean setForceHidden(int flags, boolean set) { 4555 int newFlags = mForceHiddenFlags; 4556 if (set) { 4557 newFlags |= flags; 4558 } else { 4559 newFlags &= ~flags; 4560 } 4561 if (mForceHiddenFlags == newFlags) { 4562 return false; 4563 } 4564 final boolean wasHidden = isForceHidden(); 4565 mForceHiddenFlags = newFlags; 4566 if (wasHidden && isFocusableAndVisible()) { 4567 // The change in force-hidden state will change visibility without triggering a stack 4568 // order change, so we should reset the preferred top focusable stack to ensure it's not 4569 // used if a new activity is started from this task. 4570 getDisplayArea().resetPreferredTopFocusableStackIfBelow(this); 4571 } 4572 return true; 4573 } 4574 4575 /** 4576 * Returns whether this task is currently forced to be hidden for any reason. 4577 */ 4578 protected boolean isForceHidden() { 4579 return mForceHiddenFlags != 0; 4580 } 4581 4582 @Override 4583 long getProtoFieldId() { 4584 return TASK; 4585 } 4586 4587 } 4588