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.ActivityManager.isStartResultSuccessful; 20 import static android.app.ActivityTaskManager.INVALID_TASK_ID; 21 import static android.app.ActivityTaskManager.INVALID_WINDOWING_MODE; 22 import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED; 23 import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN; 24 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 25 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 26 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 27 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 28 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 29 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 30 import static android.app.WindowConfiguration.activityTypeToString; 31 import static android.app.WindowConfiguration.windowingModeToString; 32 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; 33 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 34 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; 35 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; 36 import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; 37 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; 38 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; 39 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; 40 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; 41 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; 42 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 43 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED; 44 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 45 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; 46 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; 47 import static android.view.Display.DEFAULT_DISPLAY; 48 import static android.view.Display.INVALID_DISPLAY; 49 import static android.view.SurfaceControl.METADATA_TASK_ID; 50 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 51 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 52 import static android.view.WindowManager.TRANSIT_CLOSE; 53 import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED; 54 import static android.view.WindowManager.TRANSIT_OPEN; 55 import static android.view.WindowManager.TRANSIT_TO_BACK; 56 import static android.view.WindowManager.TRANSIT_TO_FRONT; 57 import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; 58 59 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ADD_REMOVE; 60 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_LOCKTASK; 61 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_STATES; 62 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_TASKS; 63 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_WINDOW_TRANSITIONS_MIN; 64 import static com.android.server.wm.ActivityRecord.State.PAUSED; 65 import static com.android.server.wm.ActivityRecord.State.PAUSING; 66 import static com.android.server.wm.ActivityRecord.State.RESUMED; 67 import static com.android.server.wm.ActivityRecord.State.STARTED; 68 import static com.android.server.wm.ActivityRecord.TRANSFER_SPLASH_SCREEN_COPYING; 69 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; 70 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; 71 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION; 72 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CLEANUP; 73 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS; 74 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; 75 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; 76 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION; 77 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING; 78 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY; 79 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; 80 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; 81 import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_TASK_MSG; 82 import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME; 83 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; 84 import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS; 85 import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity; 86 import static com.android.server.wm.IdentifierProto.HASH_CODE; 87 import static com.android.server.wm.IdentifierProto.TITLE; 88 import static com.android.server.wm.IdentifierProto.USER_ID; 89 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED; 90 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_DONT_LOCK; 91 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE; 92 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; 93 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_PINNABLE; 94 import static com.android.server.wm.TaskProto.AFFINITY; 95 import static com.android.server.wm.TaskProto.BOUNDS; 96 import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER; 97 import static com.android.server.wm.TaskProto.FILLS_PARENT; 98 import static com.android.server.wm.TaskProto.HAS_CHILD_PIP_ACTIVITY; 99 import static com.android.server.wm.TaskProto.LAST_NON_FULLSCREEN_BOUNDS; 100 import static com.android.server.wm.TaskProto.ORIG_ACTIVITY; 101 import static com.android.server.wm.TaskProto.REAL_ACTIVITY; 102 import static com.android.server.wm.TaskProto.RESIZE_MODE; 103 import static com.android.server.wm.TaskProto.RESUMED_ACTIVITY; 104 import static com.android.server.wm.TaskProto.ROOT_TASK_ID; 105 import static com.android.server.wm.TaskProto.SURFACE_HEIGHT; 106 import static com.android.server.wm.TaskProto.SURFACE_WIDTH; 107 import static com.android.server.wm.TaskProto.TASK_FRAGMENT; 108 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; 109 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; 110 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; 111 import static com.android.server.wm.WindowContainerChildProto.TASK; 112 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK; 113 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; 114 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 115 116 import static java.lang.Integer.MAX_VALUE; 117 118 import android.annotation.IntDef; 119 import android.annotation.NonNull; 120 import android.annotation.Nullable; 121 import android.annotation.UserIdInt; 122 import android.app.Activity; 123 import android.app.ActivityManager; 124 import android.app.ActivityManager.TaskDescription; 125 import android.app.ActivityOptions; 126 import android.app.ActivityTaskManager; 127 import android.app.AppGlobals; 128 import android.app.IActivityController; 129 import android.app.PictureInPictureParams; 130 import android.app.TaskInfo; 131 import android.app.WindowConfiguration; 132 import android.content.ComponentName; 133 import android.content.Intent; 134 import android.content.pm.ActivityInfo; 135 import android.content.pm.ActivityInfo.ScreenOrientation; 136 import android.content.pm.ApplicationInfo; 137 import android.content.pm.IPackageManager; 138 import android.content.pm.PackageManager; 139 import android.content.res.Configuration; 140 import android.graphics.Matrix; 141 import android.graphics.Point; 142 import android.graphics.Rect; 143 import android.os.Binder; 144 import android.os.Debug; 145 import android.os.Handler; 146 import android.os.IBinder; 147 import android.os.Looper; 148 import android.os.Message; 149 import android.os.Process; 150 import android.os.RemoteException; 151 import android.os.SystemClock; 152 import android.os.Trace; 153 import android.os.UserHandle; 154 import android.provider.Settings; 155 import android.service.voice.IVoiceInteractionSession; 156 import android.util.DisplayMetrics; 157 import android.util.Slog; 158 import android.util.proto.ProtoOutputStream; 159 import android.view.DisplayInfo; 160 import android.view.InsetsState; 161 import android.view.SurfaceControl; 162 import android.view.WindowInsets; 163 import android.view.WindowManager; 164 import android.window.DesktopExperienceFlags; 165 import android.window.DesktopModeFlags; 166 import android.window.ITaskOrganizer; 167 import android.window.PictureInPictureSurfaceTransaction; 168 import android.window.StartingWindowInfo; 169 import android.window.TaskFragmentParentInfo; 170 import android.window.TaskSnapshot; 171 import android.window.WindowContainerToken; 172 173 import com.android.internal.annotations.GuardedBy; 174 import com.android.internal.annotations.VisibleForTesting; 175 import com.android.internal.app.IVoiceInteractor; 176 import com.android.internal.protolog.ProtoLog; 177 import com.android.internal.util.XmlUtils; 178 import com.android.internal.util.function.pooled.PooledLambda; 179 import com.android.internal.util.function.pooled.PooledPredicate; 180 import com.android.modules.utils.TypedXmlPullParser; 181 import com.android.modules.utils.TypedXmlSerializer; 182 import com.android.server.Watchdog; 183 import com.android.server.am.ActivityManagerService; 184 import com.android.server.am.AppTimeTracker; 185 import com.android.server.uri.NeededUriGrants; 186 import com.android.window.flags.Flags; 187 188 import org.xmlpull.v1.XmlPullParser; 189 import org.xmlpull.v1.XmlPullParserException; 190 191 import java.io.FileDescriptor; 192 import java.io.IOException; 193 import java.io.PrintWriter; 194 import java.lang.annotation.Retention; 195 import java.lang.annotation.RetentionPolicy; 196 import java.util.ArrayList; 197 import java.util.List; 198 import java.util.Objects; 199 import java.util.function.Consumer; 200 import java.util.function.Predicate; 201 202 /** 203 * {@link Task} is a TaskFragment that can contain a group of activities to perform a certain job. 204 * Activities of the same task affinities usually group in the same {@link Task}. A {@link Task} 205 * can also be an entity that showing in the Recents Screen for a job that user interacted with. 206 * A {@link Task} can also contain other {@link Task}s. 207 */ 208 class Task extends TaskFragment { 209 private static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_ATM; 210 private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; 211 static final String TAG_TASKS = TAG + POSTFIX_TASKS; 212 static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP; 213 private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; 214 private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION; 215 private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; 216 static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY; 217 218 private static final String ATTR_TASKID = "task_id"; 219 private static final String TAG_INTENT = "intent"; 220 private static final String TAG_AFFINITYINTENT = "affinity_intent"; 221 private static final String ATTR_REALACTIVITY = "real_activity"; 222 private static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended"; 223 private static final String ATTR_ORIGACTIVITY = "orig_activity"; 224 private static final String TAG_ACTIVITY = "activity"; 225 private static final String ATTR_AFFINITY = "affinity"; 226 private static final String ATTR_ROOT_AFFINITY = "root_affinity"; 227 private static final String ATTR_ROOTHASRESET = "root_has_reset"; 228 private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents"; 229 private static final String ATTR_USERID = "user_id"; 230 private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete"; 231 private static final String ATTR_EFFECTIVE_UID = "effective_uid"; 232 @Deprecated 233 private static final String ATTR_TASKTYPE = "task_type"; 234 private static final String ATTR_LASTDESCRIPTION = "last_description"; 235 private static final String ATTR_LASTTIMEMOVED = "last_time_moved"; 236 private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity"; 237 private static final String ATTR_TASK_AFFILIATION = "task_affiliation"; 238 private static final String ATTR_PREV_AFFILIATION = "prev_affiliation"; 239 private static final String ATTR_NEXT_AFFILIATION = "next_affiliation"; 240 private static final String ATTR_CALLING_UID = "calling_uid"; 241 private static final String ATTR_CALLING_PACKAGE = "calling_package"; 242 private static final String ATTR_CALLING_FEATURE_ID = "calling_feature_id"; 243 private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture"; 244 private static final String ATTR_RESIZE_MODE = "resize_mode"; 245 private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds"; 246 private static final String ATTR_MIN_WIDTH = "min_width"; 247 private static final String ATTR_MIN_HEIGHT = "min_height"; 248 private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version"; 249 private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity"; 250 251 // How long to wait for all background Activities to redraw following a call to 252 // convertToTranslucent(). 253 private static final long TRANSLUCENT_CONVERSION_TIMEOUT = 2000; 254 255 // Current version of the task record we persist. Used to check if we need to run any upgrade 256 // code. 257 static final int PERSIST_TASK_VERSION = 1; 258 259 private static final int DEFAULT_MIN_TASK_SIZE_DP = 220; 260 261 /** 262 * The modes to control how root task is moved to the front when calling {@link Task#reparent}. 263 */ 264 @Retention(RetentionPolicy.SOURCE) 265 @IntDef({ 266 REPARENT_MOVE_ROOT_TASK_TO_FRONT, 267 REPARENT_KEEP_ROOT_TASK_AT_FRONT, 268 REPARENT_LEAVE_ROOT_TASK_IN_PLACE 269 }) 270 @interface ReparentMoveRootTaskMode {} 271 // Moves the root task to the front if it was not at the front 272 static final int REPARENT_MOVE_ROOT_TASK_TO_FRONT = 0; 273 // Only moves the root task to the front if it was focused or front most already 274 static final int REPARENT_KEEP_ROOT_TASK_AT_FRONT = 1; 275 // Do not move the root task as a part of reparenting 276 static final int REPARENT_LEAVE_ROOT_TASK_IN_PLACE = 2; 277 278 // The topmost Activity passed to convertToTranslucent(). When non-null it means we are 279 // waiting for all Activities in mUndrawnActivitiesBelowTopTranslucent to be removed as they 280 // are drawn. When the last member of mUndrawnActivitiesBelowTopTranslucent is removed the 281 // Activity in mTranslucentActivityWaiting is notified via 282 // Activity.onTranslucentConversionComplete(false). If a timeout occurs prior to the last 283 // background activity being drawn then the same call will be made with a true value. 284 ActivityRecord mTranslucentActivityWaiting = null; 285 ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent = new ArrayList<>(); 286 287 // The topmost Activity that was converted to translucent for scene transition, which should 288 // be converted from translucent once the transition is completed, or the app died. 289 private ActivityRecord mPendingConvertFromTranslucentActivity = null; 290 291 /** 292 * Set when we know we are going to be calling updateConfiguration() 293 * soon, so want to skip intermediate config checks. 294 */ 295 boolean mConfigWillChange; 296 297 /** 298 * Used to keep resumeTopActivityUncheckedLocked() from being entered recursively 299 */ 300 boolean mInResumeTopActivity = false; 301 302 /** 303 * Used to identify if the activity that is installed from device's system image. 304 */ 305 boolean mIsEffectivelySystemApp; 306 307 int mCurrentUser; 308 309 String affinity; // The affinity name for this task, or null; may change identity. 310 String rootAffinity; // Initial base affinity, or null; does not change from initial root. 311 String mWindowLayoutAffinity; // Launch param affinity of this task or null. Used when saving 312 // launch params of this task. 313 IVoiceInteractionSession voiceSession; // Voice interaction session driving task 314 IVoiceInteractor voiceInteractor; // Associated interactor to provide to app 315 Intent intent; // The original intent that started the task. Note that this value can 316 // be null. 317 Intent affinityIntent; // Intent of affinity-moved activity that started this task. 318 int effectiveUid; // The current effective uid of the identity of this task. 319 ComponentName origActivity; // The non-alias activity component of the intent. 320 ComponentName realActivity; // The actual activity component that started the task. 321 boolean realActivitySuspended; // True if the actual activity component that started the 322 // task is suspended. 323 boolean inRecents; // Actually in the recents list? 324 long lastActiveTime; // Last time this task was active in the current device session, 325 // including sleep. This time is initialized to the elapsed time when 326 // restored from disk. 327 boolean isAvailable; // Is the activity available to be launched? 328 boolean rootWasReset; // True if the intent at the root of the task had 329 // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag. 330 boolean autoRemoveRecents; // If true, we should automatically remove the task from 331 // recents when activity finishes 332 private boolean mHasBeenVisible; // Set if any activities in the task have been visible 333 334 String stringName; // caching of toString() result. 335 boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity 336 // was changed. 337 338 int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE; 339 340 int mLockTaskUid = -1; // The uid of the application that called startLockTask(). 341 342 /** 343 * If non-null, the starting window should cover the associated task. It is assigned when the 344 * parent activity of starting window is put in a partial area of the task. This field will be 345 * cleared when all visible activities in this task are drawn. 346 */ 347 StartingData mSharedStartingData; 348 349 /** The process that had previously hosted the root activity of this task. 350 * Used to know that we should try harder to keep this process around, in case the 351 * user wants to return to it. */ 352 private WindowProcessController mRootProcess; 353 354 /** The TF host info are set once the task has ever added an organized task fragment. */ 355 int mTaskFragmentHostUid; 356 String mTaskFragmentHostProcessName; 357 358 /** Takes on same value as first root activity */ 359 boolean isPersistable = false; 360 int maxRecents; 361 362 /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for 363 * determining the order when restoring. */ 364 long mLastTimeMoved; 365 366 /** 367 * If it is set, the processes belong to the task will be killed when one of its activity 368 * reports that Activity#onDestroy is done and the task no longer contains perceptible 369 * components. This should only be set on a leaf task. 370 */ 371 boolean mKillProcessesOnDestroyed; 372 373 /** If original intent did not allow relinquishing task identity, save that information */ 374 private boolean mNeverRelinquishIdentity = true; 375 376 /** Avoid reentrant of {@link #removeImmediately(String)}. */ 377 private boolean mRemoving; 378 379 // Used in the unique case where we are clearing the task in order to reuse it. In that case we 380 // do not want to delete the root task when the task goes empty. 381 private boolean mReuseTask = false; 382 383 CharSequence lastDescription; // Last description captured for this item. 384 385 int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent. 386 Task mPrevAffiliate; // previous task in affiliated chain. 387 int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence. 388 Task mNextAffiliate; // next task in affiliated chain. 389 int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence. 390 391 // For relaunching the task from recents as though it was launched by the original launcher. 392 int mCallingUid; 393 String mCallingPackage; 394 String mCallingFeatureId; 395 396 // Last non-fullscreen bounds the task was launched in or resized to. 397 // The information is persisted and used to determine the appropriate root task to launch the 398 // task into on restore. 399 Rect mLastNonFullscreenBounds = null; 400 401 // The surface transition of the target when recents animation is finished. 402 // This is originally introduced to carry out the current surface control position and window 403 // crop when a multi-activity task enters pip with autoEnterPip enabled. In such case, 404 // the surface control of the task will be animated in Launcher and then the top activity is 405 // reparented to pinned root task. 406 // Do not forget to reset this after reparenting. 407 // TODO: remove this once the recents animation is moved to the Shell 408 PictureInPictureSurfaceTransaction mLastRecentsAnimationTransaction; 409 // The content overlay to be applied with mLastRecentsAnimationTransaction 410 // TODO: remove this once the recents animation is moved to the Shell 411 SurfaceControl mLastRecentsAnimationOverlay; 412 413 // A surface that is used by TaskFragmentOrganizer to place content on top of own activities and 414 // trusted TaskFragments. 415 @Nullable 416 DecorSurfaceContainer mDecorSurfaceContainer; 417 418 static final int LAYER_RANK_INVISIBLE = -1; 419 // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible) 420 // This number will be assigned when we evaluate OOM scores for all visible tasks. 421 int mLayerRank = LAYER_RANK_INVISIBLE; 422 423 /** A 0~100 ratio to indicate the percentage of visible area on screen of a freeform task. */ 424 int mNonOccludedFreeformAreaRatio; 425 426 /* Unique identifier for this task. */ 427 final int mTaskId; 428 /* User for which this task was created. */ 429 // TODO: Make final 430 int mUserId; 431 432 // Id of the previous display the root task was on. 433 int mPrevDisplayId = INVALID_DISPLAY; 434 435 int mMultiWindowRestoreWindowingMode = INVALID_WINDOWING_MODE; 436 WindowContainerToken mMultiWindowRestoreParent; 437 438 /** 439 * Last requested orientation reported to DisplayContent. This is different from {@link 440 * #mOrientation} in the sense that this takes activities' requested orientation into 441 * account. Start with {@link ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} so that we don't need 442 * to notify for activities that don't specify any orientation. 443 */ 444 int mLastReportedRequestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 445 446 private final Rect mTmpRect = new Rect(); 447 448 // Resize mode of the task. See {@link ActivityInfo#resizeMode} 449 // Based on the {@link ActivityInfo#resizeMode} of the root activity. 450 int mResizeMode; 451 452 // Whether or not this task and its activities support PiP. Based on the 453 // {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag of the root activity. 454 boolean mSupportsPictureInPicture; 455 456 // Whether the task is currently being drag-resized 457 private boolean mDragResizing; 458 459 // This represents the last resolved activity values for this task 460 // NOTE: This value needs to be persisted with each task 461 private TaskDescription mTaskDescription; 462 463 private static Exception sTmpException; 464 465 private boolean mForceShowForAllUsers; 466 467 // The display category name for this task. 468 String mRequiredDisplayCategory; 469 470 // TODO(b/160201781): Revisit double invocation issue in Task#removeChild. 471 /** 472 * Skip {@link ActivityTaskSupervisor#removeTask(Task, boolean, boolean, String)} execution if 473 * {@code true} to prevent double traversal of {@link #mChildren} in a loop. 474 */ 475 boolean mInRemoveTask; 476 477 /** 478 * When set, disassociate the leaf task if relaunched and reparented it to TDA as root task if 479 * possible. 480 */ 481 boolean mReparentLeafTaskIfRelaunch; 482 483 /** 484 * Set to affect whether recents should be able to trim this task or not. It's set to true by 485 * default. 486 */ 487 boolean mIsTrimmableFromRecents; 488 489 /** 490 * Sets whether the launch-adjacent flag is respected or not for this task or its child tasks. 491 */ 492 private boolean mLaunchAdjacentDisabled; 493 494 /** 495 * Bounds offset should be applied when calculating compatible configuration for apps targeting 496 * SDK level 34 or before. 497 */ 498 int mOffsetXForInsets; 499 int mOffsetYForInsets; 500 501 /** 502 * When set to true, the task will be kept at a PERCEPTIBLE_APP_ADJ, and downgraded 503 * to PREVIOUS_APP_ADJ if not in foreground for a period of time. 504 * One example use case is for desktop form factors, where it is important keep tasks in the 505 * perceptible state (rather than cached where it may be frozen) when a user moves it to the 506 * foreground. 507 * On startup, restored Tasks will not be perceptible, until user actually interacts with it 508 * (i.e. brings it to the foreground) 509 */ 510 boolean mIsPerceptible = false; 511 512 /** 513 * Whether the task has been forced resizable, which is determined by the 514 * activity that started this task. 515 */ 516 private boolean mForceResizeOverride; 517 518 /** 519 * Whether the task has been forced non-resizable, which is determined by 520 * the activity that started this task. 521 */ 522 private boolean mForceNonResizeOverride; 523 524 private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_TASK_MSG + 1; 525 526 private final Handler mHandler; 527 528 private class ActivityTaskHandler extends Handler { 529 ActivityTaskHandler(Looper looper)530 ActivityTaskHandler(Looper looper) { 531 super(looper); 532 } 533 534 @Override handleMessage(Message msg)535 public void handleMessage(Message msg) { 536 switch (msg.what) { 537 case TRANSLUCENT_TIMEOUT_MSG: { 538 synchronized (mAtmService.mGlobalLock) { 539 notifyActivityDrawnLocked(null); 540 } 541 } break; 542 } 543 } 544 } 545 546 private static final ResetTargetTaskHelper sResetTargetTaskHelper = new ResetTargetTaskHelper(); 547 548 private final FindRootHelper mFindRootHelper = new FindRootHelper(); 549 private class FindRootHelper implements Predicate<ActivityRecord> { 550 private ActivityRecord mRoot; 551 private boolean mIgnoreRelinquishIdentity; 552 private boolean mSetToBottomIfNone; 553 findRoot(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone)554 ActivityRecord findRoot(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) { 555 mIgnoreRelinquishIdentity = ignoreRelinquishIdentity; 556 mSetToBottomIfNone = setToBottomIfNone; 557 forAllActivities(this, false /* traverseTopToBottom */); 558 final ActivityRecord root = mRoot; 559 mRoot = null; 560 return root; 561 } 562 563 @Override test(ActivityRecord r)564 public boolean test(ActivityRecord r) { 565 if (mRoot == null && mSetToBottomIfNone) { 566 // This is the first activity we are process. Set it as the candidate root in case 567 // we don't find a better one. 568 mRoot = r; 569 } 570 571 if (r.finishing) return false; 572 573 if (mRoot == null || mRoot.finishing) { 574 // Set this as the candidate root since it isn't finishing. 575 mRoot = r; 576 } 577 578 final int uid = mRoot == r ? effectiveUid : r.info.applicationInfo.uid; 579 if (mIgnoreRelinquishIdentity 580 || (mRoot.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0 581 || (mRoot.info.applicationInfo.uid != Process.SYSTEM_UID 582 && !mRoot.info.applicationInfo.isSystemApp() 583 && mRoot.info.applicationInfo.uid != uid)) { 584 // No need to relinquish identity, end search. 585 return true; 586 } 587 588 // Relinquish to next activity 589 mRoot = r; 590 return false; 591 } 592 } 593 594 /** 595 * The TaskOrganizer which is delegated presentation of this task. If set the Task will 596 * emit an WindowContainerToken (allowing access to it's SurfaceControl leash) to the organizers 597 * taskAppeared callback, and emit a taskRemoved callback when the Task is vanished. 598 */ 599 ITaskOrganizer mTaskOrganizer; 600 601 /** 602 * Prevent duplicate calls to onTaskAppeared. 603 */ 604 boolean mTaskAppearedSent; 605 606 // If the sending of the task appear signal should be deferred until this flag is set back to 607 // false. 608 private boolean mDeferTaskAppear; 609 610 // Tracking cookie for the creation of this task. 611 IBinder mLaunchCookie; 612 613 // The task will be removed when TaskOrganizer, which is managing the task, is destroyed. 614 boolean mRemoveWithTaskOrganizer; 615 616 /** 617 * Reference to the pinned activity that is logically parented to this task, ie. 618 * the previous top activity within this task is put into pinned mode. 619 * This always gets cleared in pair with the ActivityRecord-to-Task link as seen in 620 * {@link ActivityRecord#clearLastParentBeforePip()}. 621 */ 622 ActivityRecord mChildPipActivity; 623 624 boolean mLastSurfaceShowing; 625 626 boolean mAlignActivityLocaleWithTask = false; 627 628 /** @see #isForceExcludedFromRecents() */ 629 private boolean mForceExcludedFromRecents; 630 Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent, Intent _affinityIntent, String _affinity, String _rootAffinity, ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents, int _userId, int _effectiveUid, String _lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId, int nextTaskId, 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, boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear, boolean _removeWithTaskOrganizer)631 private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent, 632 Intent _affinityIntent, String _affinity, String _rootAffinity, 633 ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, 634 boolean _autoRemoveRecents, int _userId, int _effectiveUid, 635 String _lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity, 636 TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId, 637 int nextTaskId, int callingUid, String callingPackage, 638 @Nullable String callingFeatureId, int resizeMode, boolean supportsPictureInPicture, 639 boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight, 640 ActivityInfo info, IVoiceInteractionSession _voiceSession, 641 IVoiceInteractor _voiceInteractor, boolean _createdByOrganizer, IBinder _launchCookie, 642 boolean _deferTaskAppear, boolean _removeWithTaskOrganizer) { 643 super(atmService, null /* fragmentToken */, _createdByOrganizer, false /* isEmbedded */); 644 645 mTaskId = _taskId; 646 mUserId = _userId; 647 mResizeMode = resizeMode; 648 mSupportsPictureInPicture = supportsPictureInPicture; 649 mTaskDescription = _lastTaskDescription != null 650 ? _lastTaskDescription 651 : new TaskDescription(); 652 affinityIntent = _affinityIntent; 653 affinity = _affinity; 654 rootAffinity = _rootAffinity; 655 voiceSession = _voiceSession; 656 voiceInteractor = _voiceInteractor; 657 realActivity = _realActivity; 658 realActivitySuspended = _realActivitySuspended; 659 origActivity = _origActivity; 660 rootWasReset = _rootWasReset; 661 isAvailable = true; 662 autoRemoveRecents = _autoRemoveRecents; 663 mUserSetupComplete = userSetupComplete; 664 effectiveUid = _effectiveUid; 665 touchActiveTime(); 666 lastDescription = _lastDescription; 667 mLastTimeMoved = lastTimeMoved; 668 mNeverRelinquishIdentity = neverRelinquishIdentity; 669 mAffiliatedTaskId = taskAffiliation; 670 mPrevAffiliateTaskId = prevTaskId; 671 mNextAffiliateTaskId = nextTaskId; 672 mCallingUid = callingUid; 673 mCallingPackage = callingPackage; 674 mCallingFeatureId = callingFeatureId; 675 mResizeMode = resizeMode; 676 if (info != null) { 677 setIntent(_intent, info); 678 setMinDimensions(info); 679 } else { 680 intent = _intent; 681 mMinWidth = minWidth; 682 mMinHeight = minHeight; 683 } 684 mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity); 685 mHandler = new ActivityTaskHandler(mTaskSupervisor.mLooper); 686 mCurrentUser = mAtmService.mAmInternal.getCurrentUserId(); 687 688 mLaunchCookie = _launchCookie; 689 mDeferTaskAppear = _deferTaskAppear; 690 mRemoveWithTaskOrganizer = _removeWithTaskOrganizer; 691 mIsTrimmableFromRecents = true; 692 EventLogTags.writeWmTaskCreated(mTaskId); 693 } 694 fromWindowContainerToken(WindowContainerToken token)695 static Task fromWindowContainerToken(WindowContainerToken token) { 696 if (token == null) return null; 697 return fromBinder(token.asBinder()).asTask(); 698 } 699 reuseAsLeafTask(IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, Intent intent, ActivityInfo info, ActivityRecord activity)700 Task reuseAsLeafTask(IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, 701 Intent intent, ActivityInfo info, ActivityRecord activity) { 702 voiceSession = _voiceSession; 703 voiceInteractor = _voiceInteractor; 704 setIntent(activity, intent, info); 705 setMinDimensions(info); 706 // Before we began to reuse a root task as the leaf task, we used to 707 // create a leaf task in this case. Therefore now we won't send out the task created 708 // notification when we decide to reuse it here, so we send out the notification below. 709 // The reason why the created notification sent out when root task is created doesn't work 710 // is that realActivity isn't set until setIntent() method above is called for the first 711 // time. Eventually this notification will be removed when we can populate those information 712 // when root task is created. 713 mAtmService.getTaskChangeNotificationController().notifyTaskCreated(mTaskId, realActivity); 714 return this; 715 } 716 cleanUpResourcesForDestroy(WindowContainer<?> oldParent)717 private void cleanUpResourcesForDestroy(WindowContainer<?> oldParent) { 718 if (hasChild()) { 719 return; 720 } 721 722 // This task is going away, so save the last state if necessary. 723 saveLaunchingStateIfNeeded(oldParent.getDisplayContent()); 724 725 // TODO: VI what about activity? 726 final boolean isVoiceSession = voiceSession != null; 727 if (isVoiceSession) { 728 try { 729 voiceSession.taskFinished(intent, mTaskId); 730 } catch (RemoteException e) { 731 } 732 } 733 if (shouldAutoRemoveFromRecents(oldParent.asTaskFragment()) || isVoiceSession) { 734 // Task creator asked to remove this when done, or this task was a voice 735 // interaction, so it should not remain on the recent tasks list. 736 mTaskSupervisor.mRecentTasks.remove(this); 737 } 738 739 removeIfPossible("cleanUpResourcesForDestroy"); 740 } 741 742 @VisibleForTesting 743 @Override removeIfPossible()744 void removeIfPossible() { 745 removeIfPossible("removeTaskIfPossible"); 746 } 747 removeIfPossible(String reason)748 void removeIfPossible(String reason) { 749 mAtmService.getLockTaskController().clearLockedTask(this); 750 if (shouldDeferRemoval()) { 751 if (DEBUG_ROOT_TASK) Slog.i(TAG, 752 "removeTask:" + reason + " deferring removing taskId=" + mTaskId); 753 return; 754 } 755 final boolean isLeafTask = isLeafTask(); 756 removeImmediately(reason); 757 if (isLeafTask) { 758 mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId); 759 760 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 761 if (taskDisplayArea != null) { 762 taskDisplayArea.onLeafTaskRemoved(mTaskId); 763 } 764 } 765 } 766 setResizeMode(int resizeMode)767 void setResizeMode(int resizeMode) { 768 if (mResizeMode == resizeMode) { 769 return; 770 } 771 mResizeMode = resizeMode; 772 mRootWindowContainer.ensureActivitiesVisible(); 773 mRootWindowContainer.resumeFocusedTasksTopActivities(); 774 updateTaskDescription(); 775 } 776 resize(Rect bounds, int resizeMode, boolean preserveWindow)777 boolean resize(Rect bounds, int resizeMode, boolean preserveWindow) { 778 mAtmService.deferWindowLayout(); 779 780 try { 781 final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0; 782 783 if (getParent() == null) { 784 // Task doesn't exist in window manager yet (e.g. was restored from recents). 785 // All we can do for now is update the bounds so it can be used when the task is 786 // added to window manager. 787 setBounds(bounds); 788 if (!inFreeformWindowingMode()) { 789 // re-restore the task so it can have the proper root task association. 790 mTaskSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP); 791 } 792 return true; 793 } 794 795 if (!canResizeToBounds(bounds)) { 796 throw new IllegalArgumentException("resizeTask: Can not resize task=" + this 797 + " to bounds=" + bounds + " resizeMode=" + mResizeMode); 798 } 799 800 // Do not move the task to another root task here. 801 // This method assumes that the task is already placed in the right root task. 802 // we do not mess with that decision and we only do the resize! 803 804 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizeTask_" + mTaskId); 805 806 // This variable holds information whether the configuration didn't change in a 807 // significant way and the activity was kept the way it was. If it's false, it means 808 // the activity had to be relaunched due to configuration change. 809 boolean kept = true; 810 if (setBounds(bounds, forced) != BOUNDS_CHANGE_NONE) { 811 final ActivityRecord r = topRunningActivityLocked(); 812 if (r != null) { 813 kept = r.ensureActivityConfiguration(); 814 // Preserve other windows for resizing because if resizing happens when there 815 // is a dialog activity in the front, the activity that still shows some 816 // content to the user will become black and cause flickers. Note in most cases 817 // this won't cause tons of irrelevant windows being preserved because only 818 // activities in this task may experience a bounds change. Configs for other 819 // activities stay the same. 820 mRootWindowContainer.ensureActivitiesVisible(r); 821 if (!kept) { 822 mRootWindowContainer.resumeFocusedTasksTopActivities(); 823 } 824 } 825 } 826 saveLaunchingStateIfNeeded(); 827 828 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 829 return kept; 830 } finally { 831 mAtmService.continueWindowLayout(); 832 } 833 } 834 835 /** 836 * Reparents the task into a preferred root task, creating it if necessary. 837 * 838 * @param preferredRootTask the target root task to move this task 839 * @param toTop top or bottom position to place this task in the target task 840 * @param animate whether or not we should wait for the new window created as a part of the 841 * reparenting to be drawn and animated in 842 * @param moveRootTaskMode whether or not to move the root task to the front always, only if 843 * it was previously focused & in front, or never 844 * @param deferResume whether or not to update the visibility of other tasks and root tasks 845 * that may have changed as a result of this reparenting 846 * @param reason the caller of this reparenting 847 * @return whether the task was reparented 848 */ 849 // TODO: Inspect all call sites and change to just changing windowing mode of the root task vs. 850 // re-parenting the task. Can only be done when we are no longer using static root task Ids. reparent(Task preferredRootTask, boolean toTop, @ReparentMoveRootTaskMode int moveRootTaskMode, boolean animate, boolean deferResume, String reason)851 boolean reparent(Task preferredRootTask, boolean toTop, 852 @ReparentMoveRootTaskMode int moveRootTaskMode, boolean animate, boolean deferResume, 853 String reason) { 854 final ActivityTaskSupervisor supervisor = mTaskSupervisor; 855 final RootWindowContainer root = mRootWindowContainer; 856 final Task sourceRootTask = getRootTask(); 857 final Task toRootTask = supervisor.getReparentTargetRootTask(this, preferredRootTask, 858 toTop); 859 if (toRootTask == sourceRootTask) { 860 return false; 861 } 862 if (!canBeLaunchedOnDisplay(toRootTask.getDisplayId())) { 863 return false; 864 } 865 866 final ActivityRecord topActivity = getTopNonFinishingActivity(); 867 868 mAtmService.deferWindowLayout(); 869 try { 870 final ActivityRecord r = topRunningActivityLocked(); 871 final boolean wasFocused = r != null && root.isTopDisplayFocusedRootTask(sourceRootTask) 872 && (topRunningActivityLocked() == r); 873 874 // In some cases the focused root task isn't the front root task. E.g. root pinned task. 875 // Whenever we are moving the top activity from the front root task we want to make 876 // sure to move the root task to the front. 877 final boolean wasFront = r != null && sourceRootTask.isTopRootTaskInDisplayArea() 878 && (sourceRootTask.topRunningActivity() == r); 879 880 final boolean moveRootTaskToFront = moveRootTaskMode == REPARENT_MOVE_ROOT_TASK_TO_FRONT 881 || (moveRootTaskMode == REPARENT_KEEP_ROOT_TASK_AT_FRONT 882 && (wasFocused || wasFront)); 883 884 reparent(toRootTask, toTop ? MAX_VALUE : 0, moveRootTaskToFront, reason); 885 886 // If the task had focus before (or we're requested to move focus), move focus to the 887 // new root task by moving the root task to the front. 888 if (r != null && moveRootTaskToFront) { 889 // Move the root task in which we are placing the activity to the front. 890 toRootTask.moveToFront(reason); 891 892 // If the original state is resumed, there is no state change to update focused app. 893 // So here makes sure the activity focus is set if it is the top. 894 if (r.isState(RESUMED) && r == mRootWindowContainer.getTopResumedActivity()) { 895 mAtmService.setLastResumedActivityUncheckLocked(r, reason); 896 } 897 } 898 if (!animate) { 899 mTaskSupervisor.mNoAnimActivities.add(topActivity); 900 } 901 } finally { 902 mAtmService.continueWindowLayout(); 903 } 904 905 if (!deferResume) { 906 // The task might have already been running and its visibility needs to be synchronized 907 // with the visibility of the root task / windows. 908 root.ensureActivitiesVisible(); 909 root.resumeFocusedTasksTopActivities(); 910 } 911 912 // TODO: Handle incorrect request to move before the actual move, not after. 913 supervisor.handleNonResizableTaskIfNeeded(this, preferredRootTask.getWindowingMode(), 914 mRootWindowContainer.getDefaultTaskDisplayArea(), toRootTask); 915 916 return (preferredRootTask == toRootTask); 917 } 918 touchActiveTime()919 void touchActiveTime() { 920 lastActiveTime = SystemClock.elapsedRealtime(); 921 } 922 getInactiveDuration()923 long getInactiveDuration() { 924 return SystemClock.elapsedRealtime() - lastActiveTime; 925 } 926 927 /** @see #setIntent(ActivityRecord, Intent, ActivityInfo) */ setIntent(ActivityRecord r)928 void setIntent(ActivityRecord r) { 929 setIntent(r, null /* intent */, null /* info */); 930 } 931 932 /** 933 * Sets the original intent, and the calling uid and package. 934 * 935 * @param r The activity that started the task 936 * @param intent The task info which could be different from {@code r.intent} if set. 937 * @param info The activity info which could be different from {@code r.info} if set. 938 */ setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info)939 void setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info) { 940 boolean updateIdentity = false; 941 if (this.intent == null) { 942 updateIdentity = true; 943 } else if (!mNeverRelinquishIdentity) { 944 final ActivityInfo activityInfo = info != null ? info : r.info; 945 updateIdentity = (effectiveUid == Process.SYSTEM_UID || mIsEffectivelySystemApp 946 || effectiveUid == activityInfo.applicationInfo.uid); 947 } 948 if (updateIdentity) { 949 mCallingUid = r.launchedFromUid; 950 mCallingPackage = r.launchedFromPackage; 951 mCallingFeatureId = r.launchedFromFeatureId; 952 setIntent(intent != null ? intent : r.intent, info != null ? info : r.info); 953 updateForceResizeOverrides(r); 954 } 955 setLockTaskAuth(r); 956 } 957 958 /** Sets the original intent, _without_ updating the calling uid or package. */ setIntent(Intent _intent, ActivityInfo info)959 private void setIntent(Intent _intent, ActivityInfo info) { 960 if (!isLeafTask()) return; 961 962 mNeverRelinquishIdentity = (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0; 963 affinity = info.taskAffinity; 964 if (intent == null) { 965 // If this task already has an intent associated with it, don't set the root 966 // affinity -- we don't want it changing after initially set, but the initially 967 // set value may be null. 968 rootAffinity = affinity; 969 mRequiredDisplayCategory = info.requiredDisplayCategory; 970 } 971 effectiveUid = info.applicationInfo.uid; 972 mIsEffectivelySystemApp = info.applicationInfo.isSystemApp(); 973 974 if (info.targetActivity == null) { 975 if (_intent != null) { 976 // If this Intent has a selector, we want to clear it for the 977 // recent task since it is not relevant if the user later wants 978 // to re-launch the app. 979 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) { 980 _intent = new Intent(_intent); 981 _intent.setSelector(null); 982 _intent.setSourceBounds(null); 983 } 984 } 985 ProtoLog.v(WM_DEBUG_TASKS, "Setting Intent of %s to %s", this, _intent); 986 intent = _intent; 987 realActivity = _intent != null ? _intent.getComponent() : null; 988 origActivity = null; 989 } else { 990 ComponentName targetComponent = new ComponentName( 991 info.packageName, info.targetActivity); 992 if (_intent != null) { 993 Intent targetIntent = new Intent(_intent); 994 targetIntent.setSelector(null); 995 targetIntent.setSourceBounds(null); 996 ProtoLog.v(WM_DEBUG_TASKS, "Setting Intent of %s to target %s", this, targetIntent); 997 intent = targetIntent; 998 realActivity = targetComponent; 999 origActivity = _intent.getComponent(); 1000 } else { 1001 intent = null; 1002 realActivity = targetComponent; 1003 origActivity = new ComponentName(info.packageName, info.name); 1004 } 1005 } 1006 mWindowLayoutAffinity = 1007 info.windowLayout == null ? null : info.windowLayout.windowLayoutAffinity; 1008 1009 final int intentFlags = intent == null ? 0 : intent.getFlags(); 1010 if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { 1011 // Once we are set to an Intent with this flag, we count this 1012 // task as having a true root activity. 1013 rootWasReset = true; 1014 } 1015 mUserId = UserHandle.getUserId(info.applicationInfo.uid); 1016 mUserSetupComplete = Settings.Secure.getIntForUser( 1017 mAtmService.mContext.getContentResolver(), USER_SETUP_COMPLETE, 0, mUserId) != 0; 1018 if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) { 1019 // If the activity itself has requested auto-remove, then just always do it. 1020 autoRemoveRecents = true; 1021 } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS)) 1022 == FLAG_ACTIVITY_NEW_DOCUMENT) { 1023 // If the caller has not asked for the document to be retained, then we may 1024 // want to turn on auto-remove, depending on whether the target has set its 1025 // own document launch mode. 1026 if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) { 1027 autoRemoveRecents = false; 1028 } else { 1029 autoRemoveRecents = true; 1030 } 1031 } else { 1032 autoRemoveRecents = false; 1033 } 1034 if (mResizeMode != info.resizeMode) { 1035 mResizeMode = info.resizeMode; 1036 updateTaskDescription(); 1037 } 1038 mSupportsPictureInPicture = info.supportsPictureInPicture(); 1039 stringName = null; 1040 1041 // Re-adding the task to Recents once updated 1042 if (inRecents) { 1043 mTaskSupervisor.mRecentTasks.remove(this); 1044 mTaskSupervisor.mRecentTasks.add(this); 1045 } 1046 } 1047 1048 /** Sets the original minimal width and height. */ setMinDimensions(ActivityInfo info)1049 void setMinDimensions(ActivityInfo info) { 1050 if (info != null && info.windowLayout != null) { 1051 mMinWidth = info.windowLayout.minWidth; 1052 mMinHeight = info.windowLayout.minHeight; 1053 } else { 1054 mMinWidth = INVALID_MIN_SIZE; 1055 mMinHeight = INVALID_MIN_SIZE; 1056 } 1057 } 1058 1059 /** 1060 * Return true if the input activity has the same intent filter as the intent this task 1061 * record is based on (normally the root activity intent). 1062 */ isSameIntentFilter(ActivityRecord r)1063 boolean isSameIntentFilter(ActivityRecord r) { 1064 final Intent intent = new Intent(r.intent); 1065 // Make sure the component are the same if the input activity has the same real activity 1066 // as the one in the task because either one of them could be the alias activity. 1067 if (Objects.equals(realActivity, r.mActivityComponent) && this.intent != null) { 1068 intent.setComponent(this.intent.getComponent()); 1069 if (intent.getSelector() == null) { 1070 // Make sure the package name the same to prevent one of the intent is set while the 1071 // other one is not. 1072 intent.setPackage(this.intent.getPackage()); 1073 } 1074 } 1075 return intent.filterEquals(this.intent); 1076 } 1077 returnsToHomeRootTask()1078 boolean returnsToHomeRootTask() { 1079 if (inMultiWindowMode() || !hasChild()) return false; 1080 if (intent != null) { 1081 final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME; 1082 if ((intent.getFlags() & returnHomeFlags) != returnHomeFlags) { 1083 return false; 1084 } 1085 final Task task = getDisplayArea() != null ? getDisplayArea().getRootHomeTask() : null; 1086 return !(task != null 1087 && mAtmService.getLockTaskController().isLockTaskModeViolation(task)); 1088 } 1089 final Task bottomTask = getBottomMostTask(); 1090 return bottomTask != this && bottomTask.returnsToHomeRootTask(); 1091 } 1092 setPrevAffiliate(Task prevAffiliate)1093 void setPrevAffiliate(Task prevAffiliate) { 1094 mPrevAffiliate = prevAffiliate; 1095 mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.mTaskId; 1096 } 1097 setNextAffiliate(Task nextAffiliate)1098 void setNextAffiliate(Task nextAffiliate) { 1099 mNextAffiliate = nextAffiliate; 1100 mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.mTaskId; 1101 } 1102 1103 @Override onParentChanged(ConfigurationContainer rawNewParent, ConfigurationContainer rawOldParent)1104 void onParentChanged(ConfigurationContainer rawNewParent, ConfigurationContainer rawOldParent) { 1105 final WindowContainer<?> newParent = (WindowContainer<?>) rawNewParent; 1106 final WindowContainer<?> oldParent = (WindowContainer<?>) rawOldParent; 1107 final DisplayContent display = newParent != null ? newParent.getDisplayContent() : null; 1108 final DisplayContent oldDisplay = oldParent != null ? oldParent.getDisplayContent() : null; 1109 1110 mPrevDisplayId = (oldDisplay != null) ? oldDisplay.mDisplayId : INVALID_DISPLAY; 1111 1112 if (oldParent != null && newParent == null) { 1113 cleanUpResourcesForDestroy(oldParent); 1114 } 1115 1116 if (display != null) { 1117 // TODO(b/168037178): Chat with the erosky@ of this code to see if this really makes 1118 // sense here... 1119 // Rotations are relative to the display. This means if there are 2 displays rotated 1120 // differently (eg. 2 monitors with one landscape and one portrait), moving a root task 1121 // from one to the other could look like a rotation change. To prevent this 1122 // apparent rotation change (and corresponding bounds rotation), pretend like our 1123 // current rotation is already the same as the new display. 1124 // Note, if Task or related logic ever gets nested, this logic will need 1125 // to move to onConfigurationChanged. 1126 getConfiguration().windowConfiguration.setRotation( 1127 display.getWindowConfiguration().getRotation()); 1128 } 1129 1130 super.onParentChanged(newParent, oldParent); 1131 1132 // Call this again after super onParentChanged in-case the surface wasn't created yet 1133 // (happens when the task is first inserted into the hierarchy). It's a no-op if it 1134 // already ran fully within super.onParentChanged 1135 updateTaskOrganizerState(); 1136 1137 if (oldParent != null) { 1138 final Task oldParentTask = oldParent.asTask(); 1139 if (oldParentTask != null) { 1140 forAllActivities(oldParentTask::cleanUpActivityReferences); 1141 1142 // Update the task description of the previous parent as well 1143 oldParentTask.updateTaskDescription(); 1144 } 1145 1146 if (newParent == null || !newParent.inPinnedWindowingMode()) { 1147 if (oldParent.inPinnedWindowingMode()) { 1148 // Notify if a task from the root pinned task is being removed 1149 // (or moved depending on the mode). 1150 mRootWindowContainer.notifyActivityPipModeChanged(this, null); 1151 } else if (inPinnedWindowingMode()) { 1152 // The task in pinned mode is removed, even though the old parent was not pinned 1153 // The task was most likely force killed or crashed 1154 Slog.e(TAG, "Pinned task is removed t=" + this); 1155 mRootWindowContainer.notifyActivityPipModeChanged(this, null); 1156 } 1157 } 1158 } 1159 1160 if (newParent != null) { 1161 // Surface of Task that will not be organized should be shown by default. 1162 // See Task#showSurfaceOnCreation 1163 if (!mCreatedByOrganizer && !canBeOrganized()) { 1164 getSyncTransaction().show(mSurfaceControl); 1165 } 1166 1167 // TODO: Ensure that this is actually necessary here 1168 // Notify the voice session if required 1169 if (voiceSession != null) { 1170 try { 1171 voiceSession.taskStarted(intent, mTaskId); 1172 } catch (RemoteException e) { 1173 } 1174 } 1175 1176 // Update the ancestor tasks' task description after reparenting 1177 updateTaskDescription(); 1178 } 1179 1180 // First time we are adding the task to the system. 1181 if (oldParent == null && newParent != null) { 1182 1183 // TODO: Super random place to be doing this, but aligns with what used to be done 1184 // before we unified Task level. Look into if this can be done in a better place. 1185 updateOverrideConfigurationFromLaunchBounds(); 1186 } 1187 1188 mRootWindowContainer.updateUIDsPresentOnDisplay(); 1189 } 1190 1191 @Override onResize()1192 void onResize() { 1193 super.onResize(); 1194 onTaskBoundsChangedForFreeform(); 1195 } 1196 1197 @Override onMovedByResize()1198 void onMovedByResize() { 1199 super.onMovedByResize(); 1200 onTaskBoundsChangedForFreeform(); 1201 } 1202 onTaskBoundsChangedForFreeform()1203 private void onTaskBoundsChangedForFreeform() { 1204 if (!isVisibleRequested() || !inFreeformWindowingMode()) { 1205 return; 1206 } 1207 1208 mAtmService.notifyTaskPersisterLocked(this, false /* flush */); 1209 1210 if (!com.android.window.flags.Flags.processPriorityPolicyForMultiWindowMode()) { 1211 return; 1212 } 1213 mRootWindowContainer.invalidateTaskLayersAndUpdateOomAdjIfNeeded(); 1214 } 1215 1216 @Override 1217 @Nullable getTopResumedActivity()1218 ActivityRecord getTopResumedActivity() { 1219 if (!isLeafTask()) { 1220 for (int i = mChildren.size() - 1; i >= 0; --i) { 1221 ActivityRecord resumedActivity = mChildren.get(i).asTask().getTopResumedActivity(); 1222 if (resumedActivity != null) { 1223 return resumedActivity; 1224 } 1225 } 1226 } 1227 1228 final ActivityRecord taskResumedActivity = getResumedActivity(); 1229 ActivityRecord topResumedActivity = null; 1230 for (int i = mChildren.size() - 1; i >= 0; --i) { 1231 final WindowContainer child = mChildren.get(i); 1232 if (child.asTaskFragment() != null) { 1233 topResumedActivity = child.asTaskFragment().getTopResumedActivity(); 1234 } else if (taskResumedActivity != null 1235 && child.asActivityRecord() == taskResumedActivity) { 1236 topResumedActivity = taskResumedActivity; 1237 } 1238 if (topResumedActivity != null) { 1239 return topResumedActivity; 1240 } 1241 } 1242 return null; 1243 } 1244 1245 @Override 1246 @Nullable getTopPausingActivity()1247 ActivityRecord getTopPausingActivity() { 1248 if (!isLeafTask()) { 1249 for (int i = mChildren.size() - 1; i >= 0; --i) { 1250 ActivityRecord pausingActivity = mChildren.get(i).asTask().getTopPausingActivity(); 1251 if (pausingActivity != null) { 1252 return pausingActivity; 1253 } 1254 } 1255 } 1256 1257 final ActivityRecord taskPausingActivity = getPausingActivity(); 1258 ActivityRecord topPausingActivity = null; 1259 for (int i = mChildren.size() - 1; i >= 0; --i) { 1260 final WindowContainer child = mChildren.get(i); 1261 if (child.asTaskFragment() != null) { 1262 topPausingActivity = child.asTaskFragment().getTopPausingActivity(); 1263 } else if (taskPausingActivity != null 1264 && child.asActivityRecord() == taskPausingActivity) { 1265 topPausingActivity = taskPausingActivity; 1266 } 1267 if (topPausingActivity != null) { 1268 return topPausingActivity; 1269 } 1270 } 1271 return null; 1272 } 1273 pauseActivityIfNeeded(@ullable ActivityRecord resuming, @NonNull String reason)1274 boolean pauseActivityIfNeeded(@Nullable ActivityRecord resuming, @NonNull String reason) { 1275 if (!isLeafTask()) { 1276 return false; 1277 } 1278 1279 final int[] someActivityPaused = {0}; 1280 // Check if the direct child resumed activity in the leaf task needed to be paused if 1281 // the leaf task is not a leaf task fragment. 1282 if (!isLeafTaskFragment()) { 1283 final ActivityRecord top = topRunningActivity(); 1284 final ActivityRecord resumedActivity = getResumedActivity(); 1285 if (resumedActivity != null 1286 && (top == null || top.getTaskFragment() != this || !canBeResumed(resuming))) { 1287 // Pausing the resumed activity because it is occluded by other task fragment, or 1288 // should not be remained in resumed state. 1289 if (startPausing(false /* uiSleeping*/, resuming, reason)) { 1290 someActivityPaused[0]++; 1291 } 1292 } 1293 } 1294 1295 forAllLeafTaskFragments((taskFrag) -> { 1296 final ActivityRecord resumedActivity = taskFrag.getResumedActivity(); 1297 if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) { 1298 if (taskFrag.startPausing(false /* uiSleeping*/, resuming, reason)) { 1299 someActivityPaused[0]++; 1300 } 1301 } 1302 }, true /* traverseTopToBottom */); 1303 1304 return someActivityPaused[0] > 0; 1305 } 1306 updateTaskMovement(boolean toTop, boolean toBottom, int position)1307 void updateTaskMovement(boolean toTop, boolean toBottom, int position) { 1308 EventLogTags.writeWmTaskMoved(mTaskId, getRootTaskId(), getDisplayId(), toTop ? 1 : 0, 1309 position); 1310 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 1311 if (taskDisplayArea != null) { 1312 taskDisplayArea.onTaskMoved(this, toTop, toBottom); 1313 } 1314 if (isPersistable) { 1315 mLastTimeMoved = System.currentTimeMillis(); 1316 } 1317 if (toTop && inRecents) { 1318 // If task is in recents, ensure it is at the top 1319 mTaskSupervisor.mRecentTasks.add(this); 1320 } 1321 } 1322 1323 // Close up recents linked list. closeRecentsChain()1324 private void closeRecentsChain() { 1325 if (mPrevAffiliate != null) { 1326 mPrevAffiliate.setNextAffiliate(mNextAffiliate); 1327 } 1328 if (mNextAffiliate != null) { 1329 mNextAffiliate.setPrevAffiliate(mPrevAffiliate); 1330 } 1331 setPrevAffiliate(null); 1332 setNextAffiliate(null); 1333 } 1334 removedFromRecents()1335 void removedFromRecents() { 1336 closeRecentsChain(); 1337 if (inRecents) { 1338 inRecents = false; 1339 mAtmService.notifyTaskPersisterLocked(this, false); 1340 } 1341 1342 clearRootProcess(); 1343 1344 mAtmService.mWindowManager.mTaskSnapshotController.removeAndDeleteSnapshot( 1345 mTaskId, mUserId); 1346 } 1347 setTaskToAffiliateWith(Task taskToAffiliateWith)1348 void setTaskToAffiliateWith(Task taskToAffiliateWith) { 1349 closeRecentsChain(); 1350 mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId; 1351 // Find the end 1352 while (taskToAffiliateWith.mNextAffiliate != null) { 1353 final Task nextRecents = taskToAffiliateWith.mNextAffiliate; 1354 if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) { 1355 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId=" 1356 + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId); 1357 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) { 1358 nextRecents.setPrevAffiliate(null); 1359 } 1360 taskToAffiliateWith.setNextAffiliate(null); 1361 break; 1362 } 1363 taskToAffiliateWith = nextRecents; 1364 } 1365 taskToAffiliateWith.setNextAffiliate(this); 1366 setPrevAffiliate(taskToAffiliateWith); 1367 setNextAffiliate(null); 1368 } 1369 1370 /** Returns the intent for the root activity for this task */ getBaseIntent()1371 Intent getBaseIntent() { 1372 if (intent != null) return intent; 1373 if (affinityIntent != null) return affinityIntent; 1374 // Probably a task that contains other tasks, so return the intent for the top task? 1375 final Task topTask = getTopMostTask(); 1376 return (topTask != this && topTask != null) ? topTask.getBaseIntent() : null; 1377 } 1378 1379 /** 1380 * Returns the package name which stands for this task. It is empty string if no activities 1381 * have been added to this task. 1382 */ 1383 @NonNull getBasePackageName()1384 String getBasePackageName() { 1385 final Intent intent = getBaseIntent(); 1386 if (intent == null) { 1387 return ""; 1388 } 1389 final ComponentName componentName = intent.getComponent(); 1390 return componentName != null ? componentName.getPackageName() : ""; 1391 } 1392 1393 /** Returns the first non-finishing activity from the bottom. */ getRootActivity()1394 ActivityRecord getRootActivity() { 1395 // TODO: Figure out why we historical ignore relinquish identity for this case... 1396 return getRootActivity(true /*ignoreRelinquishIdentity*/, false /*setToBottomIfNone*/); 1397 } 1398 getRootActivity(boolean setToBottomIfNone)1399 ActivityRecord getRootActivity(boolean setToBottomIfNone) { 1400 return getRootActivity(false /*ignoreRelinquishIdentity*/, setToBottomIfNone); 1401 } 1402 getRootActivity(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone)1403 ActivityRecord getRootActivity(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) { 1404 return mFindRootHelper.findRoot(ignoreRelinquishIdentity, setToBottomIfNone); 1405 } 1406 topRunningActivityLocked()1407 ActivityRecord topRunningActivityLocked() { 1408 if (getParent() == null) { 1409 return null; 1410 } 1411 return getActivity(ActivityRecord::canBeTopRunning); 1412 } 1413 1414 /** 1415 * Return true if any activities in this task belongs to input uid. 1416 */ isUidPresent(int uid)1417 boolean isUidPresent(int uid) { 1418 final PooledPredicate p = PooledLambda.obtainPredicate( 1419 ActivityRecord::isUid, PooledLambda.__(ActivityRecord.class), uid); 1420 final boolean isUidPresent = getActivity(p) != null; 1421 p.recycle(); 1422 return isUidPresent; 1423 } 1424 topStartingWindow()1425 WindowState topStartingWindow() { 1426 return getWindow(w -> w.mAttrs.type == TYPE_APPLICATION_STARTING); 1427 } 1428 topActivityContainsStartingWindow()1429 ActivityRecord topActivityContainsStartingWindow() { 1430 final WindowState startingWindow = topStartingWindow(); 1431 return startingWindow != null ? startingWindow.mActivityRecord : null; 1432 } 1433 1434 /** 1435 * Reorder the history task so that the passed activity is brought to the front. 1436 * @return whether it was actually moved (vs already being top). 1437 */ moveActivityToFront(ActivityRecord newTop)1438 final boolean moveActivityToFront(ActivityRecord newTop) { 1439 ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing and adding activity %s to root task at top " 1440 + "callers=%s", newTop, Debug.getCallers(4)); 1441 final TaskFragment taskFragment = newTop.getTaskFragment(); 1442 boolean moved; 1443 if (taskFragment != this) { 1444 if (taskFragment.isEmbedded() && taskFragment.getNonFinishingActivityCount() == 1) { 1445 taskFragment.mClearedForReorderActivityToFront = true; 1446 } 1447 newTop.reparent(this, POSITION_TOP); 1448 moved = true; 1449 if (taskFragment.isEmbedded()) { 1450 mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController 1451 .onActivityReparentedToTask(newTop); 1452 } 1453 } else { 1454 moved = moveChildToFront(newTop); 1455 } 1456 updateEffectiveIntent(); 1457 return moved; 1458 } 1459 1460 @Override addChild(WindowContainer child, int index)1461 void addChild(WindowContainer child, int index) { 1462 index = getAdjustedChildPosition(child, index); 1463 super.addChild(child, index); 1464 1465 ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this); 1466 1467 // A rootable task that is now being added to be the child of an organized task. Making 1468 // sure the root task references is keep updated. 1469 if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) { 1470 getDisplayArea().addRootTaskReferenceIfNeeded((Task) child); 1471 } 1472 1473 // Make sure the list of display UID allowlists is updated 1474 // now that this record is in a new task. 1475 mRootWindowContainer.updateUIDsPresentOnDisplay(); 1476 1477 // Only pass minimum dimensions for pure TaskFragment. Task's minimum dimensions must be 1478 // passed from Task constructor. 1479 final TaskFragment childTaskFrag = child.asTaskFragment(); 1480 if (childTaskFrag != null && childTaskFrag.asTask() == null) { 1481 if (childTaskFrag.mTaskFragmentOrganizerProcessName != null 1482 && mTaskFragmentHostProcessName == null) { 1483 mTaskFragmentHostUid = childTaskFrag.mTaskFragmentOrganizerUid; 1484 mTaskFragmentHostProcessName = childTaskFrag.mTaskFragmentOrganizerProcessName; 1485 } 1486 childTaskFrag.setMinDimensions(mMinWidth, mMinHeight); 1487 1488 // The starting window should keep covering its task when a pure TaskFragment is added 1489 // because its bounds may not fill the task. 1490 final ActivityRecord top = getTopMostActivity(); 1491 if (top != null && !top.hasFixedRotationTransform()) { 1492 top.associateStartingWindowWithTaskIfNeeded(); 1493 } 1494 } 1495 } 1496 1497 /** Called when an {@link ActivityRecord} is added as a descendant */ onDescendantActivityAdded(boolean hadActivity, int activityType, ActivityRecord r)1498 void onDescendantActivityAdded(boolean hadActivity, int activityType, ActivityRecord r) { 1499 warnForNonLeafTask("onDescendantActivityAdded"); 1500 1501 // Only set this based on the first activity 1502 if (!hadActivity) { 1503 int activityOverrideType = 1504 r.getRequestedOverrideConfiguration().windowConfiguration.getActivityType(); 1505 if (activityOverrideType == ACTIVITY_TYPE_UNDEFINED) { 1506 // Normally non-standard activity type for the activity record will be set when the 1507 // object is created, however we delay setting the standard application type until 1508 // this point so that the task can set the type for additional activities added in 1509 // the else condition below. 1510 activityOverrideType = activityType != ACTIVITY_TYPE_UNDEFINED ? activityType 1511 : ACTIVITY_TYPE_STANDARD; 1512 // Set the Activity's requestedOverrideConfiguration directly to reduce 1513 // WC#onConfigurationChanged calls since it will be called while setting the 1514 // Task's activity type below. 1515 r.getRequestedOverrideConfiguration().windowConfiguration.setActivityType( 1516 activityOverrideType); 1517 } 1518 setActivityType(activityOverrideType); 1519 isPersistable = r.isPersistable(); 1520 mCallingUid = r.launchedFromUid; 1521 mCallingPackage = r.launchedFromPackage; 1522 mCallingFeatureId = r.launchedFromFeatureId; 1523 // Clamp to [1, max]. 1524 maxRecents = Math.min(Math.max(r.info.maxRecents, 1), 1525 ActivityTaskManager.getMaxAppRecentsLimitStatic()); 1526 } else { 1527 // Otherwise make all added activities match this one. 1528 r.setActivityType(activityType); 1529 } 1530 1531 updateEffectiveIntent(); 1532 } 1533 1534 @Override removeChild(WindowContainer child)1535 void removeChild(WindowContainer child) { 1536 removeChild(child, "removeChild"); 1537 } 1538 removeChild(WindowContainer r, String reason)1539 void removeChild(WindowContainer r, String reason) { 1540 // A rootable child task that is now being removed from an organized task. Making sure 1541 // the root task references is keep updated. 1542 if (mCreatedByOrganizer && r.asTask() != null) { 1543 getDisplayArea().removeRootTaskReferenceIfNeeded((Task) r); 1544 } 1545 if (!mChildren.contains(r)) { 1546 Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this); 1547 return; 1548 } 1549 1550 if (DEBUG_TASK_MOVEMENT) { 1551 Slog.d(TAG_WM, "removeChild: child=" + r + " reason=" + reason); 1552 } 1553 super.removeChild(r, false /* removeSelfIfPossible */); 1554 1555 if (inPinnedWindowingMode()) { 1556 // We normally notify listeners of task stack changes on pause, however root pinned task 1557 // activities are normally in the paused state so no notification will be sent there 1558 // before the activity is removed. We send it here so instead. 1559 mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged(); 1560 } 1561 1562 if (mDecorSurfaceContainer != null && r == mDecorSurfaceContainer.mOwnerTaskFragment) { 1563 // Remove the decor surface if the owner TaskFragment is removed; 1564 removeDecorSurface(); 1565 } 1566 1567 if (hasChild()) { 1568 updateEffectiveIntent(); 1569 1570 // The following block can be executed multiple times if there is more than one overlay. 1571 // {@link ActivityTaskSupervisor#removeTaskByIdLocked} handles this by reverse lookup 1572 // of the task by id and exiting early if not found. 1573 if (onlyHasTaskOverlayActivities(true /*includeFinishing*/)) { 1574 // When destroying a task, tell the supervisor to remove it so that any activity it 1575 // has can be cleaned up correctly. This is currently the only place where we remove 1576 // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays 1577 // state into removeChild(), we just clear the task here before the other residual 1578 // work. 1579 // TODO: If the callers to removeChild() changes such that we have multiple places 1580 // where we are destroying the task, move this back into removeChild() 1581 mTaskSupervisor.removeTask(this, false /* killProcess */, 1582 !REMOVE_FROM_RECENTS, reason); 1583 } 1584 } else if (!mReuseTask && shouldRemoveSelfOnLastChildRemoval()) { 1585 reason += ", last child = " + r + " in " + this; 1586 removeIfPossible(reason); 1587 } 1588 } 1589 1590 /** 1591 * @return whether or not there are ONLY task overlay activities in the task. 1592 * If {@param includeFinishing} is set, then don't ignore finishing activities in the 1593 * check. If there are no task overlay activities, this call returns false. 1594 */ onlyHasTaskOverlayActivities(boolean includeFinishing)1595 boolean onlyHasTaskOverlayActivities(boolean includeFinishing) { 1596 int count = 0; 1597 for (int i = getChildCount() - 1; i >= 0; i--) { 1598 final ActivityRecord r = getChildAt(i).asActivityRecord(); 1599 if (r == null) { 1600 // Has a child that is other than Activity. 1601 return false; 1602 } 1603 if (!includeFinishing && r.finishing) { 1604 continue; 1605 } 1606 if (!r.isTaskOverlay()) { 1607 return false; 1608 } 1609 count++; 1610 } 1611 return count > 0; 1612 } 1613 shouldAutoRemoveFromRecents(TaskFragment oldParentFragment)1614 private boolean shouldAutoRemoveFromRecents(TaskFragment oldParentFragment) { 1615 // We will automatically remove the task either if it has explicitly asked for 1616 // this, or it is empty and has never contained an activity that got shown to 1617 // the user, or it was being embedded in another Task, or the display policy 1618 // doesn't allow recents, 1619 return autoRemoveRecents || (!hasChild() && !getHasBeenVisible()) 1620 || (oldParentFragment != null && oldParentFragment.isEmbedded()) 1621 || (mDisplayContent != null && !mDisplayContent.canShowTasksInHostDeviceRecents()); 1622 } 1623 clearPinnedTaskIfNeed()1624 private void clearPinnedTaskIfNeed() { 1625 // The original task is to be removed, try remove also the pinned task. 1626 if (mChildPipActivity != null && mChildPipActivity.getTask() != null) { 1627 mTaskSupervisor.removeRootTask(mChildPipActivity.getTask()); 1628 } 1629 } 1630 1631 /** Completely remove all activities associated with an existing task. */ removeActivities(String reason, boolean excludingTaskOverlay)1632 void removeActivities(String reason, boolean excludingTaskOverlay) { 1633 clearPinnedTaskIfNeed(); 1634 // Broken down into to cases to avoid object create due to capturing mStack. 1635 if (getRootTask() == null) { 1636 forAllActivities((r) -> { 1637 if (r.finishing || (excludingTaskOverlay && r.isTaskOverlay())) { 1638 return; 1639 } 1640 // Task was restored from persistent storage. 1641 r.takeFromHistory(); 1642 removeChild(r, reason); 1643 }); 1644 } else { 1645 final ArrayList<ActivityRecord> finishingActivities = new ArrayList<>(); 1646 forAllActivities(r -> { 1647 if (r.finishing || (excludingTaskOverlay && r.isTaskOverlay())) { 1648 return; 1649 } 1650 finishingActivities.add(r); 1651 }); 1652 1653 // Finish or destroy apps from the bottom to ensure that all the other activity have 1654 // been finished and the top task in another task gets resumed when a top activity is 1655 // removed. Otherwise, the next top activity could be started while the top activity 1656 // is removed, which is not necessary since the next top activity is on the same Task 1657 // and should also be removed. 1658 for (int i = finishingActivities.size() - 1; i >= 0; i--) { 1659 final ActivityRecord r = finishingActivities.get(i); 1660 1661 // Prevent the transition from being executed too early if the top activity is 1662 // resumed but the mVisibleRequested of any other activity is true, the transition 1663 // should wait until next activity resumed. 1664 if (r.isState(RESUMED) || r.isVisible()) { 1665 r.finishIfPossible(reason, false /* oomAdj */); 1666 } else { 1667 r.destroyIfPossible(reason); 1668 } 1669 } 1670 } 1671 } 1672 1673 /** 1674 * Completely remove all activities associated with an existing task. 1675 */ performClearTaskForReuse(boolean excludingTaskOverlay)1676 void performClearTaskForReuse(boolean excludingTaskOverlay) { 1677 mReuseTask = true; 1678 mTaskSupervisor.beginDeferResume(); 1679 try { 1680 removeActivities("clear-task-all", excludingTaskOverlay); 1681 } finally { 1682 mTaskSupervisor.endDeferResume(); 1683 mReuseTask = false; 1684 } 1685 } 1686 performClearTop(ActivityRecord newR, int launchFlags, int[] finishCount)1687 ActivityRecord performClearTop(ActivityRecord newR, int launchFlags, int[] finishCount) { 1688 // The task should be preserved for putting new activity in case the last activity is 1689 // finished if it is normal launch mode and not single top ("clear-task-top"). 1690 mReuseTask = true; 1691 mTaskSupervisor.beginDeferResume(); 1692 final ActivityRecord result; 1693 try { 1694 result = clearTopActivities(newR, launchFlags, finishCount); 1695 } finally { 1696 mTaskSupervisor.endDeferResume(); 1697 mReuseTask = false; 1698 } 1699 return result; 1700 } 1701 1702 /** 1703 * Perform clear operation as requested by 1704 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the 1705 * root task to the given task, then look for 1706 * an instance of that activity in the root task and, if found, finish all 1707 * activities on top of it and return the instance. 1708 * 1709 * @param newR Description of the new activity being started. 1710 * @param finishCount 1-element array that will be populated with the number of activities 1711 * that have been finished. 1712 * @return Returns the existing activity in the task that performs the clear-top operation, 1713 * or {@code null} if none was found. 1714 */ clearTopActivities(ActivityRecord newR, int launchFlags, int[] finishCount)1715 private ActivityRecord clearTopActivities(ActivityRecord newR, int launchFlags, 1716 int[] finishCount) { 1717 final ActivityRecord r = findActivityInHistory(newR.mActivityComponent, newR.mUserId); 1718 if (r == null) return null; 1719 1720 moveTaskFragmentsToBottomIfNeeded(r, finishCount); 1721 1722 final PooledPredicate f = PooledLambda.obtainPredicate( 1723 (ActivityRecord ar, ActivityRecord boundaryActivity) -> 1724 finishActivityAbove(ar, boundaryActivity, finishCount), 1725 PooledLambda.__(ActivityRecord.class), r); 1726 forAllActivities(f); 1727 f.recycle(); 1728 1729 // Finally, if this is a normal launch mode (that is, not expecting onNewIntent()), then we 1730 // will finish the current instance of the activity so a new fresh one can be started. 1731 if (r.launchMode == ActivityInfo.LAUNCH_MULTIPLE 1732 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0 1733 && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) { 1734 if (!r.finishing) { 1735 r.finishIfPossible("clear-task-top", false /* oomAdj */); 1736 } 1737 } 1738 1739 return r; 1740 } 1741 1742 /** 1743 * Moves {@link TaskFragment}s to the bottom if the flag 1744 * {@link TaskFragment#isMoveToBottomIfClearWhenLaunch} is {@code true}. 1745 */ 1746 @VisibleForTesting moveTaskFragmentsToBottomIfNeeded(@onNull ActivityRecord r, @NonNull int[] finishCount)1747 void moveTaskFragmentsToBottomIfNeeded(@NonNull ActivityRecord r, @NonNull int[] finishCount) { 1748 final int activityIndex = mChildren.indexOf(r); 1749 if (activityIndex < 0) { 1750 return; 1751 } 1752 1753 List<TaskFragment> taskFragmentsToMove = null; 1754 1755 // Find the TaskFragments that need to be moved 1756 for (int i = mChildren.size() - 1; i > activityIndex; i--) { 1757 final TaskFragment taskFragment = mChildren.get(i).asTaskFragment(); 1758 if (taskFragment != null && taskFragment.isMoveToBottomIfClearWhenLaunch()) { 1759 if (taskFragmentsToMove == null) { 1760 taskFragmentsToMove = new ArrayList<>(); 1761 } 1762 taskFragmentsToMove.add(taskFragment); 1763 } 1764 } 1765 if (taskFragmentsToMove == null) { 1766 return; 1767 } 1768 1769 // Move the TaskFragments to the bottom of the Task. Their relative orders are preserved. 1770 final int size = taskFragmentsToMove.size(); 1771 for (int i = 0; i < size; i++) { 1772 final TaskFragment taskFragment = taskFragmentsToMove.get(i); 1773 1774 // The visibility of the TaskFragment may change. Collect it in the transition so that 1775 // transition animation can be properly played. 1776 mTransitionController.collect(taskFragment); 1777 1778 positionChildAt(POSITION_BOTTOM, taskFragment, false /* includeParents */); 1779 } 1780 1781 // Treat it as if the TaskFragments are finished so that a transition animation can be 1782 // played to send the TaskFragments back and bring the activity to front. 1783 finishCount[0] += size; 1784 } 1785 finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity, @NonNull int[] finishCount)1786 private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity, 1787 @NonNull int[] finishCount) { 1788 // Stop operation once we reach the boundary activity. 1789 if (r == boundaryActivity) return true; 1790 1791 if (!r.finishing && !r.isTaskOverlay()) { 1792 final ActivityOptions opts = r.getOptions(); 1793 if (opts != null) { 1794 r.clearOptionsAnimation(); 1795 // TODO: Why is this updating the boundary activity vs. the current activity??? 1796 boundaryActivity.updateOptionsLocked(opts); 1797 } 1798 finishCount[0] += 1; 1799 r.finishIfPossible("clear-task-stack", false /* oomAdj */); 1800 } 1801 1802 return false; 1803 } 1804 lockTaskAuthToString()1805 String lockTaskAuthToString() { 1806 switch (mLockTaskAuth) { 1807 case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK"; 1808 case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE"; 1809 case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE"; 1810 case LOCK_TASK_AUTH_ALLOWLISTED: return "LOCK_TASK_AUTH_ALLOWLISTED"; 1811 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV"; 1812 default: return "unknown=" + mLockTaskAuth; 1813 } 1814 } 1815 setLockTaskAuth()1816 void setLockTaskAuth() { 1817 setLockTaskAuth(getRootActivity()); 1818 } 1819 setLockTaskAuth(@ullable ActivityRecord r)1820 private void setLockTaskAuth(@Nullable ActivityRecord r) { 1821 mLockTaskAuth = mAtmService.getLockTaskController().getLockTaskAuth(r, this); 1822 ProtoLog.d(WM_DEBUG_LOCKTASK, "setLockTaskAuth: task=%s mLockTaskAuth=%s", this, 1823 lockTaskAuthToString()); 1824 } 1825 supportsFreeform()1826 boolean supportsFreeform() { 1827 return supportsFreeformInDisplayArea(getDisplayArea()); 1828 } 1829 1830 /** 1831 * @return whether this task supports freeform multi-window if it is in the given 1832 * {@link TaskDisplayArea}. 1833 */ supportsFreeformInDisplayArea(@ullable TaskDisplayArea tda)1834 boolean supportsFreeformInDisplayArea(@Nullable TaskDisplayArea tda) { 1835 return mAtmService.mSupportsFreeformWindowManagement 1836 && supportsMultiWindowInDisplayArea(tda); 1837 } 1838 1839 /** Returns true if the task bounds should persist across power cycles. */ persistTaskBounds(@onNull WindowConfiguration configuration)1840 private static boolean persistTaskBounds(@NonNull WindowConfiguration configuration) { 1841 return configuration.getWindowingMode() == WINDOWING_MODE_FREEFORM; 1842 } 1843 1844 /** Returns true if the nested task is allowed to have independent bounds from its parent. */ allowIndependentBoundsFromParent( @onNull WindowConfiguration configuration)1845 private static boolean allowIndependentBoundsFromParent( 1846 @NonNull WindowConfiguration configuration) { 1847 return configuration.getWindowingMode() == WINDOWING_MODE_FREEFORM; 1848 } 1849 1850 /** 1851 * Check whether this task can be launched on the specified display. 1852 * 1853 * @param displayId Target display id. 1854 * @return {@code true} if either it is the default display or this activity can be put on a 1855 * secondary display. 1856 */ canBeLaunchedOnDisplay(int displayId)1857 boolean canBeLaunchedOnDisplay(int displayId) { 1858 return mTaskSupervisor.canPlaceEntityOnDisplay(displayId, 1859 -1 /* don't check PID */, -1 /* don't check UID */, this); 1860 } 1861 updateForceResizeOverrides(@onNull ActivityRecord r)1862 private void updateForceResizeOverrides(@NonNull ActivityRecord r) { 1863 final AppCompatResizeOverrides resizeOverrides = r.mAppCompatController 1864 .getResizeOverrides(); 1865 mForceResizeOverride = resizeOverrides.shouldOverrideForceResizeApp() 1866 || r.isUniversalResizeable() 1867 || r.mAppCompatController.getAspectRatioOverrides() 1868 .hasFullscreenOverride(); 1869 mForceNonResizeOverride = resizeOverrides.shouldOverrideForceNonResizeApp(); 1870 } 1871 1872 /** 1873 * Check that a given bounds matches the application requested orientation. 1874 * 1875 * @param bounds The bounds to be tested. 1876 * @return True if the requested bounds are okay for a resizing request. 1877 */ canResizeToBounds(Rect bounds)1878 private boolean canResizeToBounds(Rect bounds) { 1879 if (bounds == null || !inFreeformWindowingMode()) { 1880 // Note: If not on the freeform workspace, we ignore the bounds. 1881 return true; 1882 } 1883 final boolean landscape = bounds.width() > bounds.height(); 1884 final Rect configBounds = getRequestedOverrideBounds(); 1885 if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) { 1886 return configBounds.isEmpty() 1887 || landscape == (configBounds.width() > configBounds.height()); 1888 } 1889 return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape) 1890 && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape); 1891 } 1892 1893 /** 1894 * @return {@code true} if the task is being cleared for the purposes of being reused. 1895 */ isClearingToReuseTask()1896 boolean isClearingToReuseTask() { 1897 return mReuseTask; 1898 } 1899 1900 /** 1901 * Find the activity in the history task within the given task. Returns 1902 * the index within the history at which it's found, or < 0 if not found. 1903 */ findActivityInHistory(ComponentName component, int userId)1904 ActivityRecord findActivityInHistory(ComponentName component, int userId) { 1905 final PooledPredicate p = PooledLambda.obtainPredicate(Task::matchesActivityInHistory, 1906 PooledLambda.__(ActivityRecord.class), component, userId); 1907 final ActivityRecord r = getActivity(p); 1908 p.recycle(); 1909 return r; 1910 } 1911 matchesActivityInHistory( ActivityRecord r, ComponentName activityComponent, int userId)1912 private static boolean matchesActivityInHistory( 1913 ActivityRecord r, ComponentName activityComponent, int userId) { 1914 return !r.finishing && r.mActivityComponent.equals(activityComponent) 1915 && r.mUserId == userId; 1916 } 1917 1918 /** Updates the last task description values. */ updateTaskDescription()1919 void updateTaskDescription() { 1920 final ActivityRecord root = getRootActivity(true); 1921 if (root == null) return; 1922 1923 final TaskDescription taskDescription = new TaskDescription(); 1924 final PooledPredicate f = PooledLambda.obtainPredicate( 1925 Task::setTaskDescriptionFromActivityAboveRoot, 1926 PooledLambda.__(ActivityRecord.class), root, taskDescription); 1927 forAllActivities(f); 1928 f.recycle(); 1929 taskDescription.setResizeMode(mResizeMode); 1930 taskDescription.setMinWidth(mMinWidth); 1931 taskDescription.setMinHeight(mMinHeight); 1932 setTaskDescription(taskDescription); 1933 mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged( 1934 getTaskInfo()); 1935 1936 final WindowContainer parent = getParent(); 1937 if (parent != null) { 1938 final Task t = parent.asTask(); 1939 if (t != null) { 1940 t.updateTaskDescription(); 1941 } 1942 } 1943 1944 dispatchTaskInfoChangedIfNeeded(false /* force */); 1945 } 1946 setTaskDescriptionFromActivityAboveRoot( ActivityRecord r, ActivityRecord root, TaskDescription td)1947 private static boolean setTaskDescriptionFromActivityAboveRoot( 1948 ActivityRecord r, ActivityRecord root, TaskDescription td) { 1949 if (!r.isTaskOverlay() && r.taskDescription != null) { 1950 final TaskDescription atd = r.taskDescription; 1951 if (td.getLabel() == null) { 1952 td.setLabel(atd.getLabel()); 1953 } 1954 if (td.getRawIcon() == null) { 1955 td.setIcon(atd.getRawIcon()); 1956 } 1957 if (td.getIconFilename() == null) { 1958 td.setIconFilename(atd.getIconFilename()); 1959 } 1960 if (td.getPrimaryColor() == 0) { 1961 td.setPrimaryColor(atd.getPrimaryColor()); 1962 } 1963 if (td.getBackgroundColor() == 0) { 1964 td.setBackgroundColor(atd.getBackgroundColor()); 1965 } 1966 if (td.getStatusBarColor() == 0) { 1967 td.setStatusBarColor(atd.getStatusBarColor()); 1968 td.setEnsureStatusBarContrastWhenTransparent( 1969 atd.getEnsureStatusBarContrastWhenTransparent()); 1970 } 1971 if (td.getSystemBarsAppearance() == 0) { 1972 td.setSystemBarsAppearance(atd.getSystemBarsAppearance()); 1973 } 1974 if (td.getTopOpaqueSystemBarsAppearance() == 0 && r.fillsParent()) { 1975 td.setTopOpaqueSystemBarsAppearance(atd.getSystemBarsAppearance()); 1976 } 1977 if (td.getNavigationBarColor() == 0) { 1978 td.setNavigationBarColor(atd.getNavigationBarColor()); 1979 td.setEnsureNavigationBarContrastWhenTransparent( 1980 atd.getEnsureNavigationBarContrastWhenTransparent()); 1981 } 1982 if (td.getBackgroundColorFloating() == 0) { 1983 td.setBackgroundColorFloating(atd.getBackgroundColorFloating()); 1984 } 1985 } 1986 1987 // End search once we get to root. 1988 return r == root; 1989 } 1990 1991 // TODO (AM refactor): Invoke automatically when there is a change in children 1992 @VisibleForTesting updateEffectiveIntent()1993 void updateEffectiveIntent() { 1994 final ActivityRecord root = getRootActivity(true /*setToBottomIfNone*/); 1995 if (root != null) { 1996 setIntent(root); 1997 // Update the task description when the activities change 1998 updateTaskDescription(); 1999 } 2000 } 2001 setLastNonFullscreenBounds(Rect bounds)2002 void setLastNonFullscreenBounds(Rect bounds) { 2003 if (mLastNonFullscreenBounds == null) { 2004 mLastNonFullscreenBounds = new Rect(bounds); 2005 } else { 2006 mLastNonFullscreenBounds.set(bounds); 2007 } 2008 } 2009 onConfigurationChangedInner(Configuration newParentConfig)2010 private void onConfigurationChangedInner(Configuration newParentConfig) { 2011 // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so 2012 // restore the last recorded non-fullscreen bounds. 2013 final boolean prevPersistTaskBounds = persistTaskBounds(getWindowConfiguration()); 2014 boolean nextPersistTaskBounds = persistTaskBounds( 2015 getRequestedOverrideConfiguration().windowConfiguration); 2016 if (getRequestedOverrideWindowingMode() == WINDOWING_MODE_UNDEFINED) { 2017 nextPersistTaskBounds = persistTaskBounds(newParentConfig.windowConfiguration); 2018 } 2019 // Only restore to the last non-fullscreen bounds when the requested override bounds 2020 // have not been explicitly set already. 2021 nextPersistTaskBounds &= 2022 (getRequestedOverrideConfiguration().windowConfiguration.getBounds() == null 2023 || getRequestedOverrideConfiguration().windowConfiguration.getBounds().isEmpty()); 2024 if (!prevPersistTaskBounds && nextPersistTaskBounds 2025 && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) { 2026 // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop. 2027 getRequestedOverrideConfiguration().windowConfiguration 2028 .setBounds(mLastNonFullscreenBounds); 2029 } 2030 2031 final int prevWinMode = getWindowingMode(); 2032 mTmpPrevBounds.set(getBounds()); 2033 final boolean wasInMultiWindowMode = inMultiWindowMode(); 2034 final boolean wasInPictureInPicture = inPinnedWindowingMode(); 2035 super.onConfigurationChanged(newParentConfig); 2036 if (mDisplayContent == null) { 2037 // This should be initializing from Task.Builder. The onConfigurationChanged will be 2038 // called again when this task is attached to hierarchy. Early return here because the 2039 // following operations are no-op for a non-attached task. 2040 return; 2041 } 2042 // Only need to update surface size here since the super method will handle updating 2043 // surface position. 2044 updateSurfaceSize(getSyncTransaction()); 2045 2046 final boolean pipChanging = wasInPictureInPicture != inPinnedWindowingMode(); 2047 if (pipChanging) { 2048 mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, getRootTask()); 2049 } else if (wasInMultiWindowMode != inMultiWindowMode()) { 2050 mTaskSupervisor.scheduleUpdateMultiWindowMode(this); 2051 } 2052 2053 if (shouldStartChangeTransition(prevWinMode, mTmpPrevBounds)) { 2054 mTransitionController.collectVisibleChange(this); 2055 } 2056 2057 // If the configuration supports persistent bounds (eg. Freeform), keep track of the 2058 // current (non-fullscreen) bounds for persistence. 2059 if (persistTaskBounds(getWindowConfiguration())) { 2060 final Rect currentBounds = getRequestedOverrideBounds(); 2061 if (!currentBounds.isEmpty()) { 2062 setLastNonFullscreenBounds(currentBounds); 2063 } 2064 } 2065 2066 if (pipChanging && wasInPictureInPicture 2067 && !mTransitionController.isShellTransitionsEnabled()) { 2068 // If the top activity is changing from PiP to fullscreen with fixed rotation, 2069 // clear the crop and rotation matrix of task because fixed rotation will handle 2070 // the transformation on activity level. This also avoids flickering caused by the 2071 // latency of fullscreen task organizer configuring the surface. 2072 final ActivityRecord r = topRunningActivity(); 2073 if (r != null && mDisplayContent.isFixedRotationLaunchingApp(r)) { 2074 resetSurfaceControlTransforms(); 2075 } 2076 } 2077 2078 saveLaunchingStateIfNeeded(); 2079 final boolean taskOrgChanged = updateTaskOrganizerState(); 2080 if (taskOrgChanged) { 2081 updateSurfacePosition(getSyncTransaction()); 2082 if (!isOrganized()) { 2083 // Surface-size update was skipped before (since internally it no-ops if 2084 // isOrganized() is true); however, now that this is not organized, the surface 2085 // size needs to be updated by WM. 2086 updateSurfaceSize(getSyncTransaction()); 2087 } 2088 } 2089 // If the task organizer has changed, then it will already be receiving taskAppeared with 2090 // the latest task-info thus the task-info won't have changed. 2091 if (!taskOrgChanged) { 2092 dispatchTaskInfoChangedIfNeeded(false /* force */); 2093 } 2094 } 2095 2096 @Override onConfigurationChanged(Configuration newParentConfig)2097 public void onConfigurationChanged(Configuration newParentConfig) { 2098 if (mDisplayContent != null 2099 && mDisplayContent.mPinnedTaskController.isFreezingTaskConfig(this)) { 2100 // It happens when animating from fullscreen to PiP with orientation change. Because 2101 // the activity in this pinned task is in fullscreen windowing mode (see 2102 // RootWindowContainer#moveActivityToPinnedRootTask) and the activity will be set to 2103 // pinned mode after the animation is done, the configuration change by orientation 2104 // change is just an intermediate state that should be ignored to avoid flickering. 2105 return; 2106 } 2107 // Calling Task#onConfigurationChanged() for leaf task since the ops in this method are 2108 // particularly for root tasks, like preventing bounds changes when inheriting certain 2109 // windowing mode. 2110 if (!isRootTask()) { 2111 onConfigurationChangedInner(newParentConfig); 2112 return; 2113 } 2114 2115 final int prevWindowingMode = getWindowingMode(); 2116 final boolean prevIsAlwaysOnTop = isAlwaysOnTop(); 2117 final int prevRotation = getWindowConfiguration().getRotation(); 2118 final Rect newBounds = mTmpRect; 2119 // Initialize the new bounds by previous bounds as the input and output for calculating 2120 // override bounds in pinned (pip) or split-screen mode. 2121 getBounds(newBounds); 2122 2123 onConfigurationChangedInner(newParentConfig); 2124 2125 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 2126 if (taskDisplayArea == null) { 2127 return; 2128 } 2129 2130 if (prevWindowingMode != getWindowingMode()) { 2131 taskDisplayArea.onRootTaskWindowingModeChanged(this); 2132 } 2133 2134 if (!isOrganized() && !getRequestedOverrideBounds().isEmpty() && mDisplayContent != null) { 2135 // If the parent (display) has rotated, rotate our bounds to best-fit where their 2136 // bounds were on the pre-rotated display. 2137 final int newRotation = getWindowConfiguration().getRotation(); 2138 final boolean rotationChanged = prevRotation != newRotation; 2139 if (rotationChanged) { 2140 mDisplayContent.rotateBounds(prevRotation, newRotation, newBounds); 2141 setBounds(newBounds); 2142 } 2143 } 2144 2145 if (prevIsAlwaysOnTop != isAlwaysOnTop()) { 2146 // Since always on top is only on when the root task is freeform or pinned, the state 2147 // can be toggled when the windowing mode changes. We must make sure the root task is 2148 // placed properly when always on top state changes. 2149 taskDisplayArea.positionChildAt(POSITION_TOP, this, false /* includingParents */); 2150 } 2151 } 2152 resolveLeafTaskOnlyOverrideConfigs(Configuration newParentConfig, Rect previousBounds)2153 void resolveLeafTaskOnlyOverrideConfigs(Configuration newParentConfig, Rect previousBounds) { 2154 if (!isLeafTask()) { 2155 return; 2156 } 2157 2158 int windowingMode = 2159 getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode(); 2160 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 2161 windowingMode = newParentConfig.windowConfiguration.getWindowingMode(); 2162 } 2163 // Commit the resolved windowing mode so the canSpecifyOrientation won't get the old 2164 // mode that may cause the bounds to be miscalculated, e.g. letterboxed. 2165 getConfiguration().windowConfiguration.setWindowingMode(windowingMode); 2166 Rect outOverrideBounds = getResolvedOverrideConfiguration().windowConfiguration.getBounds(); 2167 2168 if (windowingMode == WINDOWING_MODE_FULLSCREEN) { 2169 if (!mCreatedByOrganizer) { 2170 // Use empty bounds to indicate "fill parent". 2171 outOverrideBounds.setEmpty(); 2172 } 2173 // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if 2174 // the parent or display is smaller than the size, the content may be cropped. 2175 return; 2176 } 2177 2178 adjustForMinimalTaskDimensions(outOverrideBounds, previousBounds, newParentConfig); 2179 if (windowingMode == WINDOWING_MODE_FREEFORM) { 2180 computeFreeformBounds(outOverrideBounds, newParentConfig); 2181 return; 2182 } 2183 } 2184 adjustForMinimalTaskDimensions(@onNull Rect bounds, @NonNull Rect previousBounds, @NonNull Configuration parentConfig)2185 void adjustForMinimalTaskDimensions(@NonNull Rect bounds, @NonNull Rect previousBounds, 2186 @NonNull Configuration parentConfig) { 2187 // If the task has no requested minimal size, we'd like to enforce a minimal size 2188 // so that the user can not render the task fragment too small to manipulate. We don't need 2189 // to do this for the root pinned task as the bounds are controlled by the system. 2190 if (inPinnedWindowingMode()) { 2191 Slog.i(TAG, "Skip adjustForMinimalTaskDimensions for pip task"); 2192 return; 2193 } 2194 2195 int minWidth = mMinWidth; 2196 int minHeight = mMinHeight; 2197 // Use Display specific min sizes when there is one associated with this Task. 2198 final int defaultMinSizeDp = mDisplayContent == null 2199 ? DEFAULT_MIN_TASK_SIZE_DP : mDisplayContent.mMinSizeOfResizeableTaskDp; 2200 final float density = (float) parentConfig.densityDpi / DisplayMetrics.DENSITY_DEFAULT; 2201 final int defaultMinSize = (int) (defaultMinSizeDp * density); 2202 2203 if (minWidth == INVALID_MIN_SIZE) { 2204 minWidth = defaultMinSize; 2205 } 2206 if (minHeight == INVALID_MIN_SIZE) { 2207 minHeight = defaultMinSize; 2208 } 2209 2210 if (bounds.isEmpty()) { 2211 // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they 2212 // do, we can just skip. 2213 final Rect parentBounds = parentConfig.windowConfiguration.getBounds(); 2214 if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) { 2215 return; 2216 } 2217 bounds.set(parentBounds); 2218 } 2219 final boolean adjustWidth = minWidth > bounds.width(); 2220 final boolean adjustHeight = minHeight > bounds.height(); 2221 if (!(adjustWidth || adjustHeight)) { 2222 return; 2223 } 2224 2225 if (adjustWidth) { 2226 if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) { 2227 bounds.left = bounds.right - minWidth; 2228 } else { 2229 // Either left bounds match, or neither match, or the previous bounds were 2230 // fullscreen and we default to keeping left. 2231 bounds.right = bounds.left + minWidth; 2232 } 2233 } 2234 if (adjustHeight) { 2235 if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) { 2236 bounds.top = bounds.bottom - minHeight; 2237 } else { 2238 // Either top bounds match, or neither match, or the previous bounds were 2239 // fullscreen and we default to keeping top. 2240 bounds.bottom = bounds.top + minHeight; 2241 } 2242 } 2243 } 2244 2245 /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FREEFORM}. */ computeFreeformBounds(@onNull Rect outBounds, @NonNull Configuration newParentConfig)2246 private void computeFreeformBounds(@NonNull Rect outBounds, 2247 @NonNull Configuration newParentConfig) { 2248 // by policy, make sure the window remains within parent somewhere 2249 final float density = 2250 ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT; 2251 final Rect parentBounds = 2252 new Rect(newParentConfig.windowConfiguration.getBounds()); 2253 final DisplayContent display = getDisplayContent(); 2254 if (display != null) { 2255 // If a freeform window moves below system bar, there is no way to move it again 2256 // by touch. Because its caption is covered by system bar. So we exclude them 2257 // from root task bounds. and then caption will be shown inside stable area. 2258 final Rect stableBounds = new Rect(); 2259 display.getStableRect(stableBounds); 2260 parentBounds.intersect(stableBounds); 2261 } 2262 2263 fitWithinBounds(outBounds, parentBounds, 2264 (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP), 2265 (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP)); 2266 2267 // Prevent to overlap caption with stable insets. 2268 final int offsetTop = parentBounds.top - outBounds.top; 2269 if (offsetTop > 0) { 2270 outBounds.offset(0, offsetTop); 2271 } 2272 } 2273 2274 /** 2275 * Adjusts bounds to stay within root task bounds. 2276 * 2277 * Since bounds might be outside of root task bounds, this method tries to move the bounds in 2278 * a way that keep them unchanged, but be contained within the root task bounds. 2279 * 2280 * @param bounds Bounds to be adjusted. 2281 * @param rootTaskBounds Bounds within which the other bounds should remain. 2282 * @param overlapPxX The amount of px required to be visible in the X dimension. 2283 * @param overlapPxY The amount of px required to be visible in the Y dimension. 2284 */ fitWithinBounds(Rect bounds, Rect rootTaskBounds, int overlapPxX, int overlapPxY)2285 private static void fitWithinBounds(Rect bounds, Rect rootTaskBounds, int overlapPxX, 2286 int overlapPxY) { 2287 if (rootTaskBounds == null || rootTaskBounds.isEmpty() || rootTaskBounds.contains(bounds)) { 2288 return; 2289 } 2290 2291 // For each side of the parent (eg. left), check if the opposing side of the window (eg. 2292 // right) is at least overlap pixels away. If less, offset the window by that difference. 2293 int horizontalDiff = 0; 2294 // If window is smaller than overlap, use it's smallest dimension instead 2295 int overlapLR = Math.min(overlapPxX, bounds.width()); 2296 if (bounds.right < (rootTaskBounds.left + overlapLR)) { 2297 horizontalDiff = overlapLR - (bounds.right - rootTaskBounds.left); 2298 } else if (bounds.left > (rootTaskBounds.right - overlapLR)) { 2299 horizontalDiff = -(overlapLR - (rootTaskBounds.right - bounds.left)); 2300 } 2301 int verticalDiff = 0; 2302 int overlapTB = Math.min(overlapPxY, bounds.width()); 2303 if (bounds.bottom < (rootTaskBounds.top + overlapTB)) { 2304 verticalDiff = overlapTB - (bounds.bottom - rootTaskBounds.top); 2305 } else if (bounds.top > (rootTaskBounds.bottom - overlapTB)) { 2306 verticalDiff = -(overlapTB - (rootTaskBounds.bottom - bounds.top)); 2307 } 2308 bounds.offset(horizontalDiff, verticalDiff); 2309 } 2310 shouldStartChangeTransition(int prevWinMode, @NonNull Rect prevBounds)2311 private boolean shouldStartChangeTransition(int prevWinMode, @NonNull Rect prevBounds) { 2312 if (!(isLeafTask() || mCreatedByOrganizer) || !canStartChangeTransition()) { 2313 return false; 2314 } 2315 final int newWinMode = getWindowingMode(); 2316 if (mTransitionController.inTransition(this)) { 2317 final Rect newBounds = getConfiguration().windowConfiguration.getBounds(); 2318 return prevWinMode != newWinMode || prevBounds.width() != newBounds.width() 2319 || prevBounds.height() != newBounds.height(); 2320 } 2321 // Only do an animation into and out-of freeform mode for now. Other mode 2322 // transition animations are currently handled by system-ui. 2323 return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM); 2324 } 2325 2326 @Override migrateToNewSurfaceControl(SurfaceControl.Transaction t)2327 void migrateToNewSurfaceControl(SurfaceControl.Transaction t) { 2328 super.migrateToNewSurfaceControl(t); 2329 mLastSurfaceSize.x = 0; 2330 mLastSurfaceSize.y = 0; 2331 updateSurfaceSize(t); 2332 } 2333 updateSurfaceSize(SurfaceControl.Transaction transaction)2334 void updateSurfaceSize(SurfaceControl.Transaction transaction) { 2335 if (mSurfaceControl == null || isOrganized()) { 2336 return; 2337 } 2338 2339 // Apply crop to root tasks only and clear the crops of the descendant tasks. 2340 int width = 0; 2341 int height = 0; 2342 if (isRootTask() && !mTransitionController.mIsWaitingForDisplayEnabled) { 2343 final Rect taskBounds = getBounds(); 2344 width = taskBounds.width(); 2345 height = taskBounds.height(); 2346 } 2347 if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) { 2348 return; 2349 } 2350 transaction.setWindowCrop(mSurfaceControl, width, height); 2351 mLastSurfaceSize.set(width, height); 2352 } 2353 2354 @Override writeIdentifierToProto(ProtoOutputStream proto, long fieldId)2355 void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { 2356 final long token = proto.start(fieldId); 2357 proto.write(HASH_CODE, System.identityHashCode(this)); 2358 proto.write(USER_ID, mUserId); 2359 proto.write(TITLE, intent != null && intent.getComponent() != null 2360 ? intent.getComponent().flattenToShortString() : "Task"); 2361 proto.end(token); 2362 } 2363 2364 /** 2365 * Saves launching state if necessary so that we can launch the activity to its latest state. 2366 */ saveLaunchingStateIfNeeded()2367 private void saveLaunchingStateIfNeeded() { 2368 saveLaunchingStateIfNeeded(getDisplayContent()); 2369 } 2370 saveLaunchingStateIfNeeded(DisplayContent display)2371 private void saveLaunchingStateIfNeeded(DisplayContent display) { 2372 if (!isLeafTask()) { 2373 return; 2374 } 2375 2376 if (!getHasBeenVisible()) { 2377 // Not ever visible to user. 2378 return; 2379 } 2380 2381 final int windowingMode = getWindowingMode(); 2382 if (windowingMode != WINDOWING_MODE_FULLSCREEN 2383 && windowingMode != WINDOWING_MODE_FREEFORM) { 2384 return; 2385 } 2386 2387 // Don't persist state if Task Display Area isn't in freeform mode. Then the task will be 2388 // launched back to its last state in a freeform Task Display Area when it's launched in a 2389 // freeform Task Display Area next time. 2390 if (getTaskDisplayArea() == null 2391 || getTaskDisplayArea().getWindowingMode() != WINDOWING_MODE_FREEFORM) { 2392 return; 2393 } 2394 2395 // Saves the new state so that we can launch the activity at the same location. 2396 mTaskSupervisor.mLaunchParamsPersister.saveTask(this, display); 2397 } 2398 updateOverrideConfigurationFromLaunchBounds()2399 void updateOverrideConfigurationFromLaunchBounds() { 2400 final Task rootTask = getRootTask(); 2401 final boolean hasParentTask = rootTask != this; 2402 final int windowingMode = getWindowingMode(); 2403 final boolean isNonStandardOrFullscreen = !isActivityTypeStandardOrUndefined() 2404 || windowingMode == WINDOWING_MODE_FULLSCREEN; 2405 if (!Flags.nestedTasksWithIndependentBounds() 2406 && !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue()) { 2407 final Rect bounds; 2408 if (hasParentTask && rootTask.isOrganized()) { 2409 bounds = null; 2410 } else if (isNonStandardOrFullscreen) { 2411 bounds = isResizeable() ? rootTask.getRequestedOverrideBounds() : null; 2412 } else if (!persistTaskBounds(getWindowConfiguration())) { 2413 bounds = rootTask.getRequestedOverrideBounds(); 2414 } else { 2415 bounds = mLastNonFullscreenBounds; 2416 } 2417 setBounds(bounds); 2418 return; 2419 } 2420 2421 // Non-standard/fullscreen unresizable tasks should always inherit. 2422 boolean shouldInheritBounds = isNonStandardOrFullscreen && !isResizeable(); 2423 // Task itself is not organized (e.g. Home), just inherit from its organized parent. 2424 shouldInheritBounds |= hasParentTask && rootTask.isOrganized() && !isOrganized(); 2425 // Nested tasks should inherit when they're not allowed to have independent bounds, such as 2426 // in multi-window split-screen. 2427 shouldInheritBounds |= hasParentTask 2428 && !(allowIndependentBoundsFromParent(getWindowConfiguration()) 2429 && persistTaskBounds(getWindowConfiguration())); 2430 if (shouldInheritBounds) { 2431 setBounds(null); 2432 return; 2433 } 2434 if (!hasParentTask && !persistTaskBounds(getWindowConfiguration())) { 2435 // Non-nested, non-persistable tasks such as PIP or multi-window floating windows. 2436 return; 2437 } 2438 // Non-nested, persisted tasks (e.g. top-level freeform) or nested persisted tasks that 2439 // allow independent bounds from parent (e.g. nested freeform) should use launch-params 2440 // bounds set to |mLastNonFullscreenBounds|. 2441 setBounds(mLastNonFullscreenBounds); 2442 } 2443 setRootProcess(WindowProcessController proc)2444 void setRootProcess(WindowProcessController proc) { 2445 clearRootProcess(); 2446 if (intent != null 2447 && (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) { 2448 mRootProcess = proc; 2449 mRootProcess.addRecentTask(this); 2450 } 2451 } 2452 clearRootProcess()2453 void clearRootProcess() { 2454 if (mRootProcess != null) { 2455 mRootProcess.removeRecentTask(this); 2456 mRootProcess = null; 2457 } 2458 } 2459 2460 /** @return Id of root task. */ getRootTaskId()2461 int getRootTaskId() { 2462 return getRootTask().mTaskId; 2463 } 2464 2465 /** @return the first organized task. */ 2466 @Nullable getOrganizedTask()2467 Task getOrganizedTask() { 2468 if (isOrganized()) { 2469 return this; 2470 } 2471 final WindowContainer parent = getParent(); 2472 if (parent == null) { 2473 return null; 2474 } 2475 final Task parentTask = parent.asTask(); 2476 return parentTask == null ? null : parentTask.getOrganizedTask(); 2477 } 2478 2479 /** @return the first create-by-organizer task. */ 2480 @Nullable getCreatedByOrganizerTask()2481 Task getCreatedByOrganizerTask() { 2482 if (mCreatedByOrganizer) { 2483 return this; 2484 } 2485 final WindowContainer parent = getParent(); 2486 if (parent == null) { 2487 return null; 2488 } 2489 final Task parentTask = parent.asTask(); 2490 return parentTask == null ? null : parentTask.getCreatedByOrganizerTask(); 2491 } 2492 2493 /** Finds the first Task parent (or itself) that has adjacent. */ 2494 @Nullable getTaskWithAdjacent()2495 Task getTaskWithAdjacent() { 2496 if (hasAdjacentTaskFragment()) { 2497 return this; 2498 } 2499 final WindowContainer parent = getParent(); 2500 if (parent == null || parent.asTask() == null) { 2501 return null; 2502 } 2503 return parent.asTask().getTaskWithAdjacent(); 2504 } 2505 2506 /** Returns true if this or its parent has adjacent Task. */ hasAdjacentTask()2507 boolean hasAdjacentTask() { 2508 return getTaskWithAdjacent() != null; 2509 } 2510 2511 /** 2512 * Finds the first Task parent (or itself) that has adjacent. Runs callback on all the adjacent 2513 * Tasks. The invoke order is not guaranteed. 2514 */ forOtherAdjacentTasks(@onNull Consumer<Task> callback)2515 void forOtherAdjacentTasks(@NonNull Consumer<Task> callback) { 2516 final Task taskWithAdjacent = getTaskWithAdjacent(); 2517 if (taskWithAdjacent == null) { 2518 return; 2519 } 2520 final AdjacentSet adjacentTasks = taskWithAdjacent.getAdjacentTaskFragments(); 2521 adjacentTasks.forAllTaskFragments(tf -> { 2522 // We don't support Task adjacent to non-Task TaskFragment. 2523 callback.accept(tf.asTask()); 2524 }, taskWithAdjacent /* exclude */); 2525 } 2526 2527 /** 2528 * Finds the first Task parent (or itself) that has adjacent. Runs callback on all the adjacent 2529 * Tasks. Returns early if callback returns true on any of them. The invoke order is not 2530 * guaranteed. 2531 */ forOtherAdjacentTasks(@onNull Predicate<Task> callback)2532 boolean forOtherAdjacentTasks(@NonNull Predicate<Task> callback) { 2533 final Task taskWithAdjacent = getTaskWithAdjacent(); 2534 if (taskWithAdjacent == null) { 2535 return false; 2536 } 2537 final AdjacentSet adjacentTasks = taskWithAdjacent.getAdjacentTaskFragments(); 2538 return adjacentTasks.forAllTaskFragments(tf -> { 2539 // We don't support Task adjacent to non-Task TaskFragment. 2540 return callback.test(tf.asTask()); 2541 }, taskWithAdjacent /* exclude */); 2542 } 2543 2544 // TODO(task-merge): Figure out what's the right thing to do for places that used it. isRootTask()2545 boolean isRootTask() { 2546 return getRootTask() == this; 2547 } 2548 isLeafTask()2549 boolean isLeafTask() { 2550 for (int i = mChildren.size() - 1; i >= 0; --i) { 2551 if (mChildren.get(i).asTask() != null) { 2552 return false; 2553 } 2554 } 2555 return true; 2556 } 2557 2558 /** Return the top-most leaf-task under this one, or this task if it is a leaf. */ getTopLeafTask()2559 public Task getTopLeafTask() { 2560 for (int i = mChildren.size() - 1; i >= 0; --i) { 2561 final Task child = mChildren.get(i).asTask(); 2562 if (child == null) continue; 2563 return child.getTopLeafTask(); 2564 } 2565 return this; 2566 } 2567 getDescendantTaskCount()2568 int getDescendantTaskCount() { 2569 final int[] currentCount = {0}; 2570 forAllLeafTasks(t -> currentCount[0]++, false /* traverseTopToBottom */); 2571 return currentCount[0]; 2572 } 2573 2574 /** 2575 * Find next proper focusable root task and make it focused. 2576 * @return The root task that now got the focus, {@code null} if none found. 2577 */ adjustFocusToNextFocusableTask(String reason)2578 Task adjustFocusToNextFocusableTask(String reason) { 2579 return adjustFocusToNextFocusableTask(reason, false /* allowFocusSelf */, 2580 true /* moveDisplayToTop */); 2581 } 2582 2583 /** Return the next focusable task by looking from the siblings and parent tasks */ getNextFocusableTask(boolean allowFocusSelf)2584 private Task getNextFocusableTask(boolean allowFocusSelf) { 2585 final WindowContainer parent = getParent(); 2586 if (parent == null) { 2587 return null; 2588 } 2589 2590 final Task focusableTask = parent.getTask((task) -> (allowFocusSelf || task != this) 2591 && ((Task) task).isFocusableAndVisible()); 2592 if (focusableTask == null && parent.asTask() != null) { 2593 return parent.asTask().getNextFocusableTask(allowFocusSelf); 2594 } else { 2595 return focusableTask; 2596 } 2597 } 2598 2599 /** 2600 * Find next proper focusable task and make it focused. 2601 * @param reason The reason of making the adjustment. 2602 * @param allowFocusSelf Is the focus allowed to remain on the same task. 2603 * @param moveDisplayToTop Whether to move display to top while making the task focused. 2604 * @return The root task that now got the focus, {@code null} if none found. 2605 */ adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf, boolean moveDisplayToTop)2606 Task adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf, 2607 boolean moveDisplayToTop) { 2608 Task focusableTask = getNextFocusableTask(allowFocusSelf); 2609 if (focusableTask == null) { 2610 focusableTask = mRootWindowContainer.getNextFocusableRootTask(this, !allowFocusSelf); 2611 } 2612 if (focusableTask == null) { 2613 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 2614 if (taskDisplayArea != null) { 2615 // Clear the recorded task since there is no next focusable task. 2616 taskDisplayArea.clearPreferredTopFocusableRootTask(); 2617 } 2618 return null; 2619 } 2620 2621 final Task rootTask = focusableTask.getRootTask(); 2622 if (!moveDisplayToTop) { 2623 // There may be multiple task layers above this task, so when relocating the task to the 2624 // top, we should move this task and each of its parent task that below display area to 2625 // the top of each layer. 2626 WindowContainer parent = focusableTask.getParent(); 2627 WindowContainer next = focusableTask; 2628 do { 2629 parent.positionChildAt(POSITION_TOP, next, false /* includingParents */); 2630 next = parent; 2631 parent = next.getParent(); 2632 } while (next.asTask() != null && parent != null); 2633 return rootTask; 2634 } 2635 2636 final String myReason = reason + " adjustFocusToNextFocusableTask"; 2637 final ActivityRecord top = focusableTask.topRunningActivity(); 2638 if (focusableTask.isActivityTypeHome() && (top == null || !top.isVisibleRequested())) { 2639 // If we will be focusing on the root home task next and its current top activity isn't 2640 // visible, then use the move the root home task to top to make the activity visible. 2641 focusableTask.getDisplayArea().moveHomeActivityToTop(myReason); 2642 return rootTask; 2643 } 2644 2645 // Move the entire hierarchy to top with updating global top resumed activity 2646 // and focused application if needed. 2647 focusableTask.moveToFront(myReason); 2648 // Top display focused root task is changed, update top resumed activity if needed. 2649 if (rootTask.getTopResumedActivity() != null) { 2650 mTaskSupervisor.updateTopResumedActivityIfNeeded(reason); 2651 } 2652 return rootTask; 2653 } 2654 2655 /** Calculate the minimum possible position for a task that can be shown to the user. 2656 * The minimum position will be above all other tasks that can't be shown. 2657 * @param minPosition The minimum position the caller is suggesting. 2658 * We will start adjusting up from here. 2659 * @param size The size of the current task list. 2660 */ 2661 // TODO: Move user to their own window container. computeMinUserPosition(int minPosition, int size)2662 private int computeMinUserPosition(int minPosition, int size) { 2663 while (minPosition < size) { 2664 final WindowContainer child = mChildren.get(minPosition); 2665 final boolean canShow = child.showToCurrentUser(); 2666 if (canShow) { 2667 break; 2668 } 2669 minPosition++; 2670 } 2671 return minPosition; 2672 } 2673 2674 /** Calculate the maximum possible position for a task that can't be shown to the user. 2675 * The maximum position will be below all other tasks that can be shown. 2676 * @param maxPosition The maximum position the caller is suggesting. 2677 * We will start adjusting down from here. 2678 */ 2679 // TODO: Move user to their own window container. computeMaxUserPosition(int maxPosition)2680 private int computeMaxUserPosition(int maxPosition) { 2681 while (maxPosition > 0) { 2682 final WindowContainer child = mChildren.get(maxPosition); 2683 final boolean canShow = child.showToCurrentUser(); 2684 if (!canShow) { 2685 break; 2686 } 2687 maxPosition--; 2688 } 2689 return maxPosition; 2690 } 2691 getAdjustedChildPosition(WindowContainer wc, int suggestedPosition)2692 private int getAdjustedChildPosition(WindowContainer wc, int suggestedPosition) { 2693 final boolean canShowChild = wc.showToCurrentUser(); 2694 2695 final int size = mChildren.size(); 2696 2697 // Figure-out min/max possible position depending on if child can show for current user. 2698 int minPosition = (canShowChild) ? computeMinUserPosition(0, size) : 0; 2699 int maxPosition = minPosition; 2700 if (size > 0) { 2701 maxPosition = (canShowChild) ? size - 1 : computeMaxUserPosition(size - 1); 2702 } 2703 2704 // Factor in always-on-top children in max possible position. 2705 if (!wc.isAlwaysOnTop()) { 2706 // We want to place all non-always-on-top containers below always-on-top ones. 2707 while (maxPosition > minPosition) { 2708 if (!mChildren.get(maxPosition).isAlwaysOnTop()) break; 2709 --maxPosition; 2710 } 2711 } 2712 2713 // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid. 2714 if (suggestedPosition == POSITION_BOTTOM && minPosition == 0) { 2715 return POSITION_BOTTOM; 2716 } else if (suggestedPosition == POSITION_TOP && maxPosition >= (size - 1)) { 2717 return POSITION_TOP; 2718 } 2719 2720 // Increase the maxPosition because children size will grow once wc is added. 2721 if (!hasChild(wc)) { 2722 ++maxPosition; 2723 } 2724 2725 // Reset position based on minimum/maximum possible positions. 2726 return Math.min(Math.max(suggestedPosition, minPosition), maxPosition); 2727 } 2728 2729 @Override positionChildAt(int position, WindowContainer child, boolean includingParents)2730 void positionChildAt(int position, WindowContainer child, boolean includingParents) { 2731 final boolean toTop = position >= (mChildren.size() - 1); 2732 position = getAdjustedChildPosition(child, position); 2733 super.positionChildAt(position, child, includingParents); 2734 2735 // Log positioning. 2736 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "positionChildAt: child=" + child 2737 + " position=" + position + " parent=" + this); 2738 2739 final Task task = child.asTask(); 2740 if (task != null) { 2741 task.updateTaskMovement(toTop, position == POSITION_BOTTOM, position); 2742 } 2743 } 2744 2745 @Override removeImmediately()2746 void removeImmediately() { 2747 removeImmediately("removeTask"); 2748 } 2749 2750 @Override removeImmediately(String reason)2751 void removeImmediately(String reason) { 2752 if (DEBUG_ROOT_TASK) Slog.i(TAG, "removeTask:" + reason + " removing taskId=" + mTaskId); 2753 if (mRemoving) { 2754 return; 2755 } 2756 mRemoving = true; 2757 2758 EventLogTags.writeWmTaskRemoved(mTaskId, getRootTaskId(), getDisplayId(), reason); 2759 clearPinnedTaskIfNeed(); 2760 if (mChildPipActivity != null) { 2761 mChildPipActivity.clearLastParentBeforePip(); 2762 } 2763 // If applicable let the TaskOrganizer know the Task is vanishing. 2764 setTaskOrganizer(null); 2765 if (mDecorSurfaceContainer != null) { 2766 mDecorSurfaceContainer.release(); 2767 } 2768 2769 super.removeImmediately(); 2770 mDisplayContent = null; 2771 mRemoving = false; 2772 } 2773 2774 // TODO: Consolidate this with Task.reparent() reparent(Task rootTask, int position, boolean moveParents, String reason)2775 void reparent(Task rootTask, int position, boolean moveParents, String reason) { 2776 if (DEBUG_ROOT_TASK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId 2777 + " from rootTask=" + getRootTask()); 2778 EventLogTags.writeWmTaskRemoved(mTaskId, getRootTaskId(), getDisplayId(), 2779 "reParentTask:" + reason); 2780 2781 reparent(rootTask, position); 2782 2783 rootTask.positionChildAt(position, this, moveParents); 2784 } 2785 setBounds(Rect bounds, boolean forceResize)2786 public int setBounds(Rect bounds, boolean forceResize) { 2787 final int boundsChanged = setBounds(bounds); 2788 2789 if (forceResize && (boundsChanged & BOUNDS_CHANGE_SIZE) != BOUNDS_CHANGE_SIZE) { 2790 onResize(); 2791 return BOUNDS_CHANGE_SIZE | boundsChanged; 2792 } 2793 2794 return boundsChanged; 2795 } 2796 2797 /** Set the task bounds. Passing in null sets the bounds to fullscreen. */ 2798 @Override setBounds(Rect bounds)2799 public int setBounds(Rect bounds) { 2800 if (isRootTask()) { 2801 return setBounds(getRequestedOverrideBounds(), bounds); 2802 } 2803 2804 final int boundsChange = super.setBounds(bounds); 2805 updateSurfacePositionNonOrganized(); 2806 return boundsChange; 2807 } 2808 2809 /** Sets the requested bounds regardless of the windowing mode. */ setBoundsUnchecked(@onNull Rect bounds)2810 int setBoundsUnchecked(@NonNull Rect bounds) { 2811 final int boundsChange = super.setBounds(bounds); 2812 updateSurfaceBounds(); 2813 return boundsChange; 2814 } 2815 2816 @Override isCompatible(int windowingMode, int activityType)2817 public boolean isCompatible(int windowingMode, int activityType) { 2818 // TODO: Should we just move this to ConfigurationContainer? 2819 if (activityType == ACTIVITY_TYPE_UNDEFINED) { 2820 // Undefined activity types end up in a standard root task once the root task is 2821 // created on a display, so they should be considered compatible. 2822 activityType = ACTIVITY_TYPE_STANDARD; 2823 } 2824 return super.isCompatible(windowingMode, activityType); 2825 } 2826 2827 @Override onDescendantOrientationChanged(WindowContainer requestingContainer)2828 public boolean onDescendantOrientationChanged(WindowContainer requestingContainer) { 2829 if (super.onDescendantOrientationChanged(requestingContainer)) { 2830 return true; 2831 } 2832 2833 // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill 2834 // it if possible. 2835 if (getParent() != null) { 2836 onConfigurationChanged(getParent().getConfiguration()); 2837 return true; 2838 } 2839 return false; 2840 } 2841 2842 @Override handlesOrientationChangeFromDescendant(@creenOrientation int orientation)2843 boolean handlesOrientationChangeFromDescendant(@ScreenOrientation int orientation) { 2844 if (!super.handlesOrientationChangeFromDescendant(orientation)) { 2845 return false; 2846 } 2847 2848 // At task level, we want to check canSpecifyOrientation() based on the top activity type. 2849 // Do this only on leaf Task, so that the result is not affecting by the sibling leaf Task. 2850 // Otherwise, root Task will use the result from the top leaf Task, and all its child 2851 // leaf Tasks will rely on that from super.handlesOrientationChangeFromDescendant(). 2852 if (!isLeafTask()) { 2853 return true; 2854 } 2855 2856 // Check for leaf Task. 2857 // Display won't rotate for the orientation request if the Task/TaskDisplayArea 2858 // can't specify orientation. 2859 return canSpecifyOrientation() && getDisplayArea().canSpecifyOrientation(orientation); 2860 } 2861 2862 @Override onDisplayChanged(DisplayContent dc)2863 void onDisplayChanged(DisplayContent dc) { 2864 final int lastDisplayId = getDisplayId(); 2865 super.onDisplayChanged(dc); 2866 if (isLeafTask()) { 2867 final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY; 2868 //Send the callback when the task reparented to another display. 2869 if (lastDisplayId != displayId) { 2870 mWmService.mAtmService.getTaskChangeNotificationController() 2871 .notifyTaskDisplayChanged(mTaskId, displayId); 2872 } 2873 } 2874 if (isRootTask()) { 2875 updateSurfaceBounds(); 2876 } 2877 sendTaskFragmentParentInfoChangedIfNeeded(); 2878 } 2879 isResizeable()2880 boolean isResizeable() { 2881 return isResizeable(/* checkPictureInPictureSupport */ true); 2882 } 2883 isResizeable(boolean checkPictureInPictureSupport)2884 boolean isResizeable(boolean checkPictureInPictureSupport) { 2885 final boolean forceResizable = mAtmService.mForceResizableActivities 2886 && getActivityType() == ACTIVITY_TYPE_STANDARD; 2887 if (forceResizable) return true; 2888 if (mForceNonResizeOverride) return false; 2889 return mForceResizeOverride || ActivityInfo.isResizeableMode(mResizeMode) 2890 || (mSupportsPictureInPicture && checkPictureInPictureSupport); 2891 } 2892 2893 /** 2894 * Tests if the orientation should be preserved upon user interactive resizig operations. 2895 2896 * @return true if orientation should not get changed upon resizing operation. 2897 */ preserveOrientationOnResize()2898 boolean preserveOrientationOnResize() { 2899 return mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY 2900 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY 2901 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; 2902 } 2903 cropWindowsToRootTaskBounds()2904 boolean cropWindowsToRootTaskBounds() { 2905 // Don't crop HOME/RECENTS windows to root task bounds. This is because in split-screen 2906 // they extend past their root task and sysui uses the root task surface to control 2907 // cropping. 2908 // TODO(b/158242495): get rid of this when drag/drop can use surface bounds. 2909 if (isActivityTypeHomeOrRecents()) { 2910 // Make sure this is the top-most non-organizer root task (if not top-most, it means 2911 // another translucent task could be above this, so this needs to stay cropped. 2912 final Task rootTask = getRootTask(); 2913 final Task topNonOrgTask = 2914 rootTask.mCreatedByOrganizer ? rootTask.getTopMostTask() : rootTask; 2915 if (this == topNonOrgTask || isDescendantOf(topNonOrgTask)) { 2916 return false; 2917 } 2918 } 2919 return isResizeable(); 2920 } 2921 2922 @Override getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, Rect outSurfaceInsets)2923 void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, 2924 Rect outSurfaceInsets) { 2925 // If this task has its adjacent task, it means they should animate together. Use display 2926 // bounds for them could move same as full screen task. 2927 if (hasAdjacentTask()) { 2928 super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); 2929 return; 2930 } 2931 2932 final WindowState windowState = getTopVisibleAppMainWindow(); 2933 if (windowState != null) { 2934 windowState.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); 2935 } else { 2936 super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); 2937 } 2938 } 2939 setDragResizing(boolean dragResizing)2940 void setDragResizing(boolean dragResizing) { 2941 if (mDragResizing != dragResizing) { 2942 // No need to check if allowed if it's leaving dragResize 2943 if (dragResizing 2944 && !(getRootTask().getWindowConfiguration().canResizeTask())) { 2945 Slog.e(TAG, "Drag resize isn't allowed for root task id=" + getRootTaskId()); 2946 return; 2947 } 2948 mDragResizing = dragResizing; 2949 resetDragResizingChangeReported(); 2950 } 2951 } 2952 isDragResizing()2953 boolean isDragResizing() { 2954 return mDragResizing; 2955 } 2956 2957 /** Cancels any running app transitions associated with the task. */ cancelTaskWindowTransition()2958 void cancelTaskWindowTransition() { 2959 for (int i = mChildren.size() - 1; i >= 0; --i) { 2960 mChildren.get(i).cancelAnimation(); 2961 } 2962 } 2963 showForAllUsers()2964 boolean showForAllUsers() { 2965 if (mChildren.isEmpty()) return false; 2966 final ActivityRecord r = getTopNonFinishingActivity(); 2967 return r != null && r.mShowForAllUsers; 2968 } 2969 2970 @Override showToCurrentUser()2971 boolean showToCurrentUser() { 2972 return mForceShowForAllUsers || showForAllUsers() 2973 || mWmService.isUserVisible(getTopMostTask().mUserId); 2974 } 2975 setForceShowForAllUsers(boolean forceShowForAllUsers)2976 void setForceShowForAllUsers(boolean forceShowForAllUsers) { 2977 mForceShowForAllUsers = forceShowForAllUsers; 2978 } 2979 2980 /** Returns the top-most activity that occludes the given one, or {@code null} if none. */ 2981 @Nullable getOccludingActivityAbove(ActivityRecord activity)2982 ActivityRecord getOccludingActivityAbove(ActivityRecord activity) { 2983 final ActivityRecord top = getActivity(r -> { 2984 if (r == activity) { 2985 // Reached the given activity, return the activity to stop searching. 2986 return true; 2987 } 2988 2989 if (!r.occludesParent()) { 2990 return false; 2991 } 2992 2993 TaskFragment parent = r.getTaskFragment(); 2994 if (parent == activity.getTaskFragment()) { 2995 // Found it. This activity on top of the given activity on the same TaskFragment. 2996 return true; 2997 } 2998 if (parent != null && parent.asTask() != null) { 2999 // Found it. This activity is the direct child of a leaf Task. 3000 return true; 3001 } 3002 // The candidate activity is being embedded. Checking if the bounds of the containing 3003 // TaskFragment equals to the outer TaskFragment. 3004 TaskFragment grandParent = parent.getParent().asTaskFragment(); 3005 while (grandParent != null) { 3006 if (!parent.getBounds().equals(grandParent.getBounds())) { 3007 // Not occluding the grandparent. 3008 break; 3009 } 3010 if (grandParent.asTask() != null) { 3011 // Found it. The activity occludes its parent TaskFragment and the parent 3012 // TaskFragment also occludes its parent all the way up. 3013 return true; 3014 } 3015 parent = grandParent; 3016 grandParent = parent.getParent().asTaskFragment(); 3017 } 3018 return false; 3019 }); 3020 return top != activity ? top : null; 3021 } 3022 3023 @Override makeAnimationLeash()3024 public SurfaceControl.Builder makeAnimationLeash() { 3025 return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId); 3026 } 3027 shouldAnimate()3028 boolean shouldAnimate() { 3029 /** 3030 * Animations are handled by the TaskOrganizer implementation. 3031 */ 3032 if (isOrganized()) { 3033 return false; 3034 } 3035 return true; 3036 } 3037 3038 @Override setInitialSurfaceControlProperties(SurfaceControl.Builder b)3039 void setInitialSurfaceControlProperties(SurfaceControl.Builder b) { 3040 b.setEffectLayer().setMetadata(METADATA_TASK_ID, mTaskId); 3041 super.setInitialSurfaceControlProperties(b); 3042 } 3043 3044 /** Checking if self or its child tasks are animated by recents animation. */ isAnimatingByRecents()3045 boolean isAnimatingByRecents() { 3046 return mTransitionController.isTransientHide(this); 3047 } 3048 getTopVisibleAppMainWindow()3049 WindowState getTopVisibleAppMainWindow() { 3050 final ActivityRecord activity = getTopVisibleActivity(); 3051 return activity != null ? activity.findMainWindow() : null; 3052 } 3053 topRunningNonDelayedActivityLocked(ActivityRecord notTop)3054 ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) { 3055 final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunningNonDelayed 3056 , PooledLambda.__(ActivityRecord.class), notTop); 3057 final ActivityRecord r = getActivity(p); 3058 p.recycle(); 3059 return r; 3060 } 3061 isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop)3062 private static boolean isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop) { 3063 return !r.delayedResume && r != notTop && r.canBeTopRunning(); 3064 } 3065 3066 /** 3067 * This is a simplified version of topRunningActivity that provides a number of 3068 * optional skip-over modes. It is intended for use with the ActivityController hook only. 3069 * 3070 * @param token If non-null, any history records matching this token will be skipped. 3071 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID. 3072 * 3073 * @return Returns the HistoryRecord of the next activity on the root task. 3074 */ topRunningActivity(IBinder token, int taskId)3075 ActivityRecord topRunningActivity(IBinder token, int taskId) { 3076 final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunning, 3077 PooledLambda.__(ActivityRecord.class), taskId, token); 3078 final ActivityRecord r = getActivity(p); 3079 p.recycle(); 3080 return r; 3081 } 3082 isTopRunning(ActivityRecord r, int taskId, IBinder notTop)3083 private static boolean isTopRunning(ActivityRecord r, int taskId, IBinder notTop) { 3084 return r.getTask().mTaskId != taskId && r.token != notTop && r.canBeTopRunning(); 3085 } 3086 3087 @Nullable getTopFullscreenMainWindow()3088 WindowState getTopFullscreenMainWindow() { 3089 return getWindow(w -> w.mAttrs.type == TYPE_BASE_APPLICATION && w.mAttrs.isFullscreen()); 3090 } 3091 3092 /** 3093 * Return the top visible requested activity. The activity has been requested to be visible, 3094 * but it's possible that the activity has just been created, so no window is yet attached to 3095 * this activity. 3096 */ getTopVisibleActivity()3097 ActivityRecord getTopVisibleActivity() { 3098 return getActivity((r) -> !r.mIsExiting && r.isClientVisible() && r.isVisibleRequested()); 3099 } 3100 3101 /** 3102 * Return the top visible activity. The activity has a window on which contents are drawn. 3103 * However it's possible that the activity has already been requested to be invisible, but the 3104 * visibility is not yet committed. 3105 */ getTopRealVisibleActivity()3106 ActivityRecord getTopRealVisibleActivity() { 3107 return getActivity((r) -> !r.mIsExiting && r.isClientVisible() && r.isVisible()); 3108 } 3109 getTopWaitSplashScreenActivity()3110 ActivityRecord getTopWaitSplashScreenActivity() { 3111 return getActivity((r) -> { 3112 return r.mHandleExitSplashScreen 3113 && r.mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_COPYING; 3114 }); 3115 } 3116 3117 void setTaskDescription(TaskDescription taskDescription) { 3118 mTaskDescription = taskDescription; 3119 } 3120 3121 void onSnapshotChanged(TaskSnapshot snapshot) { 3122 mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged( 3123 mTaskId, snapshot); 3124 } 3125 3126 void onSnapshotInvalidated() { 3127 mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotInvalidated(mTaskId); 3128 } 3129 3130 3131 TaskDescription getTaskDescription() { 3132 return mTaskDescription; 3133 } 3134 3135 @Override 3136 void forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom) { 3137 final int count = mChildren.size(); 3138 boolean isLeafTask = true; 3139 if (traverseTopToBottom) { 3140 for (int i = count - 1; i >= 0; --i) { 3141 final Task child = mChildren.get(i).asTask(); 3142 if (child != null) { 3143 isLeafTask = false; 3144 child.forAllLeafTasks(callback, traverseTopToBottom); 3145 } 3146 } 3147 } else { 3148 for (int i = 0; i < count; i++) { 3149 final Task child = mChildren.get(i).asTask(); 3150 if (child != null) { 3151 isLeafTask = false; 3152 child.forAllLeafTasks(callback, traverseTopToBottom); 3153 } 3154 } 3155 } 3156 if (isLeafTask) callback.accept(this); 3157 } 3158 3159 @Override 3160 void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom) { 3161 super.forAllTasks(callback, traverseTopToBottom); 3162 callback.accept(this); 3163 } 3164 3165 @Override 3166 void forAllRootTasks(Consumer<Task> callback, boolean traverseTopToBottom) { 3167 if (isRootTask()) { 3168 callback.accept(this); 3169 } 3170 } 3171 3172 @Override 3173 boolean forAllTasks(Predicate<Task> callback) { 3174 if (super.forAllTasks(callback)) return true; 3175 return callback.test(this); 3176 } 3177 3178 @Override 3179 boolean forAllLeafTasks(Predicate<Task> callback) { 3180 boolean isLeafTask = true; 3181 for (int i = mChildren.size() - 1; i >= 0; --i) { 3182 final Task child = mChildren.get(i).asTask(); 3183 if (child != null) { 3184 isLeafTask = false; 3185 if (child.forAllLeafTasks(callback)) { 3186 return true; 3187 } 3188 } 3189 } 3190 if (isLeafTask) { 3191 return callback.test(this); 3192 } 3193 return false; 3194 } 3195 3196 /** Iterates through all leaf task fragments and the leaf tasks. */ 3197 void forAllLeafTasksAndLeafTaskFragments(final Consumer<TaskFragment> callback, 3198 boolean traverseTopToBottom) { 3199 forAllLeafTasks(task -> { 3200 if (task.isLeafTaskFragment()) { 3201 callback.accept(task); 3202 return; 3203 } 3204 3205 // A leaf task that may contains both activities and task fragments. 3206 boolean consumed = false; 3207 if (traverseTopToBottom) { 3208 for (int i = task.mChildren.size() - 1; i >= 0; --i) { 3209 final WindowContainer child = task.mChildren.get(i); 3210 if (child.asTaskFragment() != null) { 3211 child.forAllLeafTaskFragments(callback, traverseTopToBottom); 3212 } else if (child.asActivityRecord() != null && !consumed) { 3213 callback.accept(task); 3214 consumed = true; 3215 } 3216 } 3217 } else { 3218 for (int i = 0; i < task.mChildren.size(); i++) { 3219 final WindowContainer child = task.mChildren.get(i); 3220 if (child.asTaskFragment() != null) { 3221 child.forAllLeafTaskFragments(callback, traverseTopToBottom); 3222 } else if (child.asActivityRecord() != null && !consumed) { 3223 callback.accept(task); 3224 consumed = true; 3225 } 3226 } 3227 } 3228 }, traverseTopToBottom); 3229 } 3230 3231 @Override 3232 boolean forAllRootTasks(Predicate<Task> callback, boolean traverseTopToBottom) { 3233 return isRootTask() ? callback.test(this) : false; 3234 } 3235 3236 @Override 3237 Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) { 3238 final Task t = super.getTask(callback, traverseTopToBottom); 3239 if (t != null) return t; 3240 return callback.test(this) ? this : null; 3241 } 3242 3243 @Nullable 3244 @Override 3245 Task getRootTask(Predicate<Task> callback, boolean traverseTopToBottom) { 3246 return isRootTask() && callback.test(this) ? this : null; 3247 } 3248 3249 void dontAnimateDimExit() { 3250 mDimmer.dontAnimateExit(); 3251 } 3252 3253 String getName() { 3254 return "Task=" + mTaskId; 3255 } 3256 3257 @Deprecated 3258 @Override 3259 Dimmer getDimmer() { 3260 // If the window is in multi-window mode, we want to dim at the Task level to ensure the dim 3261 // bounds match the area the app lives in 3262 if (inMultiWindowMode()) { 3263 return mDimmer; 3264 } 3265 3266 // If we're not at the root task level, we want to keep traversing through the parents to 3267 // find the root. 3268 // Once at the root task level, we want to check {@link #isTranslucent(ActivityRecord)}. 3269 // If true, we want to get the Dimmer from the level above since we don't want to animate 3270 // the dim with the Task. 3271 if (!isRootTask() || isTranslucentAndVisible() 3272 || (Flags.getDimmerOnClosing() ? isTranslucentForTransition() 3273 : isTranslucent(null))) { 3274 return super.getDimmer(); 3275 } 3276 3277 return mDimmer; 3278 } 3279 3280 boolean isSuitableForDimming() { 3281 // If the window is in multi-window mode, we want to dim at the Task level to ensure the dim 3282 // bounds match the area the app lives in. 3283 // If translucent, we will move the dim to the display area 3284 return inMultiWindowMode() || !isTranslucentAndVisible(); 3285 } 3286 3287 @Override 3288 void prepareSurfaces() { 3289 mDimmer.resetDimStates(); 3290 super.prepareSurfaces(); 3291 3292 Rect dimBounds = null; 3293 if (!Flags.useTasksDimOnly()) { 3294 dimBounds = mDimmer.getDimBounds(); 3295 if (dimBounds != null) { 3296 getDimBounds(dimBounds); 3297 3298 // Bounds need to be relative, as the dim layer is a child. 3299 if (inFreeformWindowingMode()) { 3300 getBounds(mTmpRect); 3301 dimBounds.offset(-mTmpRect.left, -mTmpRect.top); 3302 } else { 3303 dimBounds.offsetTo(0, 0); 3304 } 3305 } 3306 } 3307 3308 final SurfaceControl.Transaction t = getSyncTransaction(); 3309 3310 if (mDimmer.hasDimState() && mDimmer.updateDims(t)) { 3311 scheduleAnimation(); 3312 } 3313 3314 // Let organizer manage task visibility for shell transition. So don't change it's 3315 // visibility during collecting. 3316 if (mTransitionController.isCollecting() && mCreatedByOrganizer) { 3317 return; 3318 } 3319 3320 // We intend to let organizer manage task visibility but it doesn't 3321 // have enough information until we finish shell transitions. 3322 // In the mean time we do an easy fix here. 3323 final boolean visible = isVisible(); 3324 final boolean show = visible || isAnimating(TRANSITION | PARENTS | CHILDREN); 3325 if (mSurfaceControl != null) { 3326 if (show != mLastSurfaceShowing) { 3327 t.setVisibility(mSurfaceControl, show); 3328 } 3329 } 3330 // Only show the overlay if the task has other visible children 3331 if (mOverlayHost != null) { 3332 mOverlayHost.setVisibility(t, visible); 3333 } 3334 mLastSurfaceShowing = show; 3335 } 3336 3337 /** 3338 * Fills in a {@link TaskInfo} with information from this task. Note that the base intent in the 3339 * task info will not include any extras or clip data. 3340 */ 3341 void fillTaskInfo(TaskInfo info) { 3342 fillTaskInfo(info, true /* stripExtras */); 3343 } 3344 3345 void fillTaskInfo(TaskInfo info, boolean stripExtras) { 3346 fillTaskInfo(info, stripExtras, getDisplayArea()); 3347 } 3348 3349 /** 3350 * Fills in a {@link TaskInfo} with information from this task. 3351 * 3352 * @param tda consider whether this Task can be put in multi window as it will be attached to 3353 * the give {@link TaskDisplayArea}. 3354 */ 3355 void fillTaskInfo(TaskInfo info, boolean stripExtras, @Nullable TaskDisplayArea tda) { 3356 info.launchCookies.clear(); 3357 info.addLaunchCookie(mLaunchCookie); 3358 final ActivityRecord top = mTaskSupervisor.mTaskInfoHelper.fillAndReturnTop(this, info); 3359 3360 info.userId = isLeafTask() ? mUserId : mCurrentUser; 3361 info.taskId = mTaskId; 3362 info.effectiveUid = effectiveUid; 3363 info.displayId = getDisplayId(); 3364 info.displayAreaFeatureId = tda != null ? tda.mFeatureId : FEATURE_UNDEFINED; 3365 final Intent baseIntent = getBaseIntent(); 3366 // Make a copy of base intent because this is like a snapshot info. 3367 // Besides, {@link RecentTasks#getRecentTasksImpl} may modify it. 3368 final int baseIntentFlags = baseIntent == null ? 0 : baseIntent.getFlags(); 3369 info.baseIntent = baseIntent == null 3370 ? new Intent() 3371 : stripExtras ? baseIntent.cloneFilter() : new Intent(baseIntent); 3372 info.baseIntent.setFlags(baseIntentFlags); 3373 3374 info.isRunning = top != null; 3375 info.topActivity = top != null ? top.mActivityComponent : null; 3376 info.origActivity = origActivity; 3377 info.realActivity = realActivity; 3378 info.lastActiveTime = lastActiveTime; 3379 info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription()); 3380 info.supportsMultiWindow = supportsMultiWindowInDisplayArea(tda); 3381 info.configuration.setTo(getConfiguration()); 3382 // Update to the task's current activity type and windowing mode which may differ from the 3383 // window configuration 3384 info.configuration.windowConfiguration.setActivityType(getActivityType()); 3385 info.configuration.windowConfiguration.setWindowingMode(getWindowingMode()); 3386 info.token = mRemoteToken.toWindowContainerToken(); 3387 3388 //TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child 3389 // order changes. 3390 final Task topTask = top != null && top.getTask() != null ? top.getTask() : this; 3391 info.resizeMode = topTask.mResizeMode; 3392 info.topActivityType = topTask.getActivityType(); 3393 info.displayCutoutInsets = topTask.getDisplayCutoutInsets(); 3394 info.isResizeable = isResizeable(); 3395 info.minWidth = mMinWidth; 3396 info.minHeight = mMinHeight; 3397 info.defaultMinSize = mDisplayContent == null 3398 ? DEFAULT_MIN_TASK_SIZE_DP : mDisplayContent.mMinSizeOfResizeableTaskDp; 3399 info.positionInParent = getRelativePosition(); 3400 3401 info.topActivityInfo = top != null ? top.info : null; 3402 info.pictureInPictureParams = getPictureInPictureParams(top); 3403 info.launchIntoPipHostTaskId = (info.pictureInPictureParams != null 3404 && info.pictureInPictureParams.isLaunchIntoPip() 3405 && top.getLastParentBeforePip() != null) 3406 ? top.getLastParentBeforePip().mTaskId : INVALID_TASK_ID; 3407 info.lastParentTaskIdBeforePip = top != null && top.getLastParentBeforePip() != null 3408 ? top.getLastParentBeforePip().mTaskId : INVALID_TASK_ID; 3409 info.shouldDockBigOverlays = top != null && top.shouldDockBigOverlays; 3410 info.mTopActivityLocusId = top != null ? top.getLocusId() : null; 3411 info.topActivityRequestOpenInBrowserEducationTimestamp = top != null 3412 ? top.mRequestOpenInBrowserEducationTimestamp : 0; 3413 final Task parentTask = getParent() != null ? getParent().asTask() : null; 3414 info.parentTaskId = parentTask != null && parentTask.mCreatedByOrganizer 3415 ? parentTask.mTaskId 3416 : INVALID_TASK_ID; 3417 info.isFocused = isFocused(); 3418 info.isVisible = hasVisibleChildren(); 3419 info.isVisibleRequested = isVisibleRequested(); 3420 info.isTopActivityNoDisplay = top != null && top.isNoDisplay(); 3421 info.isSleeping = shouldSleepActivities(); 3422 info.isTopActivityTransparent = top != null && !top.fillsParent(); 3423 info.isActivityStackTransparent = !topTask.forAllActivities(r -> (r.occludesParent())); 3424 info.lastNonFullscreenBounds = topTask.mLastNonFullscreenBounds; 3425 final WindowState windowState = top != null 3426 ? top.findMainWindow(/* includeStartingApp= */ false) : null; 3427 info.requestedVisibleTypes = 3428 (windowState != null && DesktopModeFlags.ENABLE_FULLY_IMMERSIVE_IN_DESKTOP.isTrue()) 3429 ? windowState.getRequestedVisibleTypes() 3430 : WindowInsets.Type.defaultVisible(); 3431 AppCompatUtils.fillAppCompatTaskInfo(this, info, top); 3432 info.topActivityMainWindowFrame = calculateTopActivityMainWindowFrameForTaskInfo(top); 3433 } 3434 3435 /** 3436 * Returns the top activity's main window frame if it doesn't match 3437 * {@link ActivityRecord#getBounds() the top activity bounds}, or {@code null}, otherwise. 3438 * 3439 * @param top The top running activity of the task 3440 */ 3441 @Nullable 3442 private static Rect calculateTopActivityMainWindowFrameForTaskInfo( 3443 @Nullable ActivityRecord top) { 3444 if (!Flags.betterSupportNonMatchParentActivity()) { 3445 return null; 3446 } 3447 if (top == null) { 3448 return null; 3449 } 3450 final WindowState mainWindow = top.findMainWindow(); 3451 if (mainWindow == null) { 3452 return null; 3453 } 3454 if (!mainWindow.mHaveFrame) { 3455 return null; 3456 } 3457 final Rect windowFrame = mainWindow.getFrame(); 3458 final Rect parentFrame = mainWindow.getParentFrame(); 3459 if (parentFrame.equals(windowFrame)) { 3460 return null; 3461 } 3462 return windowFrame; 3463 } 3464 3465 /** 3466 * Removes the activity info if the activity belongs to a different uid, which is 3467 * different from the app that hosts the task. 3468 */ 3469 static void trimIneffectiveInfo(Task task, TaskInfo info) { 3470 final ActivityRecord baseActivity = task.getActivity(r -> !r.finishing, 3471 false /* traverseTopToBottom */); 3472 final int baseActivityUid = 3473 baseActivity != null ? baseActivity.getUid() : task.effectiveUid; 3474 3475 if (info.topActivityInfo != null 3476 && task.effectiveUid != info.topActivityInfo.applicationInfo.uid) { 3477 // Making a copy to prevent eliminating the info in the original ActivityRecord. 3478 info.topActivityInfo = new ActivityInfo(info.topActivityInfo); 3479 info.topActivityInfo.applicationInfo = 3480 new ApplicationInfo(info.topActivityInfo.applicationInfo); 3481 3482 // Strip the sensitive info. 3483 info.topActivity = new ComponentName("", ""); 3484 info.topActivityInfo.packageName = ""; 3485 info.topActivityInfo.taskAffinity = ""; 3486 info.topActivityInfo.processName = ""; 3487 info.topActivityInfo.name = ""; 3488 info.topActivityInfo.parentActivityName = ""; 3489 info.topActivityInfo.targetActivity = ""; 3490 info.topActivityInfo.splitName = ""; 3491 info.topActivityInfo.applicationInfo.className = ""; 3492 info.topActivityInfo.applicationInfo.credentialProtectedDataDir = ""; 3493 info.topActivityInfo.applicationInfo.dataDir = ""; 3494 info.topActivityInfo.applicationInfo.deviceProtectedDataDir = ""; 3495 info.topActivityInfo.applicationInfo.manageSpaceActivityName = ""; 3496 info.topActivityInfo.applicationInfo.nativeLibraryDir = ""; 3497 info.topActivityInfo.applicationInfo.nativeLibraryRootDir = ""; 3498 info.topActivityInfo.applicationInfo.processName = ""; 3499 info.topActivityInfo.applicationInfo.publicSourceDir = ""; 3500 info.topActivityInfo.applicationInfo.scanPublicSourceDir = ""; 3501 info.topActivityInfo.applicationInfo.scanSourceDir = ""; 3502 info.topActivityInfo.applicationInfo.sourceDir = ""; 3503 info.topActivityInfo.applicationInfo.taskAffinity = ""; 3504 info.topActivityInfo.applicationInfo.name = ""; 3505 info.topActivityInfo.applicationInfo.packageName = ""; 3506 } 3507 3508 if (task.effectiveUid != baseActivityUid) { 3509 info.baseActivity = new ComponentName("", ""); 3510 } 3511 3512 info.capturedLink = null; 3513 info.capturedLinkTimestamp = 0; 3514 info.topActivityRequestOpenInBrowserEducationTimestamp = 0; 3515 } 3516 3517 @Nullable PictureInPictureParams getPictureInPictureParams() { 3518 final Task topTask = getTopMostTask(); 3519 if (topTask == null) return null; 3520 return getPictureInPictureParams(topTask.getTopMostActivity()); 3521 } 3522 3523 private static @Nullable PictureInPictureParams getPictureInPictureParams(ActivityRecord top) { 3524 return (top == null || top.pictureInPictureArgs.empty()) 3525 ? null : new PictureInPictureParams(top.pictureInPictureArgs); 3526 } 3527 3528 /** @return The display cutout insets where the main window is not allowed to extend to. */ 3529 @NonNull Rect getDisplayCutoutInsets() { 3530 final Rect displayCutoutInsets = new Rect(); 3531 if (mDisplayContent == null || getDisplayInfo().displayCutout == null) { 3532 return displayCutoutInsets; 3533 } 3534 final WindowState w = getTopVisibleAppMainWindow(); 3535 final Rect displayFrame; 3536 if (w != null && w.mHaveFrame) { 3537 displayFrame = w.getDisplayFrame(); 3538 } else { 3539 displayFrame = mDisplayContent.getBounds(); 3540 displayFrame.inset(getDisplayInfo().displayCutout.getSafeInsets()); 3541 } 3542 final Rect taskBounds = getBounds(); 3543 if (displayCutoutInsets.setIntersect(taskBounds, displayFrame)) { 3544 displayCutoutInsets.set( 3545 displayCutoutInsets.left - taskBounds.left, 3546 displayCutoutInsets.top - taskBounds.top, 3547 taskBounds.right - displayCutoutInsets.right, 3548 taskBounds.bottom - displayCutoutInsets.bottom); 3549 } 3550 return displayCutoutInsets; 3551 } 3552 3553 /** 3554 * Returns a {@link TaskInfo} with information from this task. 3555 */ 3556 ActivityManager.RunningTaskInfo getTaskInfo() { 3557 ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo(); 3558 fillTaskInfo(info); 3559 return info; 3560 } 3561 3562 /** 3563 * Returns a {@link StartingWindowInfo} with information from this task and the target activity. 3564 * @param activity Target activity which to show the starting window. 3565 */ 3566 StartingWindowInfo getStartingWindowInfo(ActivityRecord activity) { 3567 final StartingWindowInfo info = new StartingWindowInfo(); 3568 info.taskInfo = getTaskInfo(); 3569 info.targetActivityInfo = info.taskInfo.topActivityInfo != null 3570 && activity.info != info.taskInfo.topActivityInfo 3571 ? activity.info : null; 3572 info.isKeyguardOccluded = 3573 mAtmService.mKeyguardController.isKeyguardOccluded(info.taskInfo.displayId); 3574 3575 info.startingWindowTypeParameter = activity.mStartingData != null 3576 ? activity.mStartingData.mTypeParams 3577 : (StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED 3578 | StartingWindowInfo.TYPE_PARAMETER_WINDOWLESS); 3579 if ((info.startingWindowTypeParameter 3580 & StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED) != 0) { 3581 final WindowState topMainWin = getTopFullscreenMainWindow(); 3582 if (topMainWin != null) { 3583 info.mainWindowLayoutParams = topMainWin.mAttrs; 3584 info.requestedVisibleTypes = topMainWin.getRequestedVisibleTypes(); 3585 } 3586 } 3587 final Rect rotatedBounds = activity.getFixedRotationTransformDisplayBounds(); 3588 info.taskBounds.set(rotatedBounds != null ? rotatedBounds 3589 : info.taskInfo.configuration.windowConfiguration.getBounds()); 3590 // If the developer has persist a different configuration, we need to override it to the 3591 // starting window because persisted configuration does not effect to Task. 3592 info.taskInfo.configuration.setTo(activity.getConfiguration()); 3593 return info; 3594 } 3595 3596 /** 3597 * Returns the {@link TaskFragmentParentInfo} which will send to the client 3598 * {@link android.window.TaskFragmentOrganizer} 3599 */ 3600 TaskFragmentParentInfo getTaskFragmentParentInfo() { 3601 return new TaskFragmentParentInfo(getConfiguration(), getDisplayId(), mTaskId, 3602 shouldBeVisible(null /* starting */), hasNonFinishingDirectActivity(), 3603 getDecorSurface()); 3604 } 3605 3606 @Override 3607 protected boolean onChildVisibleRequestedChanged(@Nullable WindowContainer child) { 3608 if (!super.onChildVisibleRequestedChanged(child)) return false; 3609 sendTaskFragmentParentInfoChangedIfNeeded(); 3610 return true; 3611 } 3612 3613 void sendTaskFragmentParentInfoChangedIfNeeded() { 3614 if (!isLeafTask()) { 3615 // Only send parent info changed event for leaf task. 3616 return; 3617 } 3618 final TaskFragment childOrganizedTf = 3619 getTaskFragment(TaskFragment::isOrganizedTaskFragment); 3620 if (childOrganizedTf != null) { 3621 childOrganizedTf.sendTaskFragmentParentInfoChanged(); 3622 } 3623 } 3624 3625 @Override 3626 void assignChildLayers(@NonNull SurfaceControl.Transaction t) { 3627 int layer = 0; 3628 boolean decorSurfacePlaced = false; 3629 3630 for (int j = 0; j < mChildren.size(); ++j) { 3631 final WindowContainer wc = mChildren.get(j); 3632 wc.assignChildLayers(t); 3633 // Place the decor surface under any untrusted content. 3634 if (mDecorSurfaceContainer != null 3635 && !mDecorSurfaceContainer.mIsBoosted 3636 && !decorSurfacePlaced 3637 && shouldPlaceDecorSurfaceBelowContainer(wc)) { 3638 mDecorSurfaceContainer.assignLayer(t, layer++); 3639 decorSurfacePlaced = true; 3640 } 3641 wc.assignLayer(t, layer++); 3642 3643 // Boost the adjacent TaskFragment for dimmer if needed. 3644 final TaskFragment taskFragment = wc.asTaskFragment(); 3645 if (taskFragment != null && taskFragment.isEmbedded() 3646 && taskFragment.hasAdjacentTaskFragment()) { 3647 final int[] nextLayer = { layer }; 3648 taskFragment.forOtherAdjacentTaskFragments(adjacentTf -> { 3649 if (adjacentTf.shouldBoostDimmer()) { 3650 adjacentTf.assignLayer(t, nextLayer[0]++); 3651 } 3652 }); 3653 layer = nextLayer[0]; 3654 } 3655 3656 // Place the decor surface just above the owner TaskFragment. 3657 if (mDecorSurfaceContainer != null 3658 && !mDecorSurfaceContainer.mIsBoosted 3659 && !decorSurfacePlaced 3660 && wc == mDecorSurfaceContainer.mOwnerTaskFragment) { 3661 mDecorSurfaceContainer.assignLayer(t, layer++); 3662 decorSurfacePlaced = true; 3663 } 3664 } 3665 3666 // Boost the decor surface above other non-boosted windows if requested. The cover surface 3667 // will ensure that the content of the windows below are invisible. 3668 if (mDecorSurfaceContainer != null && mDecorSurfaceContainer.mIsBoosted) { 3669 mDecorSurfaceContainer.assignLayer(t, layer++); 3670 } 3671 3672 if (mOverlayHost != null) { 3673 mOverlayHost.setLayer(t, layer++); 3674 } 3675 } 3676 3677 boolean shouldPlaceDecorSurfaceBelowContainer(@NonNull WindowContainer wc) { 3678 boolean isOwnActivity = 3679 wc.asActivityRecord() != null 3680 && wc.asActivityRecord().isUid(effectiveUid); 3681 boolean isTrustedTaskFragment = 3682 wc.asTaskFragment() != null 3683 && wc.asTaskFragment().isEmbedded() 3684 && wc.asTaskFragment().isAllowedToBeEmbeddedInTrustedMode(); 3685 return !isOwnActivity && !isTrustedTaskFragment; 3686 } 3687 3688 /** 3689 * Sets the requested boosted state for the decor surface. 3690 * 3691 * The caller must call {@link #commitDecorSurfaceBoostedState()} to ensure that the change is 3692 * applied. 3693 */ 3694 void requestDecorSurfaceBoosted( 3695 @NonNull TaskFragment ownerTaskFragment, 3696 boolean isBoosted, 3697 @Nullable SurfaceControl.Transaction clientTransaction) { 3698 if (mDecorSurfaceContainer == null 3699 || mDecorSurfaceContainer.mOwnerTaskFragment != ownerTaskFragment) { 3700 return; 3701 } 3702 mDecorSurfaceContainer.requestBoosted(isBoosted, clientTransaction); 3703 } 3704 3705 void commitDecorSurfaceBoostedState() { 3706 if (mDecorSurfaceContainer == null) { 3707 return; 3708 } 3709 mDecorSurfaceContainer.commitBoostedState(); 3710 3711 // assignChildLayers() calls scheduleAnimation(), which calls prepareSurfaces() 3712 // to ensure child surface visibility. 3713 assignChildLayers(); 3714 } 3715 3716 boolean isDecorSurfaceBoosted() { 3717 return mDecorSurfaceContainer != null && mDecorSurfaceContainer.mIsBoosted; 3718 } 3719 3720 boolean isTaskId(int taskId) { 3721 return mTaskId == taskId; 3722 } 3723 3724 @Override 3725 Task asTask() { 3726 // I'm a task! 3727 return this; 3728 } 3729 3730 ActivityRecord isInTask(ActivityRecord r) { 3731 if (r == null) { 3732 return null; 3733 } 3734 if (r.isDescendantOf(this)) { 3735 return r; 3736 } 3737 return null; 3738 } 3739 3740 void dump(PrintWriter pw, String prefix) { 3741 pw.print(prefix); pw.print("userId="); pw.print(mUserId); 3742 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid); 3743 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid); 3744 pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete); 3745 pw.print(" mCallingPackage="); pw.print(mCallingPackage); 3746 pw.print(" mCallingFeatureId="); pw.println(mCallingFeatureId); 3747 if (affinity != null || rootAffinity != null) { 3748 pw.print(prefix); pw.print("affinity="); pw.print(affinity); 3749 if (affinity == null || !affinity.equals(rootAffinity)) { 3750 pw.print(" root="); pw.println(rootAffinity); 3751 } else { 3752 pw.println(); 3753 } 3754 } 3755 if (mWindowLayoutAffinity != null) { 3756 pw.print(prefix); pw.print("windowLayoutAffinity="); pw.println(mWindowLayoutAffinity); 3757 } 3758 if (voiceSession != null || voiceInteractor != null) { 3759 pw.print(prefix); pw.print("VOICE: session=0x"); 3760 pw.print(Integer.toHexString(System.identityHashCode(voiceSession))); 3761 pw.print(" interactor=0x"); 3762 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor))); 3763 } 3764 if (intent != null) { 3765 StringBuilder sb = new StringBuilder(128); 3766 sb.append(prefix); sb.append("intent={"); 3767 intent.toShortString(sb, false, true, false, false); 3768 sb.append('}'); 3769 pw.println(sb.toString()); 3770 } 3771 if (affinityIntent != null) { 3772 StringBuilder sb = new StringBuilder(128); 3773 sb.append(prefix); sb.append("affinityIntent={"); 3774 affinityIntent.toShortString(sb, false, true, false, false); 3775 sb.append('}'); 3776 pw.println(sb.toString()); 3777 } 3778 if (origActivity != null) { 3779 pw.print(prefix); pw.print("origActivity="); 3780 pw.println(origActivity.flattenToShortString()); 3781 } 3782 if (realActivity != null) { 3783 pw.print(prefix); pw.print("mActivityComponent="); 3784 pw.println(realActivity.flattenToShortString()); 3785 } 3786 if (autoRemoveRecents || isPersistable || !isActivityTypeStandard()) { 3787 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents); 3788 pw.print(" isPersistable="); pw.print(isPersistable); 3789 pw.print(" activityType="); pw.println(getActivityType()); 3790 } 3791 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask 3792 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) { 3793 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset); 3794 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity); 3795 pw.print(" mReuseTask="); pw.print(mReuseTask); 3796 pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString()); 3797 } 3798 if (mAffiliatedTaskId != mTaskId || mPrevAffiliateTaskId != INVALID_TASK_ID 3799 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID 3800 || mNextAffiliate != null) { 3801 pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId); 3802 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId); 3803 pw.print(" ("); 3804 if (mPrevAffiliate == null) { 3805 pw.print("null"); 3806 } else { 3807 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate))); 3808 } 3809 pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId); 3810 pw.print(" ("); 3811 if (mNextAffiliate == null) { 3812 pw.print("null"); 3813 } else { 3814 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate))); 3815 } 3816 pw.println(")"); 3817 } 3818 pw.print(prefix); pw.print("Activities="); pw.println(mChildren); 3819 if (!inRecents || !isAvailable) { 3820 pw.print(prefix); 3821 pw.print(" inRecents="); pw.print(inRecents); 3822 pw.print(" isAvailable="); pw.println(isAvailable); 3823 } 3824 if (lastDescription != null) { 3825 pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription); 3826 } 3827 if (mRootProcess != null) { 3828 pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess); 3829 } 3830 if (mSharedStartingData != null) { 3831 pw.println(prefix + "mSharedStartingData=" + mSharedStartingData); 3832 } 3833 if (mKillProcessesOnDestroyed) { 3834 pw.println(prefix + "mKillProcessesOnDestroyed=true"); 3835 } 3836 pw.print(prefix); pw.print("taskId=" + mTaskId); 3837 pw.println(" rootTaskId=" + getRootTaskId()); 3838 pw.print(prefix); pw.println("hasChildPipActivity=" + (mChildPipActivity != null)); 3839 pw.print(prefix); pw.print("mHasBeenVisible="); pw.println(getHasBeenVisible()); 3840 pw.print(prefix); pw.print("mResizeMode="); 3841 pw.print(ActivityInfo.resizeModeToString(mResizeMode)); 3842 pw.print(" mSupportsPictureInPicture="); pw.print(mSupportsPictureInPicture); 3843 pw.print(" isResizeable="); pw.println(isResizeable()); 3844 pw.print(prefix); pw.print("isPerceptible="); pw.println(mIsPerceptible); 3845 pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime); 3846 pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)"); 3847 pw.print(prefix); pw.print("isTrimmable=" + mIsTrimmableFromRecents); 3848 pw.print(" isForceHidden="); pw.print(isForceHidden()); 3849 pw.print(" isForceExcludedFromRecents="); pw.println(isForceExcludedFromRecents()); 3850 if (mLaunchAdjacentDisabled) { 3851 pw.println(prefix + "mLaunchAdjacentDisabled=true"); 3852 } 3853 if (mReparentLeafTaskIfRelaunch) { 3854 pw.println(prefix + "mReparentLeafTaskIfRelaunch=true"); 3855 } 3856 } 3857 3858 @Override 3859 String toFullString() { 3860 final StringBuilder sb = new StringBuilder(192); 3861 sb.append(this); 3862 sb.setLength(sb.length() - 1); // Remove tail '}'. 3863 sb.append(" U="); 3864 sb.append(mUserId); 3865 final Task rootTask = getRootTask(); 3866 if (rootTask != this) { 3867 sb.append(" rootTaskId="); 3868 sb.append(rootTask.mTaskId); 3869 } 3870 sb.append(" visible="); 3871 sb.append(shouldBeVisible(null /* starting */)); 3872 sb.append(" visibleRequested="); 3873 sb.append(isVisibleRequested()); 3874 sb.append(" mode="); 3875 sb.append(windowingModeToString(getWindowingMode())); 3876 sb.append(" translucent="); 3877 sb.append(isTranslucent(null /* starting */)); 3878 sb.append(" sz="); 3879 sb.append(getChildCount()); 3880 sb.append('}'); 3881 return sb.toString(); 3882 } 3883 3884 @Override 3885 public String toString() { 3886 if (stringName != null) return stringName; 3887 StringBuilder sb = new StringBuilder(128); 3888 sb.append("Task{"); 3889 sb.append(Integer.toHexString(System.identityHashCode(this))); 3890 sb.append(" #"); 3891 sb.append(mTaskId); 3892 sb.append(" type=" + activityTypeToString(getActivityType())); 3893 if (affinity != null) { 3894 sb.append(" A="); 3895 sb.append(affinity); 3896 } else if (intent != null && intent.getComponent() != null) { 3897 sb.append(" I="); 3898 sb.append(intent.getComponent().flattenToShortString()); 3899 } else if (affinityIntent != null && affinityIntent.getComponent() != null) { 3900 sb.append(" aI="); 3901 sb.append(affinityIntent.getComponent().flattenToShortString()); 3902 } 3903 if (!isResizeable()) { 3904 sb.append(" nonResizable"); 3905 } 3906 if (mMinWidth != INVALID_MIN_SIZE || mMinHeight != INVALID_MIN_SIZE) { 3907 sb.append(" minWidth=").append(mMinWidth); 3908 sb.append(" minHeight=").append(mMinHeight); 3909 } 3910 sb.append('}'); 3911 return stringName = sb.toString(); 3912 } 3913 3914 /** 3915 * Saves this {@link Task} to XML using given serializer. 3916 */ 3917 void saveToXml(TypedXmlSerializer out) throws Exception { 3918 if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this); 3919 3920 out.attributeInt(null, ATTR_TASKID, mTaskId); 3921 if (realActivity != null) { 3922 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString()); 3923 } 3924 out.attributeBoolean(null, ATTR_REALACTIVITY_SUSPENDED, realActivitySuspended); 3925 if (origActivity != null) { 3926 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString()); 3927 } 3928 // Write affinity, and root affinity if it is different from affinity. 3929 // We use the special string "@" for a null root affinity, so we can identify 3930 // later whether we were given a root affinity or should just make it the 3931 // same as the affinity. 3932 if (affinity != null) { 3933 out.attribute(null, ATTR_AFFINITY, affinity); 3934 if (!affinity.equals(rootAffinity)) { 3935 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 3936 } 3937 } else if (rootAffinity != null) { 3938 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 3939 } 3940 if (mWindowLayoutAffinity != null) { 3941 out.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity); 3942 } 3943 out.attributeBoolean(null, ATTR_ROOTHASRESET, rootWasReset); 3944 out.attributeBoolean(null, ATTR_AUTOREMOVERECENTS, autoRemoveRecents); 3945 out.attributeInt(null, ATTR_USERID, mUserId); 3946 out.attributeBoolean(null, ATTR_USER_SETUP_COMPLETE, mUserSetupComplete); 3947 out.attributeInt(null, ATTR_EFFECTIVE_UID, effectiveUid); 3948 out.attributeLong(null, ATTR_LASTTIMEMOVED, mLastTimeMoved); 3949 out.attributeBoolean(null, ATTR_NEVERRELINQUISH, mNeverRelinquishIdentity); 3950 if (lastDescription != null) { 3951 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); 3952 } 3953 if (getTaskDescription() != null) { 3954 getTaskDescription().saveToXml(out); 3955 } 3956 out.attributeInt(null, ATTR_TASK_AFFILIATION, mAffiliatedTaskId); 3957 out.attributeInt(null, ATTR_PREV_AFFILIATION, mPrevAffiliateTaskId); 3958 out.attributeInt(null, ATTR_NEXT_AFFILIATION, mNextAffiliateTaskId); 3959 out.attributeInt(null, ATTR_CALLING_UID, mCallingUid); 3960 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage); 3961 out.attribute(null, ATTR_CALLING_FEATURE_ID, 3962 mCallingFeatureId == null ? "" : mCallingFeatureId); 3963 out.attributeInt(null, ATTR_RESIZE_MODE, mResizeMode); 3964 out.attributeBoolean(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE, mSupportsPictureInPicture); 3965 if (mLastNonFullscreenBounds != null) { 3966 out.attribute( 3967 null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString()); 3968 } 3969 out.attributeInt(null, ATTR_MIN_WIDTH, mMinWidth); 3970 out.attributeInt(null, ATTR_MIN_HEIGHT, mMinHeight); 3971 out.attributeInt(null, ATTR_PERSIST_TASK_VERSION, PERSIST_TASK_VERSION); 3972 3973 if (affinityIntent != null) { 3974 out.startTag(null, TAG_AFFINITYINTENT); 3975 affinityIntent.saveToXml(out); 3976 out.endTag(null, TAG_AFFINITYINTENT); 3977 } 3978 3979 if (intent != null) { 3980 out.startTag(null, TAG_INTENT); 3981 intent.saveToXml(out); 3982 out.endTag(null, TAG_INTENT); 3983 } 3984 3985 sTmpException = null; 3986 final PooledPredicate f = PooledLambda.obtainPredicate(Task::saveActivityToXml, 3987 PooledLambda.__(ActivityRecord.class), getBottomMostActivity(), out); 3988 forAllActivities(f); 3989 f.recycle(); 3990 if (sTmpException != null) { 3991 throw sTmpException; 3992 } 3993 } 3994 3995 private static boolean saveActivityToXml( 3996 ActivityRecord r, ActivityRecord first, TypedXmlSerializer out) { 3997 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() 3998 || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT 3999 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) 4000 && r != first) { 4001 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET). 4002 return true; 4003 } 4004 try { 4005 out.startTag(null, TAG_ACTIVITY); 4006 r.saveToXml(out); 4007 out.endTag(null, TAG_ACTIVITY); 4008 return false; 4009 } catch (Exception e) { 4010 sTmpException = e; 4011 return true; 4012 } 4013 } 4014 4015 static Task restoreFromXml(TypedXmlPullParser in, ActivityTaskSupervisor taskSupervisor) 4016 throws IOException, XmlPullParserException { 4017 Intent intent = null; 4018 Intent affinityIntent = null; 4019 ArrayList<ActivityRecord> activities = new ArrayList<>(); 4020 ComponentName realActivity = null; 4021 boolean realActivitySuspended = false; 4022 ComponentName origActivity = null; 4023 String affinity = null; 4024 String rootAffinity = null; 4025 boolean hasRootAffinity = false; 4026 String windowLayoutAffinity = null; 4027 boolean rootHasReset = false; 4028 boolean autoRemoveRecents = false; 4029 int taskType = 0; 4030 int userId = 0; 4031 boolean userSetupComplete = true; 4032 int effectiveUid = -1; 4033 String lastDescription = null; 4034 long lastTimeOnTop = 0; 4035 boolean neverRelinquishIdentity = true; 4036 int taskId = INVALID_TASK_ID; 4037 final int outerDepth = in.getDepth(); 4038 TaskDescription taskDescription = new TaskDescription(); 4039 int taskAffiliation = INVALID_TASK_ID; 4040 int prevTaskId = INVALID_TASK_ID; 4041 int nextTaskId = INVALID_TASK_ID; 4042 int callingUid = -1; 4043 String callingPackage = ""; 4044 String callingFeatureId = null; 4045 int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; 4046 boolean supportsPictureInPicture = false; 4047 Rect lastNonFullscreenBounds = null; 4048 int minWidth = INVALID_MIN_SIZE; 4049 int minHeight = INVALID_MIN_SIZE; 4050 int persistTaskVersion = 0; 4051 4052 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { 4053 final String attrName = in.getAttributeName(attrNdx); 4054 final String attrValue = in.getAttributeValue(attrNdx); 4055 if (TaskPersister.DEBUG) { 4056 Slog.d(TaskPersister.TAG, "Task: attribute name=" + attrName + " value=" 4057 + attrValue); 4058 } 4059 switch (attrName) { 4060 case ATTR_TASKID: 4061 if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue); 4062 break; 4063 case ATTR_REALACTIVITY: 4064 realActivity = ComponentName.unflattenFromString(attrValue); 4065 break; 4066 case ATTR_REALACTIVITY_SUSPENDED: 4067 realActivitySuspended = Boolean.valueOf(attrValue); 4068 break; 4069 case ATTR_ORIGACTIVITY: 4070 origActivity = ComponentName.unflattenFromString(attrValue); 4071 break; 4072 case ATTR_AFFINITY: 4073 affinity = attrValue; 4074 break; 4075 case ATTR_ROOT_AFFINITY: 4076 rootAffinity = attrValue; 4077 hasRootAffinity = true; 4078 break; 4079 case ATTR_WINDOW_LAYOUT_AFFINITY: 4080 windowLayoutAffinity = attrValue; 4081 break; 4082 case ATTR_ROOTHASRESET: 4083 rootHasReset = Boolean.parseBoolean(attrValue); 4084 break; 4085 case ATTR_AUTOREMOVERECENTS: 4086 autoRemoveRecents = Boolean.parseBoolean(attrValue); 4087 break; 4088 case ATTR_USERID: 4089 userId = Integer.parseInt(attrValue); 4090 break; 4091 case ATTR_USER_SETUP_COMPLETE: 4092 userSetupComplete = Boolean.parseBoolean(attrValue); 4093 break; 4094 case ATTR_EFFECTIVE_UID: 4095 effectiveUid = Integer.parseInt(attrValue); 4096 break; 4097 case ATTR_TASKTYPE: 4098 taskType = Integer.parseInt(attrValue); 4099 break; 4100 case ATTR_LASTDESCRIPTION: 4101 lastDescription = attrValue; 4102 break; 4103 case ATTR_LASTTIMEMOVED: 4104 lastTimeOnTop = Long.parseLong(attrValue); 4105 break; 4106 case ATTR_NEVERRELINQUISH: 4107 neverRelinquishIdentity = Boolean.parseBoolean(attrValue); 4108 break; 4109 case ATTR_TASK_AFFILIATION: 4110 taskAffiliation = Integer.parseInt(attrValue); 4111 break; 4112 case ATTR_PREV_AFFILIATION: 4113 prevTaskId = Integer.parseInt(attrValue); 4114 break; 4115 case ATTR_NEXT_AFFILIATION: 4116 nextTaskId = Integer.parseInt(attrValue); 4117 break; 4118 case ATTR_CALLING_UID: 4119 callingUid = Integer.parseInt(attrValue); 4120 break; 4121 case ATTR_CALLING_PACKAGE: 4122 callingPackage = attrValue; 4123 break; 4124 case ATTR_CALLING_FEATURE_ID: 4125 callingFeatureId = attrValue; 4126 break; 4127 case ATTR_RESIZE_MODE: 4128 resizeMode = Integer.parseInt(attrValue); 4129 break; 4130 case ATTR_SUPPORTS_PICTURE_IN_PICTURE: 4131 supportsPictureInPicture = Boolean.parseBoolean(attrValue); 4132 break; 4133 case ATTR_NON_FULLSCREEN_BOUNDS: 4134 lastNonFullscreenBounds = Rect.unflattenFromString(attrValue); 4135 break; 4136 case ATTR_MIN_WIDTH: 4137 minWidth = Integer.parseInt(attrValue); 4138 break; 4139 case ATTR_MIN_HEIGHT: 4140 minHeight = Integer.parseInt(attrValue); 4141 break; 4142 case ATTR_PERSIST_TASK_VERSION: 4143 persistTaskVersion = Integer.parseInt(attrValue); 4144 break; 4145 default: 4146 if (!attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) { 4147 Slog.w(TAG, "Task: Unknown attribute=" + attrName); 4148 } 4149 } 4150 } 4151 taskDescription.restoreFromXml(in); 4152 4153 int event; 4154 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) 4155 && (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) { 4156 if (event == XmlPullParser.START_TAG) { 4157 final String name = in.getName(); 4158 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: START_TAG name=" + name); 4159 if (TAG_AFFINITYINTENT.equals(name)) { 4160 affinityIntent = Intent.restoreFromXml(in); 4161 } else if (TAG_INTENT.equals(name)) { 4162 intent = Intent.restoreFromXml(in); 4163 } else if (TAG_ACTIVITY.equals(name)) { 4164 ActivityRecord activity = 4165 ActivityRecord.restoreFromXml(in, taskSupervisor); 4166 if (TaskPersister.DEBUG) { 4167 Slog.d(TaskPersister.TAG, "Task: activity=" + activity); 4168 } 4169 if (activity != null) { 4170 activities.add(activity); 4171 } 4172 } else { 4173 Slog.e(TAG, "restoreTask: Unexpected name=" + name); 4174 XmlUtils.skipCurrentTag(in); 4175 } 4176 } 4177 } 4178 if (!hasRootAffinity) { 4179 rootAffinity = affinity; 4180 } else if ("@".equals(rootAffinity)) { 4181 rootAffinity = null; 4182 } 4183 if (effectiveUid <= 0) { 4184 Intent checkIntent = intent != null ? intent : affinityIntent; 4185 effectiveUid = 0; 4186 if (checkIntent != null) { 4187 IPackageManager pm = AppGlobals.getPackageManager(); 4188 try { 4189 ApplicationInfo ai = pm.getApplicationInfo( 4190 checkIntent.getComponent().getPackageName(), 4191 PackageManager.MATCH_UNINSTALLED_PACKAGES 4192 | PackageManager.MATCH_DISABLED_COMPONENTS, userId); 4193 if (ai != null) { 4194 effectiveUid = ai.uid; 4195 } 4196 } catch (RemoteException e) { 4197 } 4198 } 4199 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent 4200 + ": effectiveUid=" + effectiveUid); 4201 } 4202 4203 if (persistTaskVersion < 1) { 4204 // We need to convert the resize mode of home activities saved before version one if 4205 // they are marked as RESIZE_MODE_RESIZEABLE to 4206 // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation 4207 // before version 1 and the system didn't resize home activities before then. 4208 if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) { 4209 resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 4210 } 4211 } else { 4212 // This activity has previously marked itself explicitly as both resizeable and 4213 // supporting picture-in-picture. Since there is no longer a requirement for 4214 // picture-in-picture activities to be resizeable, we can mark this simply as 4215 // resizeable and supporting picture-in-picture separately. 4216 if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) { 4217 resizeMode = RESIZE_MODE_RESIZEABLE; 4218 supportsPictureInPicture = true; 4219 } 4220 } 4221 4222 final Task task = new Task.Builder(taskSupervisor.mService) 4223 .setTaskId(taskId) 4224 .setIntent(intent) 4225 .setAffinityIntent(affinityIntent) 4226 .setAffinity(affinity) 4227 .setRootAffinity(rootAffinity) 4228 .setRealActivity(realActivity) 4229 .setOrigActivity(origActivity) 4230 .setRootWasReset(rootHasReset) 4231 .setAutoRemoveRecents(autoRemoveRecents) 4232 .setUserId(userId) 4233 .setEffectiveUid(effectiveUid) 4234 .setLastDescription(lastDescription) 4235 .setLastTimeMoved(lastTimeOnTop) 4236 .setNeverRelinquishIdentity(neverRelinquishIdentity) 4237 .setLastTaskDescription(taskDescription) 4238 .setTaskAffiliation(taskAffiliation) 4239 .setPrevAffiliateTaskId(prevTaskId) 4240 .setNextAffiliateTaskId(nextTaskId) 4241 .setCallingUid(callingUid) 4242 .setCallingPackage(callingPackage) 4243 .setCallingFeatureId(callingFeatureId) 4244 .setResizeMode(resizeMode) 4245 .setSupportsPictureInPicture(supportsPictureInPicture) 4246 .setRealActivitySuspended(realActivitySuspended) 4247 .setUserSetupComplete(userSetupComplete) 4248 .setMinWidth(minWidth) 4249 .setMinHeight(minHeight) 4250 .buildInner(); 4251 task.mLastNonFullscreenBounds = lastNonFullscreenBounds; 4252 task.setBounds(lastNonFullscreenBounds); 4253 task.mWindowLayoutAffinity = windowLayoutAffinity; 4254 if (activities.size() > 0) { 4255 // We need to add the task into hierarchy before adding child to it. 4256 final DisplayContent dc = 4257 taskSupervisor.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY); 4258 dc.getDefaultTaskDisplayArea().addChild(task, POSITION_BOTTOM); 4259 4260 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { 4261 task.addChild(activities.get(activityNdx)); 4262 } 4263 } 4264 4265 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task); 4266 return task; 4267 } 4268 4269 @Override 4270 boolean isOrganized() { 4271 return mTaskOrganizer != null; 4272 } 4273 4274 private boolean canBeOrganized() { 4275 // All root tasks can be organized 4276 if (isRootTask() || mCreatedByOrganizer) { 4277 return true; 4278 } 4279 4280 // Task could be organized if it's the direct child of a task created by organizer. 4281 final Task parentTask = getParent().asTask(); 4282 return parentTask != null && parentTask.mCreatedByOrganizer; 4283 } 4284 4285 @Override 4286 boolean showSurfaceOnCreation() { 4287 return false; 4288 } 4289 4290 @Override 4291 protected void reparentSurfaceControl(SurfaceControl.Transaction t, SurfaceControl newParent) { 4292 /** 4293 * Avoid reparenting SurfaceControl of the organized tasks that are always on top, since 4294 * the surfaces should be controlled by the organizer itself, like bubbles. 4295 */ 4296 if (isOrganized() && isAlwaysOnTop()) { 4297 return; 4298 } 4299 super.reparentSurfaceControl(t, newParent); 4300 } 4301 4302 void setHasBeenVisible(boolean hasBeenVisible) { 4303 mHasBeenVisible = hasBeenVisible; 4304 if (!hasBeenVisible) { 4305 return; 4306 } 4307 if (!mDeferTaskAppear) { 4308 sendTaskAppeared(); 4309 } 4310 for (WindowContainer<?> parent = getParent(); parent != null; parent = parent.getParent()) { 4311 final Task parentTask = parent.asTask(); 4312 if (parentTask == null) { 4313 break; 4314 } 4315 parentTask.setHasBeenVisible(true); 4316 } 4317 } 4318 4319 4320 boolean getHasBeenVisible() { 4321 return mHasBeenVisible; 4322 } 4323 4324 void setDeferTaskAppear(boolean deferTaskAppear) { 4325 final boolean wasDeferred = mDeferTaskAppear; 4326 mDeferTaskAppear = deferTaskAppear; 4327 if (wasDeferred && !deferTaskAppear) { 4328 sendTaskAppeared(); 4329 } 4330 } 4331 4332 /** In the case that these conditions are true, we want to send the Task to the organizer: 4333 * 1. An organizer has been set 4334 * 2. The Task was created by the organizer 4335 * or 4336 * 2a. We have a SurfaceControl 4337 * 2b. We have finished drawing 4338 * Any time any of these conditions are updated, the updating code should call 4339 * sendTaskAppeared. 4340 */ 4341 boolean taskAppearedReady() { 4342 if (mTaskOrganizer == null) { 4343 return false; 4344 } 4345 4346 if (mDeferTaskAppear) { 4347 return false; 4348 } 4349 4350 if (mCreatedByOrganizer) { 4351 return true; 4352 } 4353 4354 return mSurfaceControl != null && getHasBeenVisible(); 4355 } 4356 4357 private void sendTaskAppeared() { 4358 if (mTaskOrganizer != null) { 4359 mAtmService.mTaskOrganizerController.onTaskAppeared(mTaskOrganizer, this); 4360 } 4361 } 4362 4363 private void sendTaskVanished(ITaskOrganizer organizer) { 4364 if (organizer != null) { 4365 mAtmService.mTaskOrganizerController.onTaskVanished(organizer, this); 4366 } 4367 } 4368 4369 @VisibleForTesting 4370 boolean setTaskOrganizer(ITaskOrganizer organizer) { 4371 return setTaskOrganizer(organizer, false /* skipTaskAppeared */); 4372 } 4373 4374 @VisibleForTesting 4375 boolean setTaskOrganizer(ITaskOrganizer organizer, boolean skipTaskAppeared) { 4376 if (mTaskOrganizer == organizer) { 4377 return false; 4378 } 4379 4380 ITaskOrganizer prevOrganizer = mTaskOrganizer; 4381 // Update the new task organizer before calling sendTaskVanished since it could result in 4382 // a new SurfaceControl getting created that would notify the old organizer about it. 4383 mTaskOrganizer = organizer; 4384 // Let the old organizer know it has lost control. 4385 sendTaskVanished(prevOrganizer); 4386 4387 if (mTaskOrganizer != null) { 4388 if (!skipTaskAppeared) { 4389 sendTaskAppeared(); 4390 } 4391 } else { 4392 // No longer managed by any organizer. 4393 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 4394 if (taskDisplayArea != null) { 4395 taskDisplayArea.removeLaunchRootTask(this); 4396 } 4397 setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */); 4398 if (mCreatedByOrganizer) { 4399 removeImmediately("setTaskOrganizer"); 4400 } 4401 } 4402 4403 return true; 4404 } 4405 4406 boolean updateTaskOrganizerState() { 4407 return updateTaskOrganizerState(false /* skipTaskAppeared */); 4408 } 4409 4410 /** 4411 * Called when the task state changes (ie. from windowing mode change) an the task organizer 4412 * state should also be updated. 4413 * 4414 * @param skipTaskAppeared Skips calling taskAppeared for the new organizer if it has changed 4415 * @return {@code true} if task organizer changed. 4416 */ 4417 boolean updateTaskOrganizerState(boolean skipTaskAppeared) { 4418 if (getSurfaceControl() == null) { 4419 // Can't call onTaskAppeared without a surfacecontrol, so defer this until next one 4420 // is created. 4421 return false; 4422 } 4423 if (!canBeOrganized()) { 4424 return setTaskOrganizer(null); 4425 } 4426 4427 final TaskOrganizerController controller = mWmService.mAtmService.mTaskOrganizerController; 4428 final ITaskOrganizer organizer = controller.getTaskOrganizer(); 4429 // Do not change to different organizer if the task is created by organizer because only 4430 // the creator knows how to manage it. 4431 if (mCreatedByOrganizer && mTaskOrganizer != null && organizer != null 4432 && mTaskOrganizer != organizer) { 4433 return false; 4434 } 4435 return setTaskOrganizer(organizer, skipTaskAppeared); 4436 } 4437 4438 @Override 4439 void setSurfaceControl(SurfaceControl sc) { 4440 super.setSurfaceControl(sc); 4441 // If the TaskOrganizer was set before we created the SurfaceControl, we need to 4442 // emit the callbacks now. 4443 sendTaskAppeared(); 4444 } 4445 4446 /** 4447 * @return {@code true} if the task is currently focused or one of its children is focused. 4448 */ 4449 boolean isFocused() { 4450 if (mDisplayContent == null || mDisplayContent.mFocusedApp == null) { 4451 return false; 4452 } 4453 final Task focusedTask = mDisplayContent.mFocusedApp.getTask(); 4454 return focusedTask == this || (focusedTask != null && focusedTask.getParent() == this); 4455 } 4456 4457 /** 4458 * @return true if the task is visible and has at least one visible child. 4459 */ 4460 private boolean hasVisibleChildren() { 4461 if (!isAttached() || isForceHidden()) { 4462 return false; 4463 } 4464 4465 return getActivity(ActivityRecord::isVisible) != null; 4466 } 4467 4468 /** 4469 * Called on the task when it gained or lost focus. 4470 * @param hasFocus 4471 */ 4472 void onAppFocusChanged(boolean hasFocus) { 4473 dispatchTaskInfoChangedIfNeeded(false /* force */); 4474 final Task parentTask = getParent().asTask(); 4475 if (parentTask != null) parentTask.dispatchTaskInfoChangedIfNeeded(false /* force */); 4476 4477 mAtmService.getTaskChangeNotificationController().notifyTaskFocusChanged(mTaskId, hasFocus); 4478 } 4479 4480 void onPictureInPictureParamsChanged() { 4481 if (inPinnedWindowingMode() || DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue()) { 4482 dispatchTaskInfoChangedIfNeeded(true /* force */); 4483 } 4484 } 4485 4486 void onShouldDockBigOverlaysChanged() { 4487 dispatchTaskInfoChangedIfNeeded(true /* force */); 4488 } 4489 4490 /** Called when the top activity in the Root Task enters or exits size compat mode. */ 4491 void onSizeCompatActivityChanged() { 4492 // Trigger TaskInfoChanged to update the size compat restart button. 4493 dispatchTaskInfoChangedIfNeeded(true /* force */); 4494 } 4495 4496 /** 4497 * See {@link WindowContainerTransaction#setBoundsChangeTransaction}. In short this 4498 * transaction will be consumed by the next BASE_APPLICATION window within our hierarchy 4499 * to resize, and it will defer the transaction until that resize frame completes. 4500 */ 4501 void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t) { 4502 setMainWindowSizeChangeTransaction(t, this); 4503 forAllWindows(WindowState::requestRedrawForSync, true); 4504 } 4505 4506 private void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t, Task origin) { 4507 // This is only meaningful on an activity's task, so put it on the top one. 4508 ActivityRecord topActivity = getTopNonFinishingActivity(); 4509 Task leaf = topActivity != null ? topActivity.getTask() : null; 4510 if (leaf == null) { 4511 return; 4512 } 4513 if (leaf != this) { 4514 leaf.setMainWindowSizeChangeTransaction(t, origin); 4515 return; 4516 } 4517 final WindowState w = getTopVisibleAppMainWindow(); 4518 if (w != null) { 4519 w.mIsSurfacePositionPaused = true; 4520 w.applyWithNextDraw((d) -> { 4521 w.mIsSurfacePositionPaused = false; 4522 w.updateSurfacePosition(d); 4523 d.merge(t); 4524 }); 4525 } else { 4526 t.apply(); 4527 } 4528 } 4529 4530 /** 4531 * Sets/unsets the forced-hidden state flag for this task depending on {@param set}. 4532 * @return Whether the force hidden state changed 4533 */ 4534 @Override 4535 boolean setForceHidden(@FlagForceHidden int flags, boolean set) { 4536 final boolean wasHidden = isForceHidden(); 4537 final boolean wasVisible = isVisible(); 4538 if (!super.setForceHidden(flags, set)) { 4539 return false; 4540 } 4541 final boolean nowHidden = isForceHidden(); 4542 if (wasHidden != nowHidden) { 4543 final String reason = "setForceHidden"; 4544 if (wasVisible && nowHidden) { 4545 // Move this visible task to back when the task is forced hidden 4546 moveToBack(reason, null); 4547 } else if (isAlwaysOnTop()) { 4548 // Move this always-on-top task to front when no longer hidden 4549 moveToFront(reason); 4550 } 4551 } 4552 return true; 4553 } 4554 4555 @Override 4556 public boolean isAlwaysOnTop() { 4557 return !isForceHidden() && super.isAlwaysOnTop(); 4558 } 4559 4560 /** 4561 * @return whether this task is always on top without taking visibility into account. 4562 * @deprecated b/388630258 replace hidden bubble tasks with reordering. 4563 * {@link RecentTasks#isVisibleRecentTask} now checks {@link #isForceExcludedFromRecents}. 4564 */ 4565 @Deprecated 4566 boolean isAlwaysOnTopWhenVisible() { 4567 return super.isAlwaysOnTop(); 4568 } 4569 4570 /** 4571 * Returns whether this task is forcibly excluded from the Recents list. 4572 * 4573 * <p>This flag is used by {@link RecentTasks#isVisibleRecentTask} to determine 4574 * if the task should be presented to the user through SystemUI. If this method 4575 * returns {@code true}, the task will not be shown in Recents, regardless of other 4576 * visibility criteria. 4577 * 4578 * @return {@code true} if the task is excluded, {@code false} otherwise. 4579 */ 4580 boolean isForceExcludedFromRecents() { 4581 return mForceExcludedFromRecents; 4582 } 4583 4584 /** 4585 * Sets whether this task should be forcibly excluded from the Recents list. 4586 * 4587 * <p>This method is intended to be used in conjunction with 4588 * {@link android.window.WindowContainerTransaction#setTaskForceExcludedFromRecents} to modify the 4589 * task's exclusion state. 4590 * 4591 * @param excluded {@code true} to exclude the task, {@code false} otherwise. 4592 */ 4593 void setForceExcludedFromRecents(boolean excluded) { 4594 if (!Flags.excludeTaskFromRecents()) { 4595 Slog.w(TAG, "Flag " + Flags.FLAG_EXCLUDE_TASK_FROM_RECENTS + " is not enabled"); 4596 return; 4597 } 4598 mForceExcludedFromRecents = excluded; 4599 } 4600 4601 boolean isForceHiddenForPinnedTask() { 4602 return (mForceHiddenFlags & FLAG_FORCE_HIDDEN_FOR_PINNED_TASK) != 0; 4603 } 4604 4605 @Override 4606 long getProtoFieldId() { 4607 return TASK; 4608 } 4609 4610 /** 4611 * Restores to the windowing mode saved when task requested to enter fullscreen using 4612 * {@link Activity#requestFullscreenMode} API if it is valid. The task is also reparented to 4613 * the previous parent if parent has changed. 4614 */ 4615 void restoreWindowingMode() { 4616 if (mMultiWindowRestoreWindowingMode == INVALID_WINDOWING_MODE) { 4617 return; 4618 } 4619 if (!getParent().mRemoteToken.toWindowContainerToken() 4620 .equals(mMultiWindowRestoreParent)) { 4621 // Restore previous parent if parent has changed. 4622 final Task parent = fromWindowContainerToken(mMultiWindowRestoreParent); 4623 reparent(parent, MAX_VALUE); 4624 } 4625 4626 // mMultiWindowRestoreWindowingMode is INVALID for non-root tasks 4627 setRootTaskWindowingMode(mMultiWindowRestoreWindowingMode); 4628 } 4629 4630 @Override 4631 public void setWindowingMode(int windowingMode) { 4632 // Calling Task#setWindowingMode() for leaf task since this is a specialization of 4633 // {@link #setWindowingMode(int)} for root task. 4634 if (!isRootTask()) { 4635 mMultiWindowRestoreWindowingMode = INVALID_WINDOWING_MODE; 4636 super.setWindowingMode(windowingMode); 4637 return; 4638 } 4639 4640 setWindowingModeInner(windowingMode, false /* creating */); 4641 } 4642 4643 /** 4644 * Version of {@link #setWindowingMode(int)} for root tasks. 4645 * 4646 * @param preferredWindowingMode the preferred windowing mode. This may not be honored depending 4647 * on the state of things. For example, WINDOWING_MODE_UNDEFINED will resolve to the 4648 * previous non-transient mode if this root task is currently in a transient mode. 4649 */ 4650 public void setRootTaskWindowingMode(int preferredWindowingMode) { 4651 if (!isRootTask()) { 4652 Slog.wtf(TAG, "Trying to set root-task windowing-mode on a non-root-task: " + this, 4653 new Throwable()); 4654 super.setWindowingMode(preferredWindowingMode); 4655 return; 4656 } 4657 setWindowingModeInner(preferredWindowingMode, false /* creating */); 4658 } 4659 4660 /** 4661 * @param creating {@code true} if this is being run during task construction. 4662 */ 4663 private void setWindowingModeInner(int preferredWindowingMode, boolean creating) { 4664 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 4665 if (taskDisplayArea == null) { 4666 Slog.d(TAG, "taskDisplayArea is null, bail early"); 4667 return; 4668 } 4669 final int currentMode = getWindowingMode(); 4670 final Task topTask = getTopMostTask(); 4671 int windowingMode = preferredWindowingMode; 4672 4673 // Need to make sure windowing mode is supported. If we in the process of creating the 4674 // root task no need to resolve the windowing mode again as it is already resolved to the 4675 // right mode. 4676 if (!creating) { 4677 if (!taskDisplayArea.isValidWindowingMode(windowingMode, null /* ActivityRecord */, 4678 topTask)) { 4679 windowingMode = WINDOWING_MODE_UNDEFINED; 4680 } 4681 } 4682 4683 if (currentMode == windowingMode) { 4684 // You are already in the window mode, so we can skip most of the work below. However, 4685 // it's possible that we have inherited the current windowing mode from a parent. So, 4686 // fulfill this method's contract by setting the override mode directly. 4687 getRequestedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode); 4688 return; 4689 } 4690 4691 // Reset multi-window restore windowing mode. 4692 mMultiWindowRestoreWindowingMode = INVALID_WINDOWING_MODE; 4693 4694 final ActivityRecord topActivity = getTopNonFinishingActivity(); 4695 4696 // For now, assume that the root task's windowing mode is what will actually be used 4697 // by it's activities. In the future, there may be situations where this doesn't 4698 // happen; so at that point, this message will need to handle that. 4699 int likelyResolvedMode = windowingMode; 4700 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 4701 final ConfigurationContainer parent = getParent(); 4702 likelyResolvedMode = parent != null ? parent.getWindowingMode() 4703 : WINDOWING_MODE_FULLSCREEN; 4704 } 4705 if (currentMode == WINDOWING_MODE_PINNED) { 4706 // In the case that we've disabled affecting the SysUI flags as a part of seamlessly 4707 // transferring the transform on the leash to the task, reset this state once we're 4708 // moving out of pip 4709 setCanAffectSystemUiFlags(true); 4710 mRootWindowContainer.notifyActivityPipModeChanged(this, null); 4711 } 4712 if (likelyResolvedMode == WINDOWING_MODE_PINNED) { 4713 if (taskDisplayArea.getRootPinnedTask() != null) { 4714 // Can only have 1 pip at a time, so replace an existing pip 4715 taskDisplayArea.getRootPinnedTask().dismissPip(); 4716 } 4717 } 4718 if (likelyResolvedMode != WINDOWING_MODE_FULLSCREEN 4719 && topActivity != null && !topActivity.isNoDisplay() 4720 && topActivity.canForceResizeNonResizable(likelyResolvedMode)) { 4721 // Inform the user that they are starting an app that may not work correctly in 4722 // multi-window mode. 4723 final String packageName = topActivity.info.applicationInfo.packageName; 4724 mAtmService.getTaskChangeNotificationController().notifyActivityForcedResizable( 4725 topTask.mTaskId, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN, packageName); 4726 } 4727 4728 mAtmService.deferWindowLayout(); 4729 try { 4730 if (topActivity != null) { 4731 mTaskSupervisor.mNoAnimActivities.add(topActivity); 4732 } 4733 4734 final boolean isPip2ExperimentEnabled = 4735 ActivityTaskManagerService.isPip2ExperimentEnabled(); 4736 if (!isPip2ExperimentEnabled) { 4737 super.setWindowingMode(windowingMode); 4738 } 4739 4740 if (currentMode == WINDOWING_MODE_PINNED && topActivity != null) { 4741 // Try reparent pinned activity back to its original task after 4742 // onConfigurationChanged cascade finishes. This is done on Task level instead of 4743 // {@link ActivityRecord#onConfigurationChanged(Configuration)} since when we exit 4744 // PiP, we set final windowing mode on the ActivityRecord first and then on its 4745 // Task when the exit PiP transition finishes. Meanwhile, the exit transition is 4746 // always performed on its original task, reparent immediately in ActivityRecord 4747 // breaks it. Do not reparent if the pinned task is in removal, indicated by the 4748 // force hidden flag. 4749 if (topActivity.getLastParentBeforePip() != null && !isForceHidden() 4750 && topActivity.getLastParentBeforePip().isAttached()) { 4751 // We need to collect the pip activity to allow for screenshots 4752 // to be taken as a part of reparenting. 4753 mTransitionController.collect(topActivity); 4754 4755 final Task lastParentBeforePip = topActivity.getLastParentBeforePip(); 4756 // Reset the activity windowing mode to match the parent. 4757 topActivity.getRequestedOverrideConfiguration() 4758 .windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED); 4759 topActivity.reparent(lastParentBeforePip, 4760 lastParentBeforePip.getChildCount() /* top */, 4761 "movePinnedActivityToOriginalTask"); 4762 final DisplayContent dc = topActivity.getDisplayContent(); 4763 if (dc != null && dc.isFixedRotationLaunchingApp(topActivity)) { 4764 // Expanding pip into new rotation, so create a rotation leash 4765 // until the display is rotated. 4766 topActivity.getOrCreateFixedRotationLeash( 4767 topActivity.getSyncTransaction()); 4768 } 4769 lastParentBeforePip.moveToFront("movePinnedActivityToOriginalTask"); 4770 // If the reparent is not included in transition, make sure the visibility of 4771 // task is still updated by core. Otherwise if the task is collected (e.g. 4772 // rotation change) after leaving this scope, the visibility operation will be 4773 // put in sync transaction, then it is not synced with reparent. 4774 if (lastParentBeforePip.mSyncState == SYNC_STATE_NONE) { 4775 lastParentBeforePip.prepareSurfaces(); 4776 // If the moveToFront is a part of finishing transition, then make sure 4777 // the z-order of tasks are up-to-date. 4778 if (topActivity.mTransitionController.inFinishingTransition(topActivity)) { 4779 final SurfaceControl.Transaction tx = 4780 taskDisplayArea.getPendingTransaction(); 4781 Transition.assignLayers(taskDisplayArea, tx); 4782 final SurfaceControl leash = topActivity.getFixedRotationLeash(); 4783 if (leash != null) { 4784 tx.setLayer(leash, topActivity.getLastLayer()); 4785 } 4786 } 4787 } 4788 } 4789 if (isPip2ExperimentEnabled) { 4790 super.setWindowingMode(windowingMode); 4791 } 4792 // Resume app-switches-allowed flag when exiting from pinned mode since 4793 // it does not follow the ActivityStarter path. 4794 if (topActivity.shouldBeVisible()) { 4795 mAtmService.resumeAppSwitches(); 4796 // In pip1, when expanding pip to full-screen, the "behind" task is not 4797 // actually becoming invisible since task windowing mode is pinned. 4798 if (!isPip2ExperimentEnabled) { 4799 final ActivityRecord ar = mAtmService.mLastResumedActivity; 4800 if (ar != null && ar.getTask() != null) { 4801 mAtmService.takeTaskSnapshot(ar.getTask().mTaskId, 4802 true /* updateCache */); 4803 } 4804 } 4805 } 4806 } else if (isPip2ExperimentEnabled) { 4807 super.setWindowingMode(windowingMode); 4808 } 4809 4810 if (creating) { 4811 // Nothing else to do if we don't have a window container yet. E.g. call from ctor. 4812 return; 4813 } 4814 4815 // From fullscreen to PiP. 4816 if (topActivity != null && currentMode == WINDOWING_MODE_FULLSCREEN 4817 && windowingMode == WINDOWING_MODE_PINNED 4818 && !mTransitionController.isShellTransitionsEnabled()) { 4819 mDisplayContent.mPinnedTaskController 4820 .deferOrientationChangeForEnteringPipFromFullScreenIfNeeded(); 4821 } 4822 } finally { 4823 mAtmService.continueWindowLayout(); 4824 } 4825 4826 if (!mTaskSupervisor.isRootVisibilityUpdateDeferred()) { 4827 mRootWindowContainer.ensureActivitiesVisible(); 4828 mRootWindowContainer.resumeFocusedTasksTopActivities(); 4829 } 4830 } 4831 4832 /** 4833 * Abort an incomplete pip-entry. If left in this state, it will cover everything but remain 4834 * paused. If this is needed, there is a bug -- this should only be used for recovery. 4835 * 4836 * @return true if there is an inconsistency in the task and activity state. 4837 */ 4838 boolean abortPipEnter(ActivityRecord top) { 4839 // an incomplete state has the task PINNED but the activity not. 4840 if (!inPinnedWindowingMode() || top.inPinnedWindowingMode() || !canMoveTaskToBack(this)) { 4841 return false; 4842 } 4843 final Transition transition = new Transition(TRANSIT_TO_BACK, 0 /* flags */, 4844 mTransitionController, mWmService.mSyncEngine); 4845 mTransitionController.moveToCollecting(transition); 4846 mTransitionController.requestStartTransition(transition, this, null /* remoteTransition */, 4847 null /* displayChange */); 4848 if (top.getLastParentBeforePip() != null) { 4849 final Task lastParentBeforePip = top.getLastParentBeforePip(); 4850 if (lastParentBeforePip.isAttached()) { 4851 top.reparent(lastParentBeforePip, lastParentBeforePip.getChildCount() /* top */, 4852 "movePinnedActivityToOriginalTask"); 4853 } 4854 } 4855 if (isAttached()) { 4856 setRootTaskWindowingMode(WINDOWING_MODE_UNDEFINED); 4857 moveTaskToBackInner(this, null /* transition */); 4858 } 4859 if (top.isAttached()) { 4860 top.setWindowingMode(WINDOWING_MODE_UNDEFINED); 4861 top.mWaitForEnteringPinnedMode = false; 4862 } 4863 return true; 4864 } 4865 4866 void resumeNextFocusAfterReparent() { 4867 adjustFocusToNextFocusableTask("reparent", true /* allowFocusSelf */, 4868 true /* moveDisplayToTop */); 4869 mRootWindowContainer.resumeFocusedTasksTopActivities(); 4870 // Update visibility of activities before notifying WM. This way it won't try to resize 4871 // windows that are no longer visible. 4872 mRootWindowContainer.ensureActivitiesVisible(); 4873 } 4874 4875 final boolean isOnHomeDisplay() { 4876 return getDisplayId() == DEFAULT_DISPLAY; 4877 } 4878 4879 void moveToFront(String reason) { 4880 moveToFront(reason, null); 4881 } 4882 4883 /** 4884 * @param reason The reason for moving the root task to the front. 4885 * @param task If non-null, the task will be moved to the top of the root task. 4886 */ 4887 @VisibleForTesting 4888 void moveToFront(String reason, Task task) { 4889 if (!isAttached()) { 4890 return; 4891 } 4892 mTransitionController.recordTaskOrder(this); 4893 4894 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 4895 4896 if (!isActivityTypeHome() && returnsToHomeRootTask()) { 4897 // Make sure the root home task is behind this root task since that is where we 4898 // should return to when this root task is no longer visible. 4899 taskDisplayArea.moveHomeRootTaskToFront(reason + " returnToHome"); 4900 } 4901 4902 final Task lastFocusedTask = isRootTask() ? taskDisplayArea.getFocusedRootTask() : null; 4903 if (task == null) { 4904 task = this; 4905 } 4906 task.getParent().positionChildAt(POSITION_TOP, task, true /* includingParents */); 4907 taskDisplayArea.updateLastFocusedRootTask(lastFocusedTask, reason); 4908 } 4909 4910 /** 4911 * This moves 'task' to the back of this task and also recursively moves this task to the back 4912 * of its parents (if applicable). 4913 * 4914 * @param reason The reason for moving the root task to the back. 4915 * @param task If non-null, the task will be moved to the bottom of the root task. 4916 **/ 4917 void moveToBack(String reason, Task task) { 4918 if (!isAttached()) { 4919 return; 4920 } 4921 final TaskDisplayArea displayArea = getDisplayArea(); 4922 if (!mCreatedByOrganizer) { 4923 // If this is just a normal task, so move to back of parent and then move 'task' to 4924 // back of this. 4925 final WindowContainer parent = getParent(); 4926 final Task parentTask = parent != null ? parent.asTask() : null; 4927 if (parentTask != null) { 4928 parentTask.moveToBack(reason, this); 4929 } else { 4930 final Task lastFocusedTask = displayArea.getFocusedRootTask(); 4931 displayArea.positionChildAt(POSITION_BOTTOM, this, false /*includingParents*/); 4932 displayArea.updateLastFocusedRootTask(lastFocusedTask, reason); 4933 } 4934 if (task != null && task != this) { 4935 positionChildAtBottom(task); 4936 } 4937 return; 4938 } 4939 if (task == null || task == this) { 4940 return; 4941 } 4942 // This is a created-by-organizer task. In this case, let the organizer deal with this 4943 // task's ordering. However, we still need to move 'task' to back. The intention is that 4944 // this ends up behind the home-task so that it is made invisible; so, if the home task 4945 // is not a child of this, reparent 'task' to the back of the home task's actual parent. 4946 displayArea.positionTaskBehindHome(task); 4947 } 4948 4949 // TODO: Should each user have there own root tasks? 4950 @Override 4951 void switchUser(int userId) { 4952 if (mCurrentUser == userId) { 4953 return; 4954 } 4955 mCurrentUser = userId; 4956 4957 super.switchUser(userId); 4958 if (!isRootTask() && showToCurrentUser()) { 4959 getParent().positionChildAt(POSITION_TOP, this, false /*includeParents*/); 4960 } 4961 } 4962 4963 void checkReadyForSleep() { 4964 if (shouldSleepActivities() && goToSleepIfPossible(false /* shuttingDown */)) { 4965 mTaskSupervisor.checkReadyForSleepLocked(true /* allowDelay */); 4966 } 4967 } 4968 4969 /** 4970 * Tries to put the activities in the root task to sleep. 4971 * 4972 * If the root task is not in a state where its activities can be put to sleep, this function 4973 * will start any necessary actions to move the root task into such a state. It is expected 4974 * that this function get called again when those actions complete. 4975 * 4976 * @param shuttingDown true when the called because the device is shutting down. 4977 * @return true if the root task finished going to sleep, false if the root task only started 4978 * the process of going to sleep (checkReadyForSleep will be called when that process finishes). 4979 */ 4980 boolean goToSleepIfPossible(boolean shuttingDown) { 4981 final int[] sleepInProgress = {0}; 4982 forAllLeafTasksAndLeafTaskFragments(taskFragment -> { 4983 if (!taskFragment.sleepIfPossible(shuttingDown)) { 4984 sleepInProgress[0]++; 4985 } 4986 }, true /* traverseTopToBottom */); 4987 return sleepInProgress[0] == 0; 4988 } 4989 4990 boolean isTopRootTaskInDisplayArea() { 4991 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 4992 return taskDisplayArea != null && taskDisplayArea.isTopRootTask(this); 4993 } 4994 4995 /** 4996 * @return {@code true} if this is the focused root task on its current display, {@code false} 4997 * otherwise. 4998 */ 4999 boolean isFocusedRootTaskOnDisplay() { 5000 return mDisplayContent != null && this == mDisplayContent.getFocusedRootTask(); 5001 } 5002 5003 /** 5004 * Make sure that all activities that need to be visible in the root task (that is, they 5005 * currently can be seen by the user) actually are and update their configuration. 5006 * @param starting The top most activity in the task. 5007 * The activity is either starting or resuming. 5008 * Caller should ensure starting activity is visible. 5009 */ 5010 void ensureActivitiesVisible(@Nullable ActivityRecord starting) { 5011 ensureActivitiesVisible(starting, true /* notifyClients */); 5012 } 5013 5014 /** 5015 * Ensure visibility with an option to also update the configuration of visible activities. 5016 * @see #ensureActivitiesVisible(ActivityRecord) 5017 * @see RootWindowContainer#ensureActivitiesVisible() 5018 * @param starting The top most activity in the task. 5019 * The activity is either starting or resuming. 5020 * Caller should ensure starting activity is visible. 5021 * @param notifyClients Flag indicating whether the visibility updates should be sent to the 5022 * clients in {@link EnsureActivitiesVisibleHelper}. 5023 */ 5024 // TODO: Should be re-worked based on the fact that each task as a root task in most cases. 5025 void ensureActivitiesVisible(@Nullable ActivityRecord starting, boolean notifyClients) { 5026 mTaskSupervisor.beginActivityVisibilityUpdate(); 5027 try { 5028 forAllLeafTasks(task -> { 5029 task.updateActivityVisibilities(starting, notifyClients); 5030 }, true /* traverseTopToBottom */); 5031 5032 if (mTranslucentActivityWaiting != null && 5033 mUndrawnActivitiesBelowTopTranslucent.isEmpty()) { 5034 // Nothing is getting drawn or everything was already visible, don't wait for 5035 // timeout. 5036 notifyActivityDrawnLocked(null); 5037 } 5038 } finally { 5039 mTaskSupervisor.endActivityVisibilityUpdate(); 5040 } 5041 } 5042 5043 void abortTranslucentActivityWaiting(@NonNull ActivityRecord r) { 5044 if (r != mTranslucentActivityWaiting && r != mPendingConvertFromTranslucentActivity) { 5045 return; 5046 } 5047 5048 if (mTranslucentActivityWaiting != null) { 5049 if (!mTranslucentActivityWaiting.finishing) { 5050 mTranslucentActivityWaiting.setOccludesParent(true); 5051 } 5052 mTranslucentActivityWaiting = null; 5053 } 5054 if (mPendingConvertFromTranslucentActivity != null) { 5055 if (!mPendingConvertFromTranslucentActivity.finishing) { 5056 mPendingConvertFromTranslucentActivity.setOccludesParent(true); 5057 } 5058 mPendingConvertFromTranslucentActivity = null; 5059 } 5060 mUndrawnActivitiesBelowTopTranslucent.clear(); 5061 mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG); 5062 } 5063 5064 void checkTranslucentActivityWaiting(ActivityRecord top) { 5065 if (mTranslucentActivityWaiting != top) { 5066 mUndrawnActivitiesBelowTopTranslucent.clear(); 5067 if (mTranslucentActivityWaiting != null) { 5068 // Call the callback with a timeout indication. 5069 notifyActivityDrawnLocked(null); 5070 mTranslucentActivityWaiting = null; 5071 } 5072 mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG); 5073 } 5074 } 5075 5076 void convertActivityToTranslucent(ActivityRecord r) { 5077 mTranslucentActivityWaiting = r; 5078 mPendingConvertFromTranslucentActivity = r; 5079 mUndrawnActivitiesBelowTopTranslucent.clear(); 5080 updateTaskDescription(); 5081 mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT); 5082 } 5083 5084 void convertActivityFromTranslucent(ActivityRecord r) { 5085 if (r != mPendingConvertFromTranslucentActivity) { 5086 Slog.e(TAG, "convertFromTranslucent expects " + mPendingConvertFromTranslucentActivity 5087 + " but is " + r); 5088 } 5089 mPendingConvertFromTranslucentActivity = null; 5090 updateTaskDescription(); 5091 } 5092 5093 /** 5094 * Called as activities below the top translucent activity are redrawn. When the last one is 5095 * redrawn notify the top activity by calling 5096 * {@link Activity#onTranslucentConversionComplete}. 5097 * 5098 * @param r The most recent background activity to be drawn. Or, if r is null then a timeout 5099 * occurred and the activity will be notified immediately. 5100 */ 5101 void notifyActivityDrawnLocked(ActivityRecord r) { 5102 if ((r == null) 5103 || (mUndrawnActivitiesBelowTopTranslucent.remove(r) && 5104 mUndrawnActivitiesBelowTopTranslucent.isEmpty())) { 5105 // The last undrawn activity below the top has just been drawn. If there is an 5106 // opaque activity at the top, notify it that it can become translucent safely now. 5107 final ActivityRecord waitingActivity = mTranslucentActivityWaiting; 5108 mTranslucentActivityWaiting = null; 5109 mUndrawnActivitiesBelowTopTranslucent.clear(); 5110 mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG); 5111 5112 if (waitingActivity != null) { 5113 waitingActivity.setMainWindowOpaque(false); 5114 if (waitingActivity.attachedToProcess()) { 5115 try { 5116 waitingActivity.app.getThread().scheduleTranslucentConversionComplete( 5117 waitingActivity.token, r != null); 5118 } catch (RemoteException e) { 5119 } 5120 } 5121 } 5122 } 5123 } 5124 5125 /** 5126 * Ensure that the top activity in the root task is resumed. 5127 * 5128 * @param prev The previously resumed activity, for when in the process 5129 * of pausing; can be null to call from elsewhere. 5130 * @param options Activity options. 5131 * @param deferPause When {@code true}, this will not pause back tasks. 5132 * 5133 * @return Returns true if something is being resumed, or false if 5134 * nothing happened. 5135 * 5136 * NOTE: It is not safe to call this method directly as it can cause an activity in a 5137 * non-focused root task to be resumed. 5138 * Use {@link RootWindowContainer#resumeFocusedTasksTopActivities} to resume the 5139 * right activity for the current system state. 5140 */ 5141 @GuardedBy("mService") 5142 boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options, 5143 boolean deferPause) { 5144 if (mInResumeTopActivity) { 5145 // Don't even start recursing. 5146 return false; 5147 } 5148 5149 boolean someActivityResumed = false; 5150 try { 5151 // Protect against recursion. 5152 mInResumeTopActivity = true; 5153 5154 if (isLeafTask()) { 5155 if (isFocusableAndVisible()) { 5156 someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause); 5157 } 5158 } else { 5159 int idx = mChildren.size() - 1; 5160 while (idx >= 0) { 5161 final Task child = (Task) getChildAt(idx--); 5162 if (!child.isTopActivityFocusable()) { 5163 continue; 5164 } 5165 if (child.getVisibility(null /* starting */) 5166 != TASK_FRAGMENT_VISIBILITY_VISIBLE) { 5167 if (child.topRunningActivity() == null) { 5168 // Skip the task if no running activity and continue resuming next task. 5169 continue; 5170 } 5171 // Otherwise, assuming everything behind this task should also be invisible. 5172 break; 5173 } 5174 5175 someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options, 5176 deferPause); 5177 // Doing so in order to prevent IndexOOB since hierarchy might changes while 5178 // resuming activities, for example dismissing split-screen while starting 5179 // non-resizeable activity. 5180 if (idx >= mChildren.size()) { 5181 idx = mChildren.size() - 1; 5182 } 5183 } 5184 } 5185 5186 // When resuming the top activity, it may be necessary to pause the top activity (for 5187 // example, returning to the lock screen. We suppress the normal pause logic in 5188 // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the 5189 // end. We call the {@link ActivityTaskSupervisor#checkReadyForSleepLocked} again here 5190 // to ensure any necessary pause logic occurs. In the case where the Activity will be 5191 // shown regardless of the lock screen, the call to 5192 // {@link ActivityTaskSupervisor#checkReadyForSleepLocked} is skipped. 5193 if (shouldSleepActivities()) { 5194 final ActivityRecord next = topRunningActivity(true /* focusableOnly */); 5195 if (next != null && next.canTurnScreenOn() 5196 && !mWmService.mPowerManager.isInteractive()) { 5197 mTaskSupervisor.wakeUp(getDisplayId(), "resumeTop-turnScreenOnFlag"); 5198 next.setCurrentLaunchCanTurnScreenOn(false); 5199 } else { 5200 checkReadyForSleep(); 5201 } 5202 } 5203 } finally { 5204 mInResumeTopActivity = false; 5205 } 5206 5207 return someActivityResumed; 5208 } 5209 5210 @GuardedBy("mService") 5211 boolean resumeTopActivityUncheckedLocked() { 5212 return resumeTopActivityUncheckedLocked(null /* prev */, null /* options */, 5213 false /* skipPause */); 5214 } 5215 5216 @GuardedBy("mService") 5217 private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options, 5218 boolean deferPause) { 5219 if (!mAtmService.isBooting() && !mAtmService.isBooted()) { 5220 // Not ready yet! 5221 return false; 5222 } 5223 5224 if (!mTaskSupervisor.readyToResume()) { 5225 return false; 5226 } 5227 5228 final ActivityRecord topActivity = topRunningActivity(true /* focusableOnly */); 5229 if (topActivity == null) { 5230 // There are no activities left in this task, let's look somewhere else. 5231 return resumeNextFocusableActivityWhenRootTaskIsEmpty(prev, options); 5232 } 5233 5234 final boolean[] resumed = new boolean[1]; 5235 final TaskFragment topFragment = topActivity.getTaskFragment(); 5236 forAllLeafTaskFragments(f -> { 5237 if (topFragment == f) { 5238 return; 5239 } 5240 if (!f.canBeResumed(null /* starting */)) { 5241 return; 5242 } 5243 resumed[0] |= f.resumeTopActivity(prev, options, deferPause); 5244 }, true); 5245 resumed[0] |= topFragment.resumeTopActivity(prev, options, deferPause); 5246 return resumed[0]; 5247 } 5248 5249 /** 5250 * Resume the next eligible activity in a focusable root task when this one does not have any 5251 * running activities left. The focus will be adjusted to the next focusable root task and 5252 * top running activities will be resumed in all focusable root tasks. However, if the 5253 * current root task is a root home task - we have to keep it focused, start and resume a 5254 * home activity on the current display instead to make sure that the display is not empty. 5255 */ 5256 private boolean resumeNextFocusableActivityWhenRootTaskIsEmpty(ActivityRecord prev, 5257 ActivityOptions options) { 5258 final String reason = "noMoreActivities"; 5259 5260 if (!isActivityTypeHome()) { 5261 final Task nextFocusedTask = adjustFocusToNextFocusableTask(reason); 5262 if (nextFocusedTask != null) { 5263 // Try to move focus to the next visible root task with a running activity if this 5264 // root task is not covering the entire screen or is on a secondary display with 5265 // no home root task. 5266 return mRootWindowContainer.resumeFocusedTasksTopActivities(nextFocusedTask, prev); 5267 } 5268 } 5269 5270 // If the current root task is a root home task, or if focus didn't switch to a different 5271 // root task - just start up the Launcher... 5272 ActivityOptions.abort(options); 5273 ProtoLog.d(WM_DEBUG_STATES, "resumeNextFocusableActivityWhenRootTaskIsEmpty: %s, " 5274 + "go home", reason); 5275 return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayArea()); 5276 } 5277 5278 void startActivityLocked(@NonNull ActivityRecord r, @Nullable Task topTask, boolean newTask, 5279 boolean isTaskSwitch, @Nullable ActivityOptions options, 5280 @Nullable ActivityRecord sourceRecord) { 5281 final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront(); 5282 final Task activityTask = r.getTask(); 5283 final boolean isThisOrHasChildTask = activityTask == this || hasChild(activityTask); 5284 5285 // mLaunchTaskBehind tasks get placed at the back of the task stack. 5286 if (!r.mLaunchTaskBehind && allowMoveToFront && (!isThisOrHasChildTask || newTask)) { 5287 // Last activity in task had been removed or ActivityManagerService is reusing task. 5288 // Insert or replace. 5289 // Might not even be in. 5290 positionChildAtTop(activityTask); 5291 } 5292 5293 if (!newTask && isThisOrHasChildTask && !r.shouldBeVisible()) { 5294 ActivityOptions.abort(options); 5295 return; 5296 } 5297 5298 // Slot the activity into the history root task and proceed 5299 ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to task %s callers: %s", r, 5300 activityTask, new RuntimeException("here").fillInStackTrace()); 5301 5302 if (isActivityTypeHomeOrRecents() && getActivityBelow(r) == null) { 5303 // If this is the first activity, don't do any fancy animations, 5304 // because there is nothing for it to animate on top of. 5305 ActivityOptions.abort(options); 5306 return; 5307 } 5308 5309 if (!allowMoveToFront) { 5310 // The transition animation and starting window are not needed if 5311 // {@code allowMoveToFront} is false, because the activity won't be visible. 5312 ActivityOptions.abort(options); 5313 return; 5314 } 5315 5316 if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: starting " + r); 5317 5318 // Place a new activity at top of root task, so it is next to interact with the user. 5319 if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) { 5320 mTaskSupervisor.mNoAnimActivities.add(r); 5321 mTransitionController.setNoAnimation(r); 5322 } else { 5323 mTaskSupervisor.mNoAnimActivities.remove(r); 5324 } 5325 if (newTask && !r.mLaunchTaskBehind) { 5326 // If a new task is being launched, then mark the existing top activity as 5327 // supporting picture-in-picture while pausing only if the starting activity 5328 // would not be considered an overlay on top of the current activity 5329 // (eg. not fullscreen, or the assistant) 5330 if (!ActivityTaskManagerService.isPip2ExperimentEnabled()) { 5331 final ActivityRecord pipCandidate = findEnterPipOnTaskSwitchCandidate(topTask); 5332 enableEnterPipOnTaskSwitch(pipCandidate, null /* toFrontTask */, r, options); 5333 } 5334 } 5335 boolean doShow = true; 5336 if (newTask) { 5337 // Even though this activity is starting fresh, we still need 5338 // to reset it to make sure we apply affinities to move any 5339 // existing activities from other tasks in to it. 5340 // If the caller has requested that the target task be 5341 // reset, then do so. 5342 if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { 5343 resetTaskIfNeeded(r, r); 5344 doShow = topRunningNonDelayedActivityLocked(null) == r; 5345 } 5346 } else if (options != null && options.getAnimationType() 5347 == ActivityOptions.ANIM_SCENE_TRANSITION) { 5348 doShow = false; 5349 } 5350 if (options != null && options.getDisableStartingWindow()) { 5351 doShow = false; 5352 } 5353 if (r.mLaunchTaskBehind) { 5354 // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we 5355 // tell WindowManager that r is visible even though it is at the back of the root 5356 // task. 5357 r.setVisibility(true); 5358 ensureActivitiesVisible(null /* starting */); 5359 // If launching behind, the app will start regardless of what's above it, so mark it 5360 // as unknown even before prior `pause`. This also prevents a race between set-ready 5361 // and activityPause. Launch-behind is basically only used for dream now. 5362 if (!r.isVisibleRequested()) { 5363 r.notifyUnknownVisibilityLaunchedForKeyguardTransition(); 5364 } 5365 // Go ahead to execute app transition for this activity since the app transition 5366 // will not be triggered through the resume channel. 5367 mDisplayContent.executeAppTransition(); 5368 } else if (SHOW_APP_STARTING_PREVIEW && doShow) { 5369 // Figure out if we are transitioning from another activity that is 5370 // "has the same starting icon" as the next one. This allows the 5371 // window manager to keep the previous window it had previously 5372 // created, if it still had one. 5373 final ActivityRecord prev = activityTask.getActivity( 5374 a -> a.mStartingData != null && a.showToCurrentUser()); 5375 mWmService.mStartingSurfaceController.showStartingWindow(r, prev, newTask, 5376 isTaskSwitch, sourceRecord); 5377 } 5378 } 5379 5380 /** On Task switch, finds the top activity that supports PiP. */ 5381 @Nullable 5382 static ActivityRecord findEnterPipOnTaskSwitchCandidate(@Nullable Task topTask) { 5383 if (topTask == null) { 5384 return null; 5385 } 5386 final ActivityRecord[] candidate = new ActivityRecord[1]; 5387 topTask.forAllLeafTaskFragments(tf -> { 5388 // Find the top activity that may enter Pip while pausing. 5389 final ActivityRecord topActivity = tf.getTopNonFinishingActivity(); 5390 if (topActivity != null && topActivity.isState(RESUMED, PAUSING) 5391 && topActivity.supportsPictureInPicture()) { 5392 candidate[0] = topActivity; 5393 return true; 5394 } 5395 return false; 5396 }); 5397 return candidate[0]; 5398 } 5399 5400 /** 5401 * When switching to another Task, marks the currently PiP candidate activity as supporting to 5402 * enter PiP while it is pausing (if supported). Only one of {@param toFrontTask} or 5403 * {@param toFrontActivity} should be set. 5404 */ 5405 static void enableEnterPipOnTaskSwitch(@Nullable ActivityRecord pipCandidate, 5406 @Nullable Task toFrontTask, @Nullable ActivityRecord toFrontActivity, 5407 @Nullable ActivityOptions opts) { 5408 if (pipCandidate == null) { 5409 return; 5410 } 5411 if (opts != null && opts.disallowEnterPictureInPictureWhileLaunching()) { 5412 // Ensure the caller has requested not to trigger auto-enter PiP 5413 return; 5414 } 5415 if (pipCandidate.inPinnedWindowingMode()) { 5416 // Ensure that we do not trigger entering PiP an activity on the root pinned task. 5417 return; 5418 } 5419 final Task targetRootTask = toFrontTask != null ? toFrontTask.getRootTask() 5420 : toFrontActivity != null ? toFrontActivity.getRootTask() : null; 5421 if (targetRootTask == null) { 5422 Slog.e(TAG, "No root task for enter pip, both to front task and activity are null?"); 5423 return; 5424 } 5425 final boolean isTransient = opts != null && opts.getTransientLaunch() 5426 || (targetRootTask.mTransitionController.isTransientHide(targetRootTask)); 5427 5428 // Ensure the task/activity being brought forward is not the assistant and is not transient 5429 // nor transient hide target. In the case of transient-launch, we want to wait until the end 5430 // of the transition and only allow to enter pip on task switch after the transient launch 5431 // was committed. 5432 pipCandidate.supportsEnterPipOnTaskSwitch = !targetRootTask.isActivityTypeAssistant() 5433 && !isTransient; 5434 } 5435 5436 /** 5437 * Reset the task by reparenting the activities that have same affinity to the task or 5438 * reparenting the activities that have different affinityies out of the task, while these 5439 * activities allow task reparenting. 5440 * 5441 * @param taskTop Top activity of the task might be reset. 5442 * @param newActivity The activity that going to be started. 5443 * @return The non-finishing top activity of the task after reset or the original task top 5444 * activity if all activities within the task are finishing. 5445 */ 5446 ActivityRecord resetTaskIfNeeded(ActivityRecord taskTop, ActivityRecord newActivity) { 5447 final boolean forceReset = 5448 (newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0; 5449 final Task task = taskTop.getTask(); 5450 5451 // If ActivityOptions are moved out and need to be aborted or moved to taskTop. 5452 final ActivityOptions topOptions; 5453 5454 // Set the task to be reused, so the TaskFragment#mClearedTaskForReuse can be set if the 5455 // embedded activities are finished while reset task. 5456 mReuseTask = true; 5457 try { 5458 topOptions = sResetTargetTaskHelper.process(task, forceReset); 5459 } finally { 5460 mReuseTask = false; 5461 } 5462 5463 if (mChildren.contains(task)) { 5464 final ActivityRecord newTop = task.getTopNonFinishingActivity(); 5465 if (newTop != null) { 5466 taskTop = newTop; 5467 } 5468 } 5469 5470 if (topOptions != null) { 5471 // If we got some ActivityOptions from an activity on top that 5472 // was removed from the task, propagate them to the new real top. 5473 taskTop.updateOptionsLocked(topOptions); 5474 } 5475 5476 return taskTop; 5477 } 5478 5479 /** 5480 * Finish the topmost activity that belongs to the crashed app. We may also finish the activity 5481 * that requested launch of the crashed one to prevent launch-crash loop. 5482 * @param app The app that crashed. 5483 * @param reason Reason to perform this action. 5484 * @return The task that was finished in this root task, {@code null} if top running activity 5485 * does not belong to the crashed app. 5486 */ 5487 final Task finishTopCrashedActivityLocked(WindowProcessController app, String reason) { 5488 final ActivityRecord r = topRunningActivity(); 5489 if (r == null || r.app != app) { 5490 return null; 5491 } 5492 if (r.isActivityTypeHome() && mAtmService.mHomeProcess == app) { 5493 // Home activities should not be force-finished as we have nothing else to go 5494 // back to. AppErrors will get to it after two crashes in MIN_CRASH_INTERVAL. 5495 Slog.w(TAG, " Not force finishing home activity " 5496 + r.intent.getComponent().flattenToShortString()); 5497 return null; 5498 } 5499 Slog.w(TAG, " Force finishing activity " 5500 + r.intent.getComponent().flattenToShortString()); 5501 Task finishedTask = r.getTask(); 5502 mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED, 5503 finishedTask); 5504 r.finishIfPossible(reason, false /* oomAdj */); 5505 5506 // Also terminate any activities below it that aren't yet stopped, to avoid a situation 5507 // where one will get re-start our crashing activity once it gets resumed again. 5508 final ActivityRecord activityBelow = getActivityBelow(r); 5509 if (activityBelow != null) { 5510 if (activityBelow.isState(STARTED, RESUMED, PAUSING, PAUSED)) { 5511 if (!activityBelow.isActivityTypeHome() 5512 || mAtmService.mHomeProcess != activityBelow.app) { 5513 Slog.w(TAG, " Force finishing activity " 5514 + activityBelow.intent.getComponent().flattenToShortString()); 5515 activityBelow.finishIfPossible(reason, false /* oomAdj */); 5516 } 5517 } 5518 } 5519 5520 return finishedTask; 5521 } 5522 5523 void finishIfVoiceTask(IBinder binder) { 5524 if (voiceSession != null && voiceSession.asBinder() == binder) { 5525 forAllActivities((r) -> { 5526 if (r.finishing) return; 5527 r.finishIfPossible("finish-voice", false /* oomAdj */); 5528 mAtmService.updateOomAdj(); 5529 }); 5530 } else { 5531 // Check if any of the activities are using voice 5532 final PooledPredicate f = PooledLambda.obtainPredicate( 5533 Task::finishIfVoiceActivity, PooledLambda.__(ActivityRecord.class), 5534 binder); 5535 forAllActivities(f); 5536 f.recycle(); 5537 } 5538 } 5539 5540 private static boolean finishIfVoiceActivity(ActivityRecord r, IBinder binder) { 5541 if (r.voiceSession == null || r.voiceSession.asBinder() != binder) return false; 5542 // Inform of cancellation 5543 r.clearVoiceSessionLocked(); 5544 try { 5545 r.app.getThread().scheduleLocalVoiceInteractionStarted(r.token, null); 5546 } catch (RemoteException re) { 5547 // Ok Boomer... 5548 } 5549 r.mAtmService.finishRunningVoiceLocked(); 5550 return true; 5551 } 5552 5553 /** @return true if the root task behind this one is a standard activity type. */ 5554 private boolean inFrontOfStandardRootTask() { 5555 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 5556 if (taskDisplayArea == null) { 5557 return false; 5558 } 5559 final boolean[] hasFound = new boolean[1]; 5560 final Task rootTaskBehind = taskDisplayArea.getRootTask( 5561 // From top to bottom, find the one behind this Task. 5562 task -> { 5563 if (hasFound[0]) { 5564 return true; 5565 } 5566 if (task == this) { 5567 // The next one is our target. 5568 hasFound[0] = true; 5569 } 5570 return false; 5571 }); 5572 return rootTaskBehind != null && rootTaskBehind.isActivityTypeStandard(); 5573 } 5574 5575 boolean shouldUpRecreateTaskLocked(ActivityRecord srec, String destAffinity) { 5576 // Basic case: for simple app-centric recents, we need to recreate 5577 // the task if the affinity has changed. 5578 5579 final String affinity = ActivityRecord.computeTaskAffinity(destAffinity, srec.getUid()); 5580 if (srec == null || srec.getTask().affinity == null 5581 || !srec.getTask().affinity.equals(affinity)) { 5582 return true; 5583 } 5584 // Document-centric case: an app may be split in to multiple documents; 5585 // they need to re-create their task if this current activity is the root 5586 // of a document, unless simply finishing it will return them to the 5587 // correct app behind. 5588 final Task task = srec.getTask(); 5589 if (srec.isRootOfTask() && task.getBaseIntent() != null 5590 && task.getBaseIntent().isDocument()) { 5591 // Okay, this activity is at the root of its task. What to do, what to do... 5592 if (!inFrontOfStandardRootTask()) { 5593 // Finishing won't return to an application, so we need to recreate. 5594 return true; 5595 } 5596 // We now need to get the task below it to determine what to do. 5597 final Task prevTask = getTaskBelow(task); 5598 if (prevTask == null) { 5599 Slog.w(TAG, "shouldUpRecreateTask: task not in history for " + srec); 5600 return false; 5601 } 5602 if (!task.affinity.equals(prevTask.affinity)) { 5603 // These are different apps, so need to recreate. 5604 return true; 5605 } 5606 } 5607 return false; 5608 } 5609 5610 boolean navigateUpTo(ActivityRecord srec, Intent destIntent, String resolvedType, 5611 NeededUriGrants destGrants, int resultCode, Intent resultData, 5612 NeededUriGrants resultGrants) { 5613 if (!srec.attachedToProcess()) { 5614 // Nothing to do if the caller is not attached, because this method should be called 5615 // from an alive activity. 5616 return false; 5617 } 5618 final Task task = srec.getTask(); 5619 if (!srec.isDescendantOf(this)) { 5620 return false; 5621 } 5622 5623 ActivityRecord parent = task.getActivityBelow(srec); 5624 boolean foundParentInTask = false; 5625 final ComponentName dest = destIntent.getComponent(); 5626 if (task.getBottomMostActivity() != srec && dest != null) { 5627 final ActivityRecord candidate = task.getActivity( 5628 (ar) -> ar.info.packageName.equals(dest.getPackageName()) 5629 && ar.info.name.equals(dest.getClassName()), srec, 5630 false /*includeBoundary*/, true /*traverseTopToBottom*/); 5631 if (candidate != null) { 5632 parent = candidate; 5633 foundParentInTask = true; 5634 } 5635 } 5636 5637 // TODO: There is a dup. of this block of code in ActivityTaskManagerService.finishActivity 5638 // We should consolidate. 5639 IActivityController controller = mAtmService.mController; 5640 if (controller != null) { 5641 ActivityRecord next = topRunningActivity(srec.token, INVALID_TASK_ID); 5642 if (next != null) { 5643 // ask watcher if this is allowed 5644 boolean resumeOK = true; 5645 try { 5646 resumeOK = controller.activityResuming(next.packageName); 5647 } catch (RemoteException e) { 5648 mAtmService.mController = null; 5649 Watchdog.getInstance().setActivityController(null); 5650 } 5651 5652 if (!resumeOK) { 5653 return false; 5654 } 5655 } 5656 } 5657 final long origId = Binder.clearCallingIdentity(); 5658 5659 final int[] resultCodeHolder = new int[1]; 5660 resultCodeHolder[0] = resultCode; 5661 final Intent[] resultDataHolder = new Intent[1]; 5662 resultDataHolder[0] = resultData; 5663 final NeededUriGrants[] resultGrantsHolder = new NeededUriGrants[1]; 5664 resultGrantsHolder[0] = resultGrants; 5665 final ActivityRecord finalParent = parent; 5666 task.forAllActivities((ar) -> { 5667 if (ar == finalParent) return true; 5668 5669 ar.finishIfPossible(resultCodeHolder[0], resultDataHolder[0], resultGrantsHolder[0], 5670 "navigate-up", true /* oomAdj */); 5671 // Only return the supplied result for the first activity finished 5672 resultCodeHolder[0] = Activity.RESULT_CANCELED; 5673 resultDataHolder[0] = null; 5674 return false; 5675 }, srec, true, true); 5676 resultCode = resultCodeHolder[0]; 5677 resultData = resultDataHolder[0]; 5678 5679 if (parent != null && foundParentInTask) { 5680 final int callingUid = srec.info.applicationInfo.uid; 5681 // TODO(b/64750076): Check if calling pid should really be -1. 5682 final int res = mAtmService.getActivityStartController() 5683 .obtainStarter(destIntent, "navigateUpTo") 5684 .setResolvedType(resolvedType) 5685 .setUserId(srec.mUserId) 5686 .setCaller(srec.app.getThread()) 5687 .setResultTo(parent.token) 5688 .setIntentGrants(destGrants) 5689 .setCallingPid(-1) 5690 .setCallingUid(callingUid) 5691 .setCallingPackage(srec.packageName) 5692 .setCallingFeatureId(parent.launchedFromFeatureId) 5693 .setRealCallingPid(-1) 5694 .setRealCallingUid(callingUid) 5695 .setComponentSpecified(true) 5696 .execute(); 5697 foundParentInTask = isStartResultSuccessful(res); 5698 if (res == ActivityManager.START_SUCCESS) { 5699 parent.finishIfPossible(resultCode, resultData, resultGrants, 5700 "navigate-top", true /* oomAdj */); 5701 } 5702 } 5703 Binder.restoreCallingIdentity(origId); 5704 return foundParentInTask; 5705 } 5706 5707 private void updateTransitLocked(@WindowManager.TransitionType int transit, 5708 ActivityOptions options) { 5709 if (options != null) { 5710 ActivityRecord r = topRunningActivity(); 5711 if (r != null && !r.isState(RESUMED)) { 5712 r.updateOptionsLocked(options); 5713 } else { 5714 ActivityOptions.abort(options); 5715 } 5716 } 5717 } 5718 5719 final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options, 5720 AppTimeTracker timeTracker, String reason) { 5721 moveTaskToFront(tr, noAnimation, options, timeTracker, !DEFER_RESUME, reason); 5722 } 5723 5724 final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options, 5725 AppTimeTracker timeTracker, boolean deferResume, String reason) { 5726 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr); 5727 5728 final ActivityRecord pipCandidate = findEnterPipOnTaskSwitchCandidate( 5729 getDisplayArea().getTopRootTask()); 5730 5731 if (tr != this && !tr.isDescendantOf(this)) { 5732 // nothing to do! 5733 if (noAnimation) { 5734 ActivityOptions.abort(options); 5735 } else { 5736 updateTransitLocked(TRANSIT_TO_FRONT, options); 5737 } 5738 return; 5739 } 5740 5741 if (timeTracker != null) { 5742 // The caller wants a time tracker associated with this task. 5743 tr.forAllActivities(a -> { a.appTimeTracker = timeTracker; }); 5744 } 5745 5746 try { 5747 // Defer updating the IME target since the new IME target will try to get computed 5748 // before updating all closing and opening apps, which can cause the ime target to 5749 // get calculated incorrectly. 5750 mDisplayContent.deferUpdateImeTarget(); 5751 5752 // Don't refocus if invisible to current user 5753 final ActivityRecord top = tr.getTopNonFinishingActivity(); 5754 if (top == null || !top.showToCurrentUser()) { 5755 positionChildAtTop(tr); 5756 if (top != null) { 5757 mTaskSupervisor.mRecentTasks.add(top.getTask()); 5758 } 5759 ActivityOptions.abort(options); 5760 return; 5761 } 5762 5763 // Set focus to the top running activity of this task and move all its parents to top. 5764 top.moveFocusableActivityToTop(reason); 5765 5766 if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr); 5767 if (noAnimation) { 5768 mTaskSupervisor.mNoAnimActivities.add(top); 5769 mTransitionController.collect(top); 5770 mTransitionController.setNoAnimation(top); 5771 ActivityOptions.abort(options); 5772 } else { 5773 updateTransitLocked(TRANSIT_TO_FRONT, options); 5774 } 5775 5776 // If a new task is moved to the front, then mark the existing top activity as 5777 // supporting 5778 5779 // picture-in-picture while paused only if the task would not be considered an oerlay 5780 // on top 5781 // of the current activity (eg. not fullscreen, or the assistant) 5782 enableEnterPipOnTaskSwitch(pipCandidate, tr, null /* toFrontActivity */, options); 5783 5784 if (!deferResume) { 5785 mRootWindowContainer.resumeFocusedTasksTopActivities(); 5786 } 5787 } finally { 5788 mDisplayContent.continueUpdateImeTarget(); 5789 } 5790 } 5791 5792 private boolean canMoveTaskToBack(Task task) { 5793 // Checks whether a task is a child of this task because it can be reparented when 5794 // transition is deferred. 5795 if (task != this && !task.isDescendantOf(this)) { 5796 return false; 5797 } 5798 5799 // In LockTask mode, moving a locked task to the back of the root task may expose unlocked 5800 // ones. Therefore we need to check if this operation is allowed. 5801 if (!mAtmService.getLockTaskController().canMoveTaskToBack(task)) { 5802 return false; 5803 } 5804 5805 // If we have a watcher, preflight the move before committing to it. 5806 // Checks for other available tasks; however, if none are available, skips because this 5807 // is the bottommost task. 5808 if (mAtmService.mController != null && isTopRootTaskInDisplayArea()) { 5809 final ActivityRecord next = getDisplayArea().getActivity( 5810 a -> isTopRunning(a, task.mTaskId, null /* notTop */)); 5811 if (next != null) { 5812 if (next.isState(RESUMED)) { 5813 return true; 5814 } 5815 // ask watcher if this is allowed 5816 boolean moveOK = true; 5817 try { 5818 moveOK = mAtmService.mController.activityResuming(next.packageName); 5819 } catch (RemoteException e) { 5820 mAtmService.mController = null; 5821 Watchdog.getInstance().setActivityController(null); 5822 } 5823 if (!moveOK) { 5824 return false; 5825 } 5826 } 5827 } 5828 return true; 5829 } 5830 5831 /** 5832 * Worker method for rearranging history task. Implements the function of moving all 5833 * activities for a specific task (gathering them if disjoint) into a single group at the 5834 * bottom of the root task. 5835 * 5836 * If a watcher is installed, the action is preflighted and the watcher has an opportunity 5837 * to premeptively cancel the move. 5838 * 5839 * If this is a pinned task, it will be removed instead of rearranged. 5840 * 5841 * @param tr The task to collect and move to the bottom. 5842 * @return Returns true if the move completed, false if not. 5843 */ 5844 boolean moveTaskToBack(Task tr) { 5845 Slog.i(TAG, "moveTaskToBack: " + tr); 5846 5847 if (!canMoveTaskToBack(tr)) return false; 5848 5849 if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task=" 5850 + tr.mTaskId); 5851 5852 if (mTransitionController.isShellTransitionsEnabled()) { 5853 // TODO(b/277838915): Consider to make it concurrent to eliminate the special case. 5854 final Transition collecting = mTransitionController.getCollectingTransition(); 5855 if (collecting != null && collecting.mType == TRANSIT_OPEN) { 5856 // It can be a CLOSING participate of an OPEN transition. This avoids the deferred 5857 // transition from moving task to back after the task was moved to front. 5858 collecting.collect(tr); 5859 moveTaskToBackInner(tr, collecting); 5860 return true; 5861 } 5862 final Transition transition = new Transition(TRANSIT_TO_BACK, 0 /* flags */, 5863 mTransitionController, mWmService.mSyncEngine); 5864 // Guarantee that this gets its own transition by queueing on SyncEngine 5865 mTransitionController.startCollectOrQueue(transition, 5866 (deferred) -> { 5867 // Need to check again if deferred since the system might 5868 // be in a different state. 5869 if (!tr.isAttached() || (deferred && !canMoveTaskToBack(tr))) { 5870 Slog.e(TAG, "Failed to move task to back after saying we could: " 5871 + tr.mTaskId); 5872 transition.abort(); 5873 return; 5874 } 5875 mTransitionController.requestStartTransition(transition, tr, 5876 null /* remoteTransition */, null /* displayChange */); 5877 mTransitionController.collect(tr); 5878 moveTaskToBackInner(tr, transition); 5879 }); 5880 } else { 5881 moveTaskToBackInner(tr, null /* transition */); 5882 } 5883 return true; 5884 } 5885 5886 private void moveTaskToBackInner(@NonNull Task task, @Nullable Transition transition) { 5887 final Transition.ReadyCondition movedToBack = 5888 new Transition.ReadyCondition("moved-to-back", task); 5889 if (transition != null) { 5890 // Preventing from update surface position for WindowState if configuration changed, 5891 // because the position is depends on WindowFrame, so update the position before 5892 // relayout will only update it to "old" position. 5893 mAtmService.deferWindowLayout(); 5894 transition.mReadyTracker.add(movedToBack); 5895 } 5896 try { 5897 moveToBack("moveTaskToBackInner", task); 5898 5899 if (inPinnedWindowingMode()) { 5900 mTaskSupervisor.removeRootTask(this); 5901 return; 5902 } 5903 5904 mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */, 5905 mDisplayContent, false /* deferResume */); 5906 } finally { 5907 if (mTransitionController.isShellTransitionsEnabled()) { 5908 mAtmService.continueWindowLayout(); 5909 } 5910 if (transition != null) { 5911 movedToBack.meet(); 5912 } 5913 } 5914 ActivityRecord topActivity = getDisplayArea().topRunningActivity(); 5915 Task topRootTask = topActivity == null ? null : topActivity.getRootTask(); 5916 if (topRootTask != null && topRootTask != this && topActivity.isState(RESUMED)) { 5917 // Usually resuming a top activity triggers the next app transition, but nothing's got 5918 // resumed in this case, so we need to execute it explicitly. 5919 mDisplayContent.executeAppTransition(); 5920 mDisplayContent.setFocusedApp(topActivity); 5921 } else { 5922 mRootWindowContainer.resumeFocusedTasksTopActivities(); 5923 } 5924 } 5925 5926 boolean willActivityBeVisible(IBinder token) { 5927 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 5928 if (r == null) { 5929 return false; 5930 } 5931 5932 if (!r.shouldBeVisible()) return false; 5933 5934 if (r.finishing) Slog.e(TAG, "willActivityBeVisible: Returning false," 5935 + " would have returned true for r=" + r); 5936 return !r.finishing; 5937 } 5938 5939 void unhandledBackLocked() { 5940 final ActivityRecord topActivity = getTopMostActivity(); 5941 if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, 5942 "Performing unhandledBack(): top activity: " + topActivity); 5943 if (topActivity != null) { 5944 topActivity.finishIfPossible("unhandled-back", true /* oomAdj */); 5945 } 5946 } 5947 5948 boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, 5949 String dumpPackage, final boolean needSep) { 5950 return dump(" ", fd, pw, dumpAll, dumpClient, dumpPackage, needSep, null /* header */); 5951 } 5952 5953 @Override 5954 void dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage) { 5955 super.dumpInner(prefix, pw, dumpAll, dumpPackage); 5956 if (mCreatedByOrganizer) { 5957 pw.println(prefix + " mCreatedByOrganizer=true"); 5958 if (mOffsetXForInsets != 0 || mOffsetYForInsets != 0) { 5959 pw.println(prefix + " mOffsetXForInsets=" + mOffsetXForInsets 5960 + " mOffsetYForInsets=" + mOffsetYForInsets); 5961 } 5962 } 5963 if (mLastNonFullscreenBounds != null) { 5964 pw.print(prefix); pw.print(" mLastNonFullscreenBounds="); 5965 pw.println(mLastNonFullscreenBounds); 5966 } 5967 if (mNonOccludedFreeformAreaRatio != 0) { 5968 pw.print(prefix); pw.print(" mNonOccludedFreeformAreaRatio="); 5969 pw.println(mNonOccludedFreeformAreaRatio); 5970 } 5971 if (isLeafTask()) { 5972 pw.println(prefix + " isSleeping=" + shouldSleepActivities()); 5973 printThisActivity(pw, getTopPausingActivity(), dumpPackage, false, 5974 prefix + " topPausingActivity=", null); 5975 printThisActivity(pw, getTopResumedActivity(), dumpPackage, false, 5976 prefix + " topResumedActivity=", null); 5977 if (mMinWidth != INVALID_MIN_SIZE || mMinHeight != INVALID_MIN_SIZE) { 5978 pw.print(prefix); pw.print(" mMinWidth="); pw.print(mMinWidth); 5979 pw.print(" mMinHeight="); pw.println(mMinHeight); 5980 } 5981 } 5982 } 5983 5984 ArrayList<ActivityRecord> getDumpActivitiesLocked(String name, @UserIdInt int userId) { 5985 ArrayList<ActivityRecord> activities = new ArrayList<>(); 5986 5987 if ("all".equals(name)) { 5988 forAllActivities((Consumer<ActivityRecord>) activities::add); 5989 } else if ("top".equals(name)) { 5990 final ActivityRecord topActivity = getTopMostActivity(); 5991 if (topActivity != null) { 5992 activities.add(topActivity); 5993 } 5994 } else { 5995 ActivityManagerService.ItemMatcher matcher = new ActivityManagerService.ItemMatcher(); 5996 matcher.build(name); 5997 5998 forAllActivities((r) -> { 5999 if (matcher.match(r, r.intent.getComponent())) { 6000 activities.add(r); 6001 } 6002 }); 6003 } 6004 if (userId != UserHandle.USER_ALL) { 6005 for (int i = activities.size() - 1; i >= 0; --i) { 6006 if (activities.get(i).mUserId != userId) { 6007 activities.remove(i); 6008 } 6009 } 6010 } 6011 return activities; 6012 } 6013 6014 Task reuseOrCreateTask(ActivityInfo info, Intent intent, boolean toTop) { 6015 return reuseOrCreateTask(info, intent, null /*voiceSession*/, null /*voiceInteractor*/, 6016 toTop, null /*activity*/, null /*source*/, null /*options*/); 6017 } 6018 6019 // TODO: Can be removed once we change callpoints creating root tasks to be creating tasks. 6020 /** Either returns this current task to be re-used or creates a new child task. */ 6021 Task reuseOrCreateTask(ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession, 6022 IVoiceInteractor voiceInteractor, boolean toTop, ActivityRecord activity, 6023 ActivityRecord source, ActivityOptions options) { 6024 6025 final Task task; 6026 if (canReuseAsLeafTask()) { 6027 // This root task will only contain one task, so just return itself since all root 6028 // tasks ara now tasks and all tasks are now root tasks. 6029 task = reuseAsLeafTask(voiceSession, voiceInteractor, intent, info, activity); 6030 } else { 6031 // Create child task since this root task can contain multiple tasks. 6032 final int taskId = activity != null 6033 ? mTaskSupervisor.getNextTaskIdForUser(activity.mUserId) 6034 : mTaskSupervisor.getNextTaskIdForUser(); 6035 task = new Task.Builder(mAtmService) 6036 .setTaskId(taskId) 6037 .setActivityInfo(info) 6038 .setActivityOptions(options) 6039 .setIntent(intent) 6040 .setVoiceSession(voiceSession) 6041 .setVoiceInteractor(voiceInteractor) 6042 .setOnTop(toTop) 6043 .setParent(this) 6044 .build(); 6045 } 6046 6047 if (com.android.window.flags.Flags.fixLayoutExistingTask()) { 6048 mTaskSupervisor.getLaunchParamsController() 6049 .layoutTask(task, info.windowLayout, activity, source, options); 6050 } else { 6051 int displayId = getDisplayId(); 6052 if (displayId == INVALID_DISPLAY) displayId = DEFAULT_DISPLAY; 6053 final boolean isLockscreenShown = 6054 mAtmService.mKeyguardController.isKeyguardOrAodShowing(displayId); 6055 if (!mTaskSupervisor.getLaunchParamsController() 6056 .layoutTask(task, info.windowLayout, activity, source, options) 6057 && !getRequestedOverrideBounds().isEmpty() 6058 && task.isResizeable() && !isLockscreenShown) { 6059 task.setBounds(getRequestedOverrideBounds()); 6060 } 6061 } 6062 return task; 6063 } 6064 6065 /** Return {@code true} if this task can be reused as leaf task. */ 6066 private boolean canReuseAsLeafTask() { 6067 // Cannot be reused as leaf task if this task is created by organizer or having child tasks. 6068 if (mCreatedByOrganizer || !isLeafTask()) { 6069 return false; 6070 } 6071 6072 // Existing Tasks can be reused if a new root task will be created anyway. 6073 final int windowingMode = getWindowingMode(); 6074 final int activityType = getActivityType(); 6075 return DisplayContent.alwaysCreateRootTask(windowingMode, activityType); 6076 } 6077 6078 void addChild(WindowContainer child, final boolean toTop, boolean showForAllUsers) { 6079 Task task = child.asTask(); 6080 try { 6081 if (task != null) { 6082 task.setForceShowForAllUsers(showForAllUsers); 6083 } 6084 // We only want to move the parents to the parents if we are creating this task at the 6085 // top of its root task. 6086 addChild(child, toTop ? MAX_VALUE : 0, toTop /*moveParents*/); 6087 } finally { 6088 if (task != null) { 6089 task.setForceShowForAllUsers(false); 6090 } 6091 } 6092 } 6093 6094 public void setAlwaysOnTop(boolean alwaysOnTop) { 6095 // {@link #isAwaysonTop} overrides the original behavior which also evaluates if this 6096 // task is force hidden, so super.isAlwaysOnTop() is used here to see whether the 6097 // alwaysOnTop attributes should be updated. 6098 if (super.isAlwaysOnTop() == alwaysOnTop) { 6099 return; 6100 } 6101 super.setAlwaysOnTop(alwaysOnTop); 6102 // positionChildAtTop() must be called even when always on top gets turned off because we 6103 // need to make sure that the root task is moved from among always on top windows to 6104 // below other always on top windows. Since the position the root task should be inserted 6105 // into is calculated properly in {@link DisplayContent#getTopInsertPosition()} in both 6106 // cases, we can just request that the root task is put at top here. 6107 // Don't bother moving task to top if this task is force hidden and invisible to user. 6108 if (!isForceHidden()) { 6109 getDisplayArea().positionChildAt(POSITION_TOP, this, false /* includingParents */); 6110 } 6111 } 6112 6113 void dismissPip() { 6114 if (!isActivityTypeStandardOrUndefined()) { 6115 throw new IllegalArgumentException( 6116 "You can't move tasks from non-standard root tasks."); 6117 } 6118 if (getWindowingMode() != WINDOWING_MODE_PINNED) { 6119 throw new IllegalArgumentException( 6120 "Can't exit pinned mode if it's not pinned already."); 6121 } 6122 6123 final Task task = getBottomMostTask(); 6124 setRootTaskWindowingMode(WINDOWING_MODE_UNDEFINED); 6125 6126 // Task could have been removed from the hierarchy due to windowing mode change 6127 // where its only child is reparented back to their original parent task. 6128 if (isAttached()) { 6129 getDisplayArea().positionChildAt(POSITION_TOP, this, false /* includingParents */); 6130 } 6131 6132 mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this); 6133 } 6134 6135 private int setBounds(Rect existing, Rect bounds) { 6136 if (equivalentBounds(existing, bounds)) { 6137 return BOUNDS_CHANGE_NONE; 6138 } 6139 6140 return setBoundsUnchecked(!inMultiWindowMode() ? null : bounds); 6141 } 6142 6143 /** 6144 * Put a Task in this root task. Used for adding only. 6145 * When task is added to top of the root task, the entire branch of the hierarchy (including 6146 * root task and display) will be brought to top. 6147 * @param child The child to add. 6148 * @param position Target position to add the task to. 6149 */ 6150 private void addChild(WindowContainer child, int position, boolean moveParents) { 6151 // Add child task. 6152 addChild(child, null); 6153 6154 // Move child to a proper position, as some restriction for position might apply. 6155 positionChildAt(position, child, moveParents /* includingParents */); 6156 } 6157 6158 void positionChildAtTop(Task child) { 6159 if (child == null) { 6160 // TODO: Fix the call-points that cause this to happen. 6161 return; 6162 } 6163 6164 if (child == this) { 6165 // TODO: Fix call-points 6166 moveToFront("positionChildAtTop"); 6167 return; 6168 } 6169 6170 positionChildAt(POSITION_TOP, child, true /* includingParents */); 6171 } 6172 6173 void positionChildAtBottom(Task child) { 6174 // If there are other focusable root tasks on the display, the z-order of the display 6175 // should not be changed just because a task was placed at the bottom. E.g. if it is 6176 // moving the topmost task to bottom, the next focusable root task on the same display 6177 // should be focused. 6178 final Task nextFocusableRootTask = getDisplayArea().getNextFocusableRootTask( 6179 child.getRootTask(), true /* ignoreCurrent */); 6180 positionChildAtBottom(child, nextFocusableRootTask == null /* includingParents */); 6181 } 6182 6183 @VisibleForTesting 6184 void positionChildAtBottom(Task child, boolean includingParents) { 6185 if (child == null) { 6186 // TODO: Fix the call-points that cause this to happen. 6187 return; 6188 } 6189 6190 positionChildAt(POSITION_BOTTOM, child, includingParents); 6191 } 6192 6193 @Override 6194 void onChildPositionChanged(WindowContainer child) { 6195 if (!mChildren.contains(child)) { 6196 dispatchTaskInfoChangedIfNeeded(false /* force */); 6197 return; 6198 } 6199 if (child.asTask() != null) { 6200 // Non-root task position changed. 6201 mRootWindowContainer.invalidateTaskLayers(); 6202 } 6203 6204 if (child.asActivityRecord() != null) { 6205 // Send for TaskFragmentParentInfo#hasDirectActivity change. 6206 sendTaskFragmentParentInfoChangedIfNeeded(); 6207 } 6208 6209 // Update the ancestor tasks' task description after any children have reparented 6210 updateTaskDescription(); 6211 dispatchTaskInfoChangedIfNeeded(false /* force */); 6212 } 6213 6214 void reparent(TaskDisplayArea newParent, boolean onTop) { 6215 if (newParent == null) { 6216 throw new IllegalArgumentException("Task can't reparent to null " + this); 6217 } 6218 6219 if (getParent() == newParent) { 6220 throw new IllegalArgumentException("Task=" + this + " already child of " + newParent); 6221 } 6222 6223 if (canBeLaunchedOnDisplay(newParent.getDisplayId())) { 6224 reparent(newParent, onTop ? POSITION_TOP : POSITION_BOTTOM); 6225 newParent.onTaskMoved(this, onTop, !onTop); 6226 } else { 6227 Slog.w(TAG, "Task=" + this + " can't reparent to " + newParent); 6228 } 6229 } 6230 6231 void setLastRecentsAnimationTransaction(@NonNull PictureInPictureSurfaceTransaction transaction, 6232 @Nullable SurfaceControl overlay) { 6233 mLastRecentsAnimationTransaction = new PictureInPictureSurfaceTransaction(transaction); 6234 mLastRecentsAnimationOverlay = overlay; 6235 } 6236 6237 void clearLastRecentsAnimationTransaction(boolean forceRemoveOverlay) { 6238 if (forceRemoveOverlay && mLastRecentsAnimationOverlay != null) { 6239 getPendingTransaction().remove(mLastRecentsAnimationOverlay); 6240 } 6241 mLastRecentsAnimationTransaction = null; 6242 mLastRecentsAnimationOverlay = null; 6243 // reset also the crop and transform introduced by mLastRecentsAnimationTransaction 6244 resetSurfaceControlTransforms(); 6245 } 6246 6247 void resetSurfaceControlTransforms() { 6248 getSyncTransaction().setMatrix(mSurfaceControl, Matrix.IDENTITY_MATRIX, new float[9]) 6249 .setWindowCrop(mSurfaceControl, null) 6250 .setShadowRadius(mSurfaceControl, 0) 6251 .setCornerRadius(mSurfaceControl, 0); 6252 } 6253 6254 void maybeApplyLastRecentsAnimationTransaction() { 6255 if (mLastRecentsAnimationTransaction != null) { 6256 ProtoLog.d(WM_DEBUG_WINDOW_TRANSITIONS_MIN, 6257 "Applying last recents animation transaction."); 6258 final SurfaceControl.Transaction tx = getPendingTransaction(); 6259 if (mLastRecentsAnimationOverlay != null) { 6260 tx.reparent(mLastRecentsAnimationOverlay, mSurfaceControl); 6261 } 6262 PictureInPictureSurfaceTransaction.apply(mLastRecentsAnimationTransaction, 6263 mSurfaceControl, tx); 6264 // If we are transferring the transform from the root task entering PIP, then also show 6265 // the new task immediately 6266 tx.show(mSurfaceControl); 6267 mLastRecentsAnimationTransaction = null; 6268 mLastRecentsAnimationOverlay = null; 6269 } 6270 } 6271 6272 private void updateSurfaceBounds() { 6273 updateSurfaceSize(getSyncTransaction()); 6274 updateSurfacePositionNonOrganized(); 6275 scheduleAnimation(); 6276 } 6277 6278 private Point getRelativePosition() { 6279 Point position = new Point(); 6280 getRelativePosition(position); 6281 return position; 6282 } 6283 6284 boolean shouldIgnoreInput() { 6285 if (mAtmService.mHasLeanbackFeature && inPinnedWindowingMode() 6286 && !isFocusedRootTaskOnDisplay()) { 6287 // Preventing Picture-in-Picture root task from receiving input on TVs. 6288 return true; 6289 } 6290 return false; 6291 } 6292 6293 /** 6294 * Simply check and give warning logs if this is not operated on leaf task. 6295 */ 6296 private void warnForNonLeafTask(String func) { 6297 if (!isLeafTask()) { 6298 Slog.w(TAG, func + " on non-leaf task " + this); 6299 } 6300 } 6301 6302 public DisplayInfo getDisplayInfo() { 6303 return mDisplayContent.getDisplayInfo(); 6304 } 6305 6306 private Rect getRawBounds() { 6307 return super.getBounds(); 6308 } 6309 6310 void dispatchTaskInfoChangedIfNeeded(boolean force) { 6311 if (isOrganized()) { 6312 mAtmService.mTaskOrganizerController.onTaskInfoChanged(this, force); 6313 } 6314 } 6315 6316 void setReparentLeafTaskIfRelaunch(boolean reparentLeafTaskIfRelaunch) { 6317 if (isOrganized()) { 6318 mReparentLeafTaskIfRelaunch = reparentLeafTaskIfRelaunch; 6319 } 6320 } 6321 6322 void setTrimmableFromRecents(boolean isTrimmable) { 6323 mIsTrimmableFromRecents = isTrimmable; 6324 } 6325 6326 /** 6327 * Sets this task and its children to disable respecting launch-adjacent. 6328 */ 6329 void setLaunchAdjacentDisabled(boolean disabled) { 6330 mLaunchAdjacentDisabled = disabled; 6331 } 6332 6333 /** 6334 * Returns whether this task or any of its ancestors have disabled respecting the 6335 * launch-adjacent flag. 6336 */ 6337 boolean isLaunchAdjacentDisabled() { 6338 Task t = this; 6339 while (t != null) { 6340 if (t.mLaunchAdjacentDisabled) { 6341 return true; 6342 } 6343 t = t.getParent().asTask(); 6344 } 6345 return false; 6346 } 6347 6348 /** 6349 * Return true if the activityInfo has the same requiredDisplayCategory as this task. 6350 */ 6351 boolean isSameRequiredDisplayCategory(@NonNull ActivityInfo info) { 6352 return mRequiredDisplayCategory != null && mRequiredDisplayCategory.equals( 6353 info.requiredDisplayCategory) 6354 || (mRequiredDisplayCategory == null && info.requiredDisplayCategory == null); 6355 } 6356 6357 @Override 6358 public void dumpDebug(ProtoOutputStream proto, long fieldId, 6359 @WindowTracingLogLevel int logLevel) { 6360 if (logLevel == WindowTracingLogLevel.CRITICAL && !isVisible()) { 6361 return; 6362 } 6363 6364 final long token = proto.start(fieldId); 6365 6366 proto.write(TaskProto.ID, mTaskId); 6367 proto.write(ROOT_TASK_ID, getRootTaskId()); 6368 6369 if (getTopResumedActivity() != null) { 6370 getTopResumedActivity().writeIdentifierToProto(proto, RESUMED_ACTIVITY); 6371 } 6372 if (realActivity != null) { 6373 proto.write(REAL_ACTIVITY, realActivity.flattenToShortString()); 6374 } 6375 if (origActivity != null) { 6376 proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString()); 6377 } 6378 proto.write(RESIZE_MODE, mResizeMode); 6379 proto.write(FILLS_PARENT, matchParentBounds()); 6380 getRawBounds().dumpDebug(proto, BOUNDS); 6381 6382 if (mLastNonFullscreenBounds != null) { 6383 mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS); 6384 } 6385 6386 if (mSurfaceControl != null) { 6387 proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth()); 6388 proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight()); 6389 } 6390 6391 proto.write(CREATED_BY_ORGANIZER, mCreatedByOrganizer); 6392 proto.write(AFFINITY, affinity); 6393 proto.write(HAS_CHILD_PIP_ACTIVITY, mChildPipActivity != null); 6394 6395 super.dumpDebug(proto, TASK_FRAGMENT, logLevel); 6396 6397 proto.end(token); 6398 } 6399 6400 static class Builder { 6401 private final ActivityTaskManagerService mAtmService; 6402 private WindowContainer mParent; 6403 private int mTaskId; 6404 private Intent mIntent; 6405 private Intent mAffinityIntent; 6406 private String mAffinity; 6407 private String mRootAffinity; 6408 private ComponentName mRealActivity; 6409 private ComponentName mOrigActivity; 6410 private boolean mRootWasReset; 6411 private boolean mAutoRemoveRecents; 6412 private int mUserId; 6413 private int mEffectiveUid; 6414 private String mLastDescription; 6415 private long mLastTimeMoved; 6416 private boolean mNeverRelinquishIdentity; 6417 private TaskDescription mLastTaskDescription; 6418 private int mTaskAffiliation; 6419 private int mPrevAffiliateTaskId = INVALID_TASK_ID; 6420 private int mNextAffiliateTaskId = INVALID_TASK_ID; 6421 private int mCallingUid; 6422 private String mCallingPackage; 6423 private String mCallingFeatureId; 6424 private int mResizeMode; 6425 private boolean mSupportsPictureInPicture; 6426 private boolean mRealActivitySuspended; 6427 private boolean mUserSetupComplete; 6428 private int mMinWidth = INVALID_MIN_SIZE; 6429 private int mMinHeight = INVALID_MIN_SIZE; 6430 private ActivityInfo mActivityInfo; 6431 private ActivityOptions mActivityOptions; 6432 private IVoiceInteractionSession mVoiceSession; 6433 private IVoiceInteractor mVoiceInteractor; 6434 private int mActivityType; 6435 private int mWindowingMode = WINDOWING_MODE_UNDEFINED; 6436 private boolean mCreatedByOrganizer; 6437 private boolean mDeferTaskAppear; 6438 private IBinder mLaunchCookie; 6439 private boolean mOnTop; 6440 private boolean mHasBeenVisible; 6441 private boolean mRemoveWithTaskOrganizer; 6442 6443 /** 6444 * Records the source task that requesting to build a new task, used to determine which of 6445 * the adjacent roots should be launch root of the new task. 6446 */ 6447 private Task mSourceTask; 6448 6449 /** 6450 * Records launch flags to apply when launching new task. 6451 */ 6452 private int mLaunchFlags; 6453 6454 Builder(ActivityTaskManagerService atm) { 6455 mAtmService = atm; 6456 } 6457 6458 Builder setParent(WindowContainer parent) { 6459 mParent = parent; 6460 return this; 6461 } 6462 6463 Builder setSourceTask(Task sourceTask) { 6464 mSourceTask = sourceTask; 6465 return this; 6466 } 6467 6468 Builder setLaunchFlags(int launchFlags) { 6469 mLaunchFlags = launchFlags; 6470 return this; 6471 } 6472 6473 Builder setTaskId(int taskId) { 6474 mTaskId = taskId; 6475 return this; 6476 } 6477 6478 Builder setIntent(Intent intent) { 6479 mIntent = intent; 6480 return this; 6481 } 6482 6483 Builder setRealActivity(ComponentName realActivity) { 6484 mRealActivity = realActivity; 6485 return this; 6486 } 6487 6488 Builder setEffectiveUid(int effectiveUid) { 6489 mEffectiveUid = effectiveUid; 6490 return this; 6491 } 6492 6493 Builder setMinWidth(int minWidth) { 6494 mMinWidth = minWidth; 6495 return this; 6496 } 6497 6498 Builder setMinHeight(int minHeight) { 6499 mMinHeight = minHeight; 6500 return this; 6501 } 6502 6503 Builder setActivityInfo(ActivityInfo info) { 6504 mActivityInfo = info; 6505 return this; 6506 } 6507 6508 Builder setActivityOptions(ActivityOptions opts) { 6509 mActivityOptions = opts; 6510 return this; 6511 } 6512 6513 Builder setVoiceSession(IVoiceInteractionSession voiceSession) { 6514 mVoiceSession = voiceSession; 6515 return this; 6516 } 6517 6518 Builder setActivityType(int activityType) { 6519 mActivityType = activityType; 6520 return this; 6521 } 6522 6523 int getActivityType() { 6524 return mActivityType; 6525 } 6526 6527 Builder setWindowingMode(int windowingMode) { 6528 mWindowingMode = windowingMode; 6529 return this; 6530 } 6531 6532 int getWindowingMode() { 6533 return mWindowingMode; 6534 } 6535 6536 Builder setCreatedByOrganizer(boolean createdByOrganizer) { 6537 mCreatedByOrganizer = createdByOrganizer; 6538 return this; 6539 } 6540 6541 boolean getCreatedByOrganizer() { 6542 return mCreatedByOrganizer; 6543 } 6544 6545 Builder setDeferTaskAppear(boolean defer) { 6546 mDeferTaskAppear = defer; 6547 return this; 6548 } 6549 6550 Builder setLaunchCookie(IBinder launchCookie) { 6551 mLaunchCookie = launchCookie; 6552 return this; 6553 } 6554 6555 Builder setOnTop(boolean onTop) { 6556 mOnTop = onTop; 6557 return this; 6558 } 6559 6560 Builder setHasBeenVisible(boolean hasBeenVisible) { 6561 mHasBeenVisible = hasBeenVisible; 6562 return this; 6563 } 6564 6565 Builder setRemoveWithTaskOrganizer(boolean removeWithTaskOrganizer) { 6566 mRemoveWithTaskOrganizer = removeWithTaskOrganizer; 6567 return this; 6568 } 6569 6570 private Builder setUserId(int userId) { 6571 mUserId = userId; 6572 return this; 6573 } 6574 6575 private Builder setLastTimeMoved(long lastTimeMoved) { 6576 mLastTimeMoved = lastTimeMoved; 6577 return this; 6578 } 6579 6580 private Builder setNeverRelinquishIdentity(boolean neverRelinquishIdentity) { 6581 mNeverRelinquishIdentity = neverRelinquishIdentity; 6582 return this; 6583 } 6584 6585 private Builder setCallingUid(int callingUid) { 6586 mCallingUid = callingUid; 6587 return this; 6588 } 6589 6590 private Builder setCallingPackage(String callingPackage) { 6591 mCallingPackage = callingPackage; 6592 return this; 6593 } 6594 6595 private Builder setResizeMode(int resizeMode) { 6596 mResizeMode = resizeMode; 6597 return this; 6598 } 6599 6600 private Builder setSupportsPictureInPicture(boolean supportsPictureInPicture) { 6601 mSupportsPictureInPicture = supportsPictureInPicture; 6602 return this; 6603 } 6604 6605 private Builder setUserSetupComplete(boolean userSetupComplete) { 6606 mUserSetupComplete = userSetupComplete; 6607 return this; 6608 } 6609 6610 private Builder setTaskAffiliation(int taskAffiliation) { 6611 mTaskAffiliation = taskAffiliation; 6612 return this; 6613 } 6614 6615 private Builder setPrevAffiliateTaskId(int prevAffiliateTaskId) { 6616 mPrevAffiliateTaskId = prevAffiliateTaskId; 6617 return this; 6618 } 6619 6620 private Builder setNextAffiliateTaskId(int nextAffiliateTaskId) { 6621 mNextAffiliateTaskId = nextAffiliateTaskId; 6622 return this; 6623 } 6624 6625 private Builder setCallingFeatureId(String callingFeatureId) { 6626 mCallingFeatureId = callingFeatureId; 6627 return this; 6628 } 6629 6630 private Builder setRealActivitySuspended(boolean realActivitySuspended) { 6631 mRealActivitySuspended = realActivitySuspended; 6632 return this; 6633 } 6634 6635 private Builder setLastDescription(String lastDescription) { 6636 mLastDescription = lastDescription; 6637 return this; 6638 } 6639 6640 private Builder setLastTaskDescription(TaskDescription lastTaskDescription) { 6641 mLastTaskDescription = lastTaskDescription; 6642 return this; 6643 } 6644 6645 private Builder setOrigActivity(ComponentName origActivity) { 6646 mOrigActivity = origActivity; 6647 return this; 6648 } 6649 6650 private Builder setRootWasReset(boolean rootWasReset) { 6651 mRootWasReset = rootWasReset; 6652 return this; 6653 } 6654 6655 private Builder setAutoRemoveRecents(boolean autoRemoveRecents) { 6656 mAutoRemoveRecents = autoRemoveRecents; 6657 return this; 6658 } 6659 6660 private Builder setAffinityIntent(Intent affinityIntent) { 6661 mAffinityIntent = affinityIntent; 6662 return this; 6663 } 6664 6665 private Builder setAffinity(String affinity) { 6666 mAffinity = affinity; 6667 return this; 6668 } 6669 6670 private Builder setRootAffinity(String rootAffinity) { 6671 mRootAffinity = rootAffinity; 6672 return this; 6673 } 6674 6675 private Builder setVoiceInteractor(IVoiceInteractor voiceInteractor) { 6676 mVoiceInteractor = voiceInteractor; 6677 return this; 6678 } 6679 6680 private void validateRootTask(TaskDisplayArea tda) { 6681 if (mActivityType == ACTIVITY_TYPE_UNDEFINED && !mCreatedByOrganizer) { 6682 // Can't have an undefined root task type yet...so re-map to standard. Anyone 6683 // that wants anything else should be passing it in anyways...except for the task 6684 // organizer. 6685 mActivityType = ACTIVITY_TYPE_STANDARD; 6686 } 6687 6688 if (!DisplayContent.alwaysCreateRootTask(tda.getWindowingMode(), mActivityType) 6689 && mActivityType != ACTIVITY_TYPE_UNDEFINED) { 6690 // Only Recents or Standard activity types are allowed to have more than one 6691 // root task on a display, this is independent of whatever windowing mode it 6692 // is currently in. 6693 Task rootTask = tda.getRootTask(WINDOWING_MODE_UNDEFINED, mActivityType); 6694 if (rootTask != null) { 6695 throw new IllegalArgumentException("Root task=" + rootTask + " of activityType=" 6696 + mActivityType + " already on display=" + tda 6697 + ". Can't have multiple."); 6698 } 6699 } 6700 6701 if (!TaskDisplayArea.isWindowingModeSupported(mWindowingMode, 6702 mAtmService.mSupportsMultiWindow, 6703 mAtmService.mSupportsFreeformWindowManagement, 6704 mAtmService.mSupportsPictureInPicture)) { 6705 throw new IllegalArgumentException("Can't create root task for unsupported " 6706 + "windowingMode=" + mWindowingMode); 6707 } 6708 6709 if (mWindowingMode == WINDOWING_MODE_PINNED 6710 && mActivityType != ACTIVITY_TYPE_STANDARD) { 6711 throw new IllegalArgumentException( 6712 "Root task with pinned windowing mode cannot with " 6713 + "non-standard activity type."); 6714 } 6715 6716 if (mWindowingMode == WINDOWING_MODE_PINNED && tda.getRootPinnedTask() != null) { 6717 // Only 1 root task can be PINNED at a time, so dismiss the existing one 6718 tda.getRootPinnedTask().dismissPip(); 6719 } 6720 6721 if (mIntent != null) { 6722 mLaunchFlags |= mIntent.getFlags(); 6723 } 6724 6725 // Task created by organizer are added as root. 6726 final Task launchRootTask = mCreatedByOrganizer 6727 ? null : tda.getLaunchRootTask(mWindowingMode, mActivityType, mActivityOptions, 6728 mSourceTask, mLaunchFlags); 6729 if (launchRootTask != null) { 6730 // Since this task will be put into a root task, its windowingMode will be 6731 // inherited. 6732 mWindowingMode = WINDOWING_MODE_UNDEFINED; 6733 mParent = launchRootTask; 6734 } 6735 6736 mTaskId = tda.getNextRootTaskId(); 6737 } 6738 6739 Task build() { 6740 if (mParent != null && mParent instanceof TaskDisplayArea) { 6741 validateRootTask((TaskDisplayArea) mParent); 6742 } 6743 6744 if (mActivityInfo == null) { 6745 mActivityInfo = new ActivityInfo(); 6746 mActivityInfo.applicationInfo = new ApplicationInfo(); 6747 } 6748 6749 mUserId = UserHandle.getUserId(mActivityInfo.applicationInfo.uid); 6750 mTaskAffiliation = mTaskId; 6751 mLastTimeMoved = System.currentTimeMillis(); 6752 mNeverRelinquishIdentity = true; 6753 mCallingUid = mActivityInfo.applicationInfo.uid; 6754 mCallingPackage = mActivityInfo.packageName; 6755 mResizeMode = mActivityInfo.resizeMode; 6756 mSupportsPictureInPicture = mActivityInfo.supportsPictureInPicture(); 6757 if (!mRemoveWithTaskOrganizer && mActivityOptions != null) { 6758 mRemoveWithTaskOrganizer = mActivityOptions.getRemoveWithTaskOranizer(); 6759 } 6760 6761 final Task task = buildInner(); 6762 task.mHasBeenVisible = mHasBeenVisible; 6763 6764 // Set activity type before adding the root task to TaskDisplayArea, so home task can 6765 // be cached, see TaskDisplayArea#addRootTaskReferenceIfNeeded(). 6766 if (mActivityType != ACTIVITY_TYPE_UNDEFINED) { 6767 task.setActivityType(mActivityType); 6768 } 6769 6770 if (mParent != null) { 6771 if (mParent instanceof Task) { 6772 final Task parentTask = (Task) mParent; 6773 parentTask.addChild(task, mOnTop ? POSITION_TOP : POSITION_BOTTOM, 6774 (mActivityInfo.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); 6775 } else { 6776 mParent.addChild(task, mOnTop ? POSITION_TOP : POSITION_BOTTOM); 6777 } 6778 } 6779 6780 // Set windowing mode after attached to display area or it abort silently. 6781 if (mWindowingMode != WINDOWING_MODE_UNDEFINED) { 6782 task.setWindowingModeInner(mWindowingMode, true /* creating */); 6783 } 6784 return task; 6785 } 6786 6787 /** Don't use {@link Builder#buildInner()} directly. This is only used by XML parser. */ 6788 @VisibleForTesting 6789 Task buildInner() { 6790 return new Task(mAtmService, mTaskId, mIntent, mAffinityIntent, mAffinity, 6791 mRootAffinity, mRealActivity, mOrigActivity, mRootWasReset, mAutoRemoveRecents, 6792 mUserId, mEffectiveUid, mLastDescription, mLastTimeMoved, 6793 mNeverRelinquishIdentity, mLastTaskDescription, 6794 mTaskAffiliation, mPrevAffiliateTaskId, mNextAffiliateTaskId, mCallingUid, 6795 mCallingPackage, mCallingFeatureId, mResizeMode, mSupportsPictureInPicture, 6796 mRealActivitySuspended, mUserSetupComplete, mMinWidth, mMinHeight, 6797 mActivityInfo, mVoiceSession, mVoiceInteractor, mCreatedByOrganizer, 6798 mLaunchCookie, mDeferTaskAppear, mRemoveWithTaskOrganizer); 6799 } 6800 } 6801 6802 @Override 6803 void updateOverlayInsetsState(WindowState originalChange) { 6804 super.updateOverlayInsetsState(originalChange); 6805 if (originalChange != getTopVisibleAppMainWindow()) { 6806 return; 6807 } 6808 if (mOverlayHost != null) { 6809 final InsetsState s = originalChange.getInsetsState(true); 6810 getBounds(mTmpRect); 6811 mOverlayHost.dispatchInsetsChanged(s, mTmpRect); 6812 } 6813 } 6814 6815 @Nullable 6816 ActivityRecord getBottomMostActivityInSamePackage() { 6817 if (realActivity == null) { 6818 return null; 6819 } 6820 return getActivity(ar -> ar.packageName.equals( 6821 realActivity.getPackageName()), false /* traverseTopToBottom */); 6822 } 6823 6824 /** 6825 * Associates the decor surface with the given TF, or create one if there 6826 * isn't one in the Task yet. The surface will be removed with the TF, 6827 * and become invisible if the TF is invisible. */ 6828 void moveOrCreateDecorSurfaceFor(TaskFragment taskFragment, boolean visible) { 6829 if (mDecorSurfaceContainer != null) { 6830 mDecorSurfaceContainer.mOwnerTaskFragment = taskFragment; 6831 } else { 6832 mDecorSurfaceContainer = new DecorSurfaceContainer(taskFragment, visible); 6833 assignChildLayers(); 6834 sendTaskFragmentParentInfoChangedIfNeeded(); 6835 } 6836 } 6837 6838 void removeDecorSurface() { 6839 if (mDecorSurfaceContainer == null) { 6840 return; 6841 } 6842 mDecorSurfaceContainer.release(); 6843 mDecorSurfaceContainer = null; 6844 sendTaskFragmentParentInfoChangedIfNeeded(); 6845 } 6846 6847 @Nullable SurfaceControl getDecorSurface() { 6848 return mDecorSurfaceContainer != null ? mDecorSurfaceContainer.mDecorSurface : null; 6849 } 6850 6851 void setDecorSurfaceVisible(@NonNull SurfaceControl.Transaction t) { 6852 if (mDecorSurfaceContainer == null) { 6853 return; 6854 } 6855 t.show(mDecorSurfaceContainer.mDecorSurface); 6856 } 6857 6858 /** 6859 * A class managing the decor surface. 6860 * 6861 * A decor surface is requested by a {@link TaskFragmentOrganizer} and is placed below children 6862 * windows in the Task except for own Activities and TaskFragments in fully trusted mode. The 6863 * decor surface is created and shared with the client app with 6864 * {@link android.window.TaskFragmentOperation#OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE} 6865 * and be removed with 6866 * {@link android.window.TaskFragmentOperation#OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE}. 6867 * 6868 * When boosted with 6869 * {@link android.window.TaskFragmentOperation#OP_TYPE_SET_DECOR_SURFACE_BOOSTED}, the decor 6870 * surface is placed above all non-boosted windows in the Task, but all the content below it 6871 * will be hidden to prevent UI redressing attacks. This can be used by the draggable 6872 * divider between {@link TaskFragment}s where veils are drawn on the decor surface while 6873 * dragging to indicate new bounds. 6874 */ 6875 @VisibleForTesting 6876 class DecorSurfaceContainer { 6877 6878 // The container surface is the parent of the decor surface. The container surface 6879 // should NEVER be shared with the client. It is used to ensure that the decor surface has 6880 // a z-order in the Task that is managed by WM core and cannot be updated by the client 6881 // process. 6882 @VisibleForTesting 6883 @NonNull final SurfaceControl mContainerSurface; 6884 6885 // The decor surface is shared with the client process owning the 6886 // {@link TaskFragmentOrganizer}. It can be used to draw the divider between TaskFragments 6887 // or other decorations. 6888 @VisibleForTesting 6889 @NonNull final SurfaceControl mDecorSurface; 6890 6891 // The TaskFragment that requested the decor surface. If it is destroyed, the decor surface 6892 // is also released. 6893 @VisibleForTesting 6894 @NonNull TaskFragment mOwnerTaskFragment; 6895 6896 private boolean mIsBoosted; 6897 private boolean mIsBoostedRequested; 6898 6899 // The surface transactions that will be applied when the layer is reassigned. 6900 @NonNull private final List<SurfaceControl.Transaction> mPendingClientTransactions = 6901 new ArrayList<>(); 6902 6903 private DecorSurfaceContainer(@NonNull TaskFragment initialOwner, boolean visible) { 6904 mOwnerTaskFragment = initialOwner; 6905 mContainerSurface = makeSurface().setContainerLayer() 6906 .setParent(mSurfaceControl) 6907 .setName(mSurfaceControl + " - decor surface container") 6908 .setContainerLayer() 6909 .setHidden(false) 6910 .setCallsite("Task.DecorSurfaceContainer") 6911 .build(); 6912 6913 mDecorSurface = makeSurface() 6914 .setParent(mContainerSurface) 6915 .setName(mSurfaceControl + " - decor surface") 6916 .setHidden(!visible) 6917 .setCallsite("Task.DecorSurfaceContainer") 6918 .build(); 6919 } 6920 6921 /** 6922 * Sets the requested boosted state. The state is not applied until 6923 * {@link commitBoostedState} is called. 6924 */ 6925 private void requestBoosted( 6926 boolean isBoosted, @Nullable SurfaceControl.Transaction clientTransaction) { 6927 mIsBoostedRequested = isBoosted; 6928 // The client transaction will be applied together with the next commitBoostedState. 6929 if (clientTransaction != null) { 6930 mPendingClientTransactions.add(clientTransaction); 6931 } 6932 } 6933 6934 /** Applies the last requested boosted state. */ 6935 private void commitBoostedState() { 6936 mIsBoosted = mIsBoostedRequested; 6937 applyPendingClientTransactions(getSyncTransaction()); 6938 } 6939 6940 private void assignLayer(@NonNull SurfaceControl.Transaction t, int layer) { 6941 t.setLayer(mContainerSurface, layer); 6942 t.setVisibility(mContainerSurface, mOwnerTaskFragment.isVisible() || mIsBoosted); 6943 } 6944 6945 private void applyPendingClientTransactions(@NonNull SurfaceControl.Transaction t) { 6946 for (int i = 0; i < mPendingClientTransactions.size(); i++) { 6947 t.merge(mPendingClientTransactions.get(i)); 6948 } 6949 mPendingClientTransactions.clear(); 6950 } 6951 6952 private void release() { 6953 getSyncTransaction() 6954 .remove(mDecorSurface) 6955 .remove(mContainerSurface); 6956 } 6957 } 6958 } 6959