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