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