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