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.ROTATION_UNDEFINED; 31 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 32 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 33 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 34 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 35 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 36 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 37 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 38 import static android.app.WindowConfiguration.activityTypeToString; 39 import static android.app.WindowConfiguration.windowingModeToString; 40 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; 41 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 42 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; 43 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; 44 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; 45 import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; 46 import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING; 47 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; 48 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; 49 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; 50 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; 51 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; 52 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 53 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED; 54 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 55 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 56 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 57 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 58 import static android.content.res.Configuration.ORIENTATION_UNDEFINED; 59 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; 60 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; 61 import static android.view.Display.DEFAULT_DISPLAY; 62 import static android.view.Display.INVALID_DISPLAY; 63 import static android.view.SurfaceControl.METADATA_TASK_ID; 64 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 65 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 66 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 67 import static android.view.WindowManager.TRANSIT_CHANGE; 68 import static android.view.WindowManager.TRANSIT_CLOSE; 69 import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED; 70 import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND; 71 import static android.view.WindowManager.TRANSIT_NONE; 72 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; 73 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; 74 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; 75 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND; 76 import static android.view.WindowManager.TRANSIT_OPEN; 77 import static android.view.WindowManager.TRANSIT_TO_BACK; 78 import static android.view.WindowManager.TRANSIT_TO_FRONT; 79 80 import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP; 81 import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; 82 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; 83 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK; 84 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; 85 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES; 86 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; 87 import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN; 88 import static com.android.server.wm.ActivityRecord.TRANSFER_SPLASH_SCREEN_COPYING; 89 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; 90 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; 91 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; 92 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION; 93 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING; 94 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE; 95 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_APP; 96 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CLEANUP; 97 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; 98 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE; 99 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS; 100 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS; 101 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ROOT_TASK; 102 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES; 103 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; 104 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; 105 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION; 106 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING; 107 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY; 108 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; 109 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; 110 import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_TASK_MSG; 111 import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME; 112 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; 113 import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; 114 import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS; 115 import static com.android.server.wm.ActivityTaskSupervisor.dumpHistoryList; 116 import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity; 117 import static com.android.server.wm.IdentifierProto.HASH_CODE; 118 import static com.android.server.wm.IdentifierProto.TITLE; 119 import static com.android.server.wm.IdentifierProto.USER_ID; 120 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED; 121 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_DONT_LOCK; 122 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE; 123 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; 124 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_PINNABLE; 125 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; 126 import static com.android.server.wm.Task.ActivityState.PAUSED; 127 import static com.android.server.wm.Task.ActivityState.PAUSING; 128 import static com.android.server.wm.Task.ActivityState.RESUMED; 129 import static com.android.server.wm.Task.ActivityState.STARTED; 130 import static com.android.server.wm.Task.ActivityState.STOPPING; 131 import static com.android.server.wm.TaskProto.ACTIVITY_TYPE; 132 import static com.android.server.wm.TaskProto.AFFINITY; 133 import static com.android.server.wm.TaskProto.BOUNDS; 134 import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER; 135 import static com.android.server.wm.TaskProto.DISPLAY_ID; 136 import static com.android.server.wm.TaskProto.FILLS_PARENT; 137 import static com.android.server.wm.TaskProto.HAS_CHILD_PIP_ACTIVITY; 138 import static com.android.server.wm.TaskProto.LAST_NON_FULLSCREEN_BOUNDS; 139 import static com.android.server.wm.TaskProto.MIN_HEIGHT; 140 import static com.android.server.wm.TaskProto.MIN_WIDTH; 141 import static com.android.server.wm.TaskProto.ORIG_ACTIVITY; 142 import static com.android.server.wm.TaskProto.REAL_ACTIVITY; 143 import static com.android.server.wm.TaskProto.RESIZE_MODE; 144 import static com.android.server.wm.TaskProto.RESUMED_ACTIVITY; 145 import static com.android.server.wm.TaskProto.ROOT_TASK_ID; 146 import static com.android.server.wm.TaskProto.SURFACE_HEIGHT; 147 import static com.android.server.wm.TaskProto.SURFACE_WIDTH; 148 import static com.android.server.wm.TaskProto.WINDOW_CONTAINER; 149 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; 150 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; 151 import static com.android.server.wm.WindowContainerChildProto.TASK; 152 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK; 153 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; 154 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 155 import static com.android.server.wm.WindowManagerService.dipToPixel; 156 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_BEFORE_ANIM; 157 158 import static java.lang.Integer.MAX_VALUE; 159 160 import android.annotation.IntDef; 161 import android.annotation.NonNull; 162 import android.annotation.Nullable; 163 import android.app.Activity; 164 import android.app.ActivityManager; 165 import android.app.ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData; 166 import android.app.ActivityManager.TaskDescription; 167 import android.app.ActivityOptions; 168 import android.app.ActivityTaskManager; 169 import android.app.AppGlobals; 170 import android.app.IActivityController; 171 import android.app.PictureInPictureParams; 172 import android.app.RemoteAction; 173 import android.app.ResultInfo; 174 import android.app.TaskInfo; 175 import android.app.WindowConfiguration; 176 import android.app.servertransaction.ActivityResultItem; 177 import android.app.servertransaction.ClientTransaction; 178 import android.app.servertransaction.NewIntentItem; 179 import android.app.servertransaction.PauseActivityItem; 180 import android.app.servertransaction.ResumeActivityItem; 181 import android.content.ComponentName; 182 import android.content.Intent; 183 import android.content.pm.ActivityInfo; 184 import android.content.pm.ApplicationInfo; 185 import android.content.pm.IPackageManager; 186 import android.content.pm.PackageManager; 187 import android.content.res.Configuration; 188 import android.graphics.Matrix; 189 import android.graphics.Point; 190 import android.graphics.Rect; 191 import android.os.Binder; 192 import android.os.Debug; 193 import android.os.Handler; 194 import android.os.IBinder; 195 import android.os.Looper; 196 import android.os.Message; 197 import android.os.RemoteException; 198 import android.os.SystemClock; 199 import android.os.Trace; 200 import android.os.UserHandle; 201 import android.provider.Settings; 202 import android.service.voice.IVoiceInteractionSession; 203 import android.util.ArraySet; 204 import android.util.DisplayMetrics; 205 import android.util.Slog; 206 import android.util.TypedXmlPullParser; 207 import android.util.TypedXmlSerializer; 208 import android.util.proto.ProtoOutputStream; 209 import android.view.DisplayInfo; 210 import android.view.RemoteAnimationAdapter; 211 import android.view.RemoteAnimationTarget; 212 import android.view.Surface; 213 import android.view.SurfaceControl; 214 import android.view.WindowManager; 215 import android.view.WindowManager.TransitionOldType; 216 import android.window.ITaskOrganizer; 217 import android.window.PictureInPictureSurfaceTransaction; 218 import android.window.StartingWindowInfo; 219 import android.window.TaskSnapshot; 220 import android.window.WindowContainerToken; 221 222 import com.android.internal.annotations.GuardedBy; 223 import com.android.internal.annotations.VisibleForTesting; 224 import com.android.internal.app.IVoiceInteractor; 225 import com.android.internal.protolog.common.ProtoLog; 226 import com.android.internal.util.XmlUtils; 227 import com.android.internal.util.function.pooled.PooledConsumer; 228 import com.android.internal.util.function.pooled.PooledFunction; 229 import com.android.internal.util.function.pooled.PooledLambda; 230 import com.android.internal.util.function.pooled.PooledPredicate; 231 import com.android.server.Watchdog; 232 import com.android.server.am.ActivityManagerService; 233 import com.android.server.am.AppTimeTracker; 234 import com.android.server.uri.NeededUriGrants; 235 236 import org.xmlpull.v1.XmlPullParser; 237 import org.xmlpull.v1.XmlPullParserException; 238 239 import java.io.FileDescriptor; 240 import java.io.IOException; 241 import java.io.PrintWriter; 242 import java.lang.annotation.Retention; 243 import java.lang.annotation.RetentionPolicy; 244 import java.util.ArrayList; 245 import java.util.List; 246 import java.util.Objects; 247 import java.util.concurrent.atomic.AtomicBoolean; 248 import java.util.function.Consumer; 249 import java.util.function.Function; 250 import java.util.function.Predicate; 251 252 class Task extends WindowContainer<WindowContainer> { 253 private static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_ATM; 254 static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; 255 private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; 256 private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK; 257 static final String TAG_TASKS = TAG + POSTFIX_TASKS; 258 private static final String TAG_APP = TAG + POSTFIX_APP; 259 static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP; 260 private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE; 261 private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS; 262 private static final String TAG_ROOT_TASK = TAG + POSTFIX_ROOT_TASK; 263 private static final String TAG_STATES = TAG + POSTFIX_STATES; 264 private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; 265 private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION; 266 private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; 267 static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY; 268 269 private static final String ATTR_TASKID = "task_id"; 270 private static final String TAG_INTENT = "intent"; 271 private static final String TAG_AFFINITYINTENT = "affinity_intent"; 272 private static final String ATTR_REALACTIVITY = "real_activity"; 273 private static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended"; 274 private static final String ATTR_ORIGACTIVITY = "orig_activity"; 275 private static final String TAG_ACTIVITY = "activity"; 276 private static final String ATTR_AFFINITY = "affinity"; 277 private static final String ATTR_ROOT_AFFINITY = "root_affinity"; 278 private static final String ATTR_ROOTHASRESET = "root_has_reset"; 279 private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents"; 280 private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode"; 281 private static final String ATTR_USERID = "user_id"; 282 private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete"; 283 private static final String ATTR_EFFECTIVE_UID = "effective_uid"; 284 @Deprecated 285 private static final String ATTR_TASKTYPE = "task_type"; 286 private static final String ATTR_LASTDESCRIPTION = "last_description"; 287 private static final String ATTR_LASTTIMEMOVED = "last_time_moved"; 288 private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity"; 289 private static final String ATTR_TASK_AFFILIATION = "task_affiliation"; 290 private static final String ATTR_PREV_AFFILIATION = "prev_affiliation"; 291 private static final String ATTR_NEXT_AFFILIATION = "next_affiliation"; 292 private static final String ATTR_CALLING_UID = "calling_uid"; 293 private static final String ATTR_CALLING_PACKAGE = "calling_package"; 294 private static final String ATTR_CALLING_FEATURE_ID = "calling_feature_id"; 295 private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture"; 296 private static final String ATTR_RESIZE_MODE = "resize_mode"; 297 private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds"; 298 private static final String ATTR_MIN_WIDTH = "min_width"; 299 private static final String ATTR_MIN_HEIGHT = "min_height"; 300 private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version"; 301 private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity"; 302 private static final String ATTR_LAST_SNAPSHOT_TASK_SIZE = "last_snapshot_task_size"; 303 private static final String ATTR_LAST_SNAPSHOT_CONTENT_INSETS = "last_snapshot_content_insets"; 304 private static final String ATTR_LAST_SNAPSHOT_BUFFER_SIZE = "last_snapshot_buffer_size"; 305 306 // Set to false to disable the preview that is shown while a new activity 307 // is being started. 308 private static final boolean SHOW_APP_STARTING_PREVIEW = true; 309 310 // How long to wait for all background Activities to redraw following a call to 311 // convertToTranslucent(). 312 private static final long TRANSLUCENT_CONVERSION_TIMEOUT = 2000; 313 314 // Current version of the task record we persist. Used to check if we need to run any upgrade 315 // code. 316 static final int PERSIST_TASK_VERSION = 1; 317 318 static final int INVALID_MIN_SIZE = -1; 319 private float mShadowRadius = 0; 320 321 /** 322 * The modes to control how root task is moved to the front when calling {@link Task#reparent}. 323 */ 324 @Retention(RetentionPolicy.SOURCE) 325 @IntDef({ 326 REPARENT_MOVE_ROOT_TASK_TO_FRONT, 327 REPARENT_KEEP_ROOT_TASK_AT_FRONT, 328 REPARENT_LEAVE_ROOT_TASK_IN_PLACE 329 }) 330 @interface ReparentMoveRootTaskMode {} 331 // Moves the root task to the front if it was not at the front 332 static final int REPARENT_MOVE_ROOT_TASK_TO_FRONT = 0; 333 // Only moves the root task to the front if it was focused or front most already 334 static final int REPARENT_KEEP_ROOT_TASK_AT_FRONT = 1; 335 // Do not move the root task as a part of reparenting 336 static final int REPARENT_LEAVE_ROOT_TASK_IN_PLACE = 2; 337 338 @IntDef(prefix = {"TASK_VISIBILITY"}, value = { 339 TASK_VISIBILITY_VISIBLE, 340 TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, 341 TASK_VISIBILITY_INVISIBLE, 342 }) 343 @interface TaskVisibility {} 344 345 /** Task is visible. No other tasks on top that fully or partially occlude it. */ 346 static final int TASK_VISIBILITY_VISIBLE = 0; 347 348 /** Task is partially occluded by other translucent task(s) on top of it. */ 349 static final int TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT = 1; 350 351 /** Task is completely invisible. */ 352 static final int TASK_VISIBILITY_INVISIBLE = 2; 353 354 enum ActivityState { 355 INITIALIZING, 356 STARTED, 357 RESUMED, 358 PAUSING, 359 PAUSED, 360 STOPPING, 361 STOPPED, 362 FINISHING, 363 DESTROYING, 364 DESTROYED, 365 RESTARTING_PROCESS 366 } 367 368 // The topmost Activity passed to convertToTranslucent(). When non-null it means we are 369 // waiting for all Activities in mUndrawnActivitiesBelowTopTranslucent to be removed as they 370 // are drawn. When the last member of mUndrawnActivitiesBelowTopTranslucent is removed the 371 // Activity in mTranslucentActivityWaiting is notified via 372 // Activity.onTranslucentConversionComplete(false). If a timeout occurs prior to the last 373 // background activity being drawn then the same call will be made with a true value. 374 ActivityRecord mTranslucentActivityWaiting = null; 375 ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent = new ArrayList<>(); 376 377 /** 378 * Set when we know we are going to be calling updateConfiguration() 379 * soon, so want to skip intermediate config checks. 380 */ 381 boolean mConfigWillChange; 382 383 /** 384 * Used to keep resumeTopActivityUncheckedLocked() from being entered recursively 385 */ 386 boolean mInResumeTopActivity = false; 387 388 int mCurrentUser; 389 390 String affinity; // The affinity name for this task, or null; may change identity. 391 String rootAffinity; // Initial base affinity, or null; does not change from initial root. 392 String mWindowLayoutAffinity; // Launch param affinity of this task or null. Used when saving 393 // launch params of this task. 394 IVoiceInteractionSession voiceSession; // Voice interaction session driving task 395 IVoiceInteractor voiceInteractor; // Associated interactor to provide to app 396 Intent intent; // The original intent that started the task. Note that this value can 397 // be null. 398 Intent affinityIntent; // Intent of affinity-moved activity that started this task. 399 int effectiveUid; // The current effective uid of the identity of this task. 400 ComponentName origActivity; // The non-alias activity component of the intent. 401 ComponentName realActivity; // The actual activity component that started the task. 402 boolean realActivitySuspended; // True if the actual activity component that started the 403 // task is suspended. 404 boolean inRecents; // Actually in the recents list? 405 long lastActiveTime; // Last time this task was active in the current device session, 406 // including sleep. This time is initialized to the elapsed time when 407 // restored from disk. 408 boolean isAvailable; // Is the activity available to be launched? 409 boolean rootWasReset; // True if the intent at the root of the task had 410 // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag. 411 boolean autoRemoveRecents; // If true, we should automatically remove the task from 412 // recents when activity finishes 413 boolean askedCompatMode;// Have asked the user about compat mode for this task. 414 private boolean mHasBeenVisible; // Set if any activities in the task have been visible 415 416 String stringName; // caching of toString() result. 417 boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity 418 // was changed. 419 420 int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE; 421 422 int mLockTaskUid = -1; // The uid of the application that called startLockTask(). 423 424 /** The process that had previously hosted the root activity of this task. 425 * Used to know that we should try harder to keep this process around, in case the 426 * user wants to return to it. */ 427 private WindowProcessController mRootProcess; 428 429 /** Takes on same value as first root activity */ 430 boolean isPersistable = false; 431 int maxRecents; 432 433 /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for 434 * determining the order when restoring. */ 435 long mLastTimeMoved; 436 437 /** If original intent did not allow relinquishing task identity, save that information */ 438 private boolean mNeverRelinquishIdentity = true; 439 440 /** Avoid reentrant of {@link #removeImmediately(String)}. */ 441 private boolean mRemoving; 442 443 // Used in the unique case where we are clearing the task in order to reuse it. In that case we 444 // do not want to delete the root task when the task goes empty. 445 private boolean mReuseTask = false; 446 447 CharSequence lastDescription; // Last description captured for this item. 448 449 Task mAdjacentTask; // Task adjacent to this one. 450 int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent. 451 Task mPrevAffiliate; // previous task in affiliated chain. 452 int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence. 453 Task mNextAffiliate; // next task in affiliated chain. 454 int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence. 455 456 // For relaunching the task from recents as though it was launched by the original launcher. 457 int mCallingUid; 458 String mCallingPackage; 459 String mCallingFeatureId; 460 461 private final Rect mTmpStableBounds = new Rect(); 462 private final Rect mTmpNonDecorBounds = new Rect(); 463 private final Rect mTmpBounds = new Rect(); 464 private final Rect mTmpInsets = new Rect(); 465 private final Rect mTmpFullBounds = new Rect(); 466 private static final Rect sTmpBounds = new Rect(); 467 468 // Last non-fullscreen bounds the task was launched in or resized to. 469 // The information is persisted and used to determine the appropriate root task to launch the 470 // task into on restore. 471 Rect mLastNonFullscreenBounds = null; 472 // Minimal width and height of this task when it's resizeable. -1 means it should use the 473 // default minimal width/height. 474 int mMinWidth; 475 int mMinHeight; 476 477 // The surface transition of the target when recents animation is finished. 478 // This is originally introduced to carry out the current surface control position and window 479 // crop when a multi-activity task enters pip with autoEnterPip enabled. In such case, 480 // the surface control of the task will be animated in Launcher and then the top activity is 481 // reparented to pinned root task. 482 // Do not forget to reset this after reparenting. 483 // TODO: remove this once the recents animation is moved to the Shell 484 PictureInPictureSurfaceTransaction mLastRecentsAnimationTransaction; 485 // The content overlay to be applied with mLastRecentsAnimationTransaction 486 // TODO: remove this once the recents animation is moved to the Shell 487 SurfaceControl mLastRecentsAnimationOverlay; 488 489 static final int LAYER_RANK_INVISIBLE = -1; 490 // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible) 491 // This number will be assigned when we evaluate OOM scores for all visible tasks. 492 int mLayerRank = LAYER_RANK_INVISIBLE; 493 494 /** Helper object used for updating override configuration. */ 495 private Configuration mTmpConfig = new Configuration(); 496 497 /** Used by fillTaskInfo */ 498 final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport(); 499 500 final ActivityTaskManagerService mAtmService; 501 final ActivityTaskSupervisor mTaskSupervisor; 502 final RootWindowContainer mRootWindowContainer; 503 504 /* Unique identifier for this task. */ 505 final int mTaskId; 506 /* User for which this task was created. */ 507 // TODO: Make final 508 int mUserId; 509 510 // Id of the previous display the root task was on. 511 int mPrevDisplayId = INVALID_DISPLAY; 512 513 /** ID of the display which rotation {@link #mRotation} has. */ 514 private int mLastRotationDisplayId = INVALID_DISPLAY; 515 516 /** 517 * Display rotation as of the last time {@link #setBounds(Rect)} was called or this task was 518 * moved to a new display. 519 */ 520 @Surface.Rotation 521 private int mRotation; 522 523 /** 524 * Last requested orientation reported to DisplayContent. This is different from {@link 525 * #mOrientation} in the sense that this takes activities' requested orientation into 526 * account. Start with {@link ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} so that we don't need 527 * to notify for activities that don't specify any orientation. 528 */ 529 int mLastReportedRequestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 530 531 // For comparison with DisplayContent bounds. 532 private Rect mTmpRect = new Rect(); 533 // For handling display rotations. 534 private Rect mTmpRect2 = new Rect(); 535 536 // Resize mode of the task. See {@link ActivityInfo#resizeMode} 537 // Based on the {@link ActivityInfo#resizeMode} of the root activity. 538 int mResizeMode; 539 540 // Whether or not this task and its activities support PiP. Based on the 541 // {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag of the root activity. 542 boolean mSupportsPictureInPicture; 543 544 // Whether the task is currently being drag-resized 545 private boolean mDragResizing; 546 private int mDragResizeMode; 547 548 // This represents the last resolved activity values for this task 549 // NOTE: This value needs to be persisted with each task 550 private TaskDescription mTaskDescription; 551 552 // Information about the last snapshot that should be persisted with the task to allow SystemUI 553 // to layout without loading all the task snapshots 554 final PersistedTaskSnapshotData mLastTaskSnapshotData; 555 556 // If set to true, the task will report that it is not in the floating 557 // state regardless of it's root task affiliation. As the floating state drives 558 // production of content insets this can be used to preserve them across 559 // root task moves and we in fact do so when moving from full screen to pinned. 560 private boolean mPreserveNonFloatingState = false; 561 562 private Dimmer mDimmer = new Dimmer(this); 563 private final Rect mTmpDimBoundsRect = new Rect(); 564 private final Point mLastSurfaceSize = new Point(); 565 566 /** @see #setCanAffectSystemUiFlags */ 567 private boolean mCanAffectSystemUiFlags = true; 568 569 private static Exception sTmpException; 570 571 /** ActivityRecords that are exiting, but still on screen for animations. */ 572 final ArrayList<ActivityRecord> mExitingActivities = new ArrayList<>(); 573 574 /** 575 * When we are in the process of pausing an activity, before starting the 576 * next one, this variable holds the activity that is currently being paused. 577 * 578 * Only set at leaf tasks. 579 */ 580 @Nullable 581 private ActivityRecord mPausingActivity = null; 582 583 /** 584 * This is the last activity that we put into the paused state. This is 585 * used to determine if we need to do an activity transition while sleeping, 586 * when we normally hold the top activity paused. 587 */ 588 ActivityRecord mLastPausedActivity = null; 589 590 /** 591 * Current activity that is resumed, or null if there is none. 592 * Only set at leaf tasks. 593 */ 594 @Nullable 595 private ActivityRecord mResumedActivity = null; 596 597 private boolean mForceShowForAllUsers; 598 599 /** When set, will force the task to report as invisible. */ 600 static final int FLAG_FORCE_HIDDEN_FOR_PINNED_TASK = 1; 601 static final int FLAG_FORCE_HIDDEN_FOR_TASK_ORG = 1 << 1; 602 private int mForceHiddenFlags = 0; 603 604 // TODO(b/160201781): Revisit double invocation issue in Task#removeChild. 605 /** 606 * Skip {@link ActivityTaskSupervisor#removeTask(Task, boolean, boolean, String)} execution if 607 * {@code true} to prevent double traversal of {@link #mChildren} in a loop. 608 */ 609 boolean mInRemoveTask; 610 611 // When non-null, this is a transaction that will get applied on the next frame returned after 612 // a relayout is requested from the client. While this is only valid on a leaf task; since the 613 // transaction can effect an ancestor task, this also needs to keep track of the ancestor task 614 // that this transaction manipulates because deferUntilFrame acts on individual surfaces. 615 SurfaceControl.Transaction mMainWindowSizeChangeTransaction; 616 Task mMainWindowSizeChangeTask; 617 618 private final AnimatingActivityRegistry mAnimatingActivityRegistry = 619 new AnimatingActivityRegistry(); 620 621 private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_TASK_MSG + 1; 622 623 private final Handler mHandler; 624 625 private class ActivityTaskHandler extends Handler { 626 ActivityTaskHandler(Looper looper)627 ActivityTaskHandler(Looper looper) { 628 super(looper); 629 } 630 631 @Override handleMessage(Message msg)632 public void handleMessage(Message msg) { 633 switch (msg.what) { 634 case TRANSLUCENT_TIMEOUT_MSG: { 635 synchronized (mAtmService.mGlobalLock) { 636 notifyActivityDrawnLocked(null); 637 } 638 } break; 639 } 640 } 641 } 642 643 private static final ResetTargetTaskHelper sResetTargetTaskHelper = new ResetTargetTaskHelper(); 644 private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper = 645 new EnsureActivitiesVisibleHelper(this); 646 private final EnsureVisibleActivitiesConfigHelper mEnsureVisibleActivitiesConfigHelper = 647 new EnsureVisibleActivitiesConfigHelper(); 648 private class EnsureVisibleActivitiesConfigHelper { 649 private boolean mUpdateConfig; 650 private boolean mPreserveWindow; 651 private boolean mBehindFullscreen; 652 reset(boolean preserveWindow)653 void reset(boolean preserveWindow) { 654 mPreserveWindow = preserveWindow; 655 mUpdateConfig = false; 656 mBehindFullscreen = false; 657 } 658 process(ActivityRecord start, boolean preserveWindow)659 void process(ActivityRecord start, boolean preserveWindow) { 660 if (start == null || !start.mVisibleRequested) { 661 return; 662 } 663 reset(preserveWindow); 664 665 final PooledFunction f = PooledLambda.obtainFunction( 666 EnsureVisibleActivitiesConfigHelper::processActivity, this, 667 PooledLambda.__(ActivityRecord.class)); 668 forAllActivities(f, start, true /*includeBoundary*/, true /*traverseTopToBottom*/); 669 f.recycle(); 670 671 if (mUpdateConfig) { 672 // Ensure the resumed state of the focus activity if we updated the configuration of 673 // any activity. 674 mRootWindowContainer.resumeFocusedTasksTopActivities(); 675 } 676 } 677 processActivity(ActivityRecord r)678 boolean processActivity(ActivityRecord r) { 679 mUpdateConfig |= r.ensureActivityConfiguration(0 /*globalChanges*/, mPreserveWindow); 680 mBehindFullscreen |= r.occludesParent(); 681 return mBehindFullscreen; 682 } 683 } 684 685 private final CheckBehindFullscreenActivityHelper mCheckBehindFullscreenActivityHelper = 686 new CheckBehindFullscreenActivityHelper(); 687 private class CheckBehindFullscreenActivityHelper { 688 private boolean mAboveTop; 689 private boolean mBehindFullscreenActivity; 690 private ActivityRecord mToCheck; 691 private Consumer<ActivityRecord> mHandleBehindFullscreenActivity; 692 private boolean mHandlingOccluded; 693 reset(ActivityRecord toCheck, Consumer<ActivityRecord> handleBehindFullscreenActivity)694 private void reset(ActivityRecord toCheck, 695 Consumer<ActivityRecord> handleBehindFullscreenActivity) { 696 mToCheck = toCheck; 697 mHandleBehindFullscreenActivity = handleBehindFullscreenActivity; 698 mAboveTop = true; 699 mBehindFullscreenActivity = false; 700 701 if (!shouldBeVisible(null)) { 702 // The root task is not visible, so no activity in it should be displaying a 703 // starting window. Mark all activities below top and behind fullscreen. 704 mAboveTop = false; 705 mBehindFullscreenActivity = true; 706 } 707 708 mHandlingOccluded = mToCheck == null && mHandleBehindFullscreenActivity != null; 709 } 710 process(ActivityRecord toCheck, Consumer<ActivityRecord> handleBehindFullscreenActivity)711 boolean process(ActivityRecord toCheck, 712 Consumer<ActivityRecord> handleBehindFullscreenActivity) { 713 reset(toCheck, handleBehindFullscreenActivity); 714 715 if (!mHandlingOccluded && mBehindFullscreenActivity) { 716 return true; 717 } 718 719 final ActivityRecord topActivity = topRunningActivity(); 720 final PooledFunction f = PooledLambda.obtainFunction( 721 CheckBehindFullscreenActivityHelper::processActivity, this, 722 PooledLambda.__(ActivityRecord.class), topActivity); 723 forAllActivities(f); 724 f.recycle(); 725 726 return mBehindFullscreenActivity; 727 } 728 729 /** Returns {@code true} to stop the outer loop and indicate the result is computed. */ processActivity(ActivityRecord r, ActivityRecord topActivity)730 private boolean processActivity(ActivityRecord r, ActivityRecord topActivity) { 731 if (mAboveTop) { 732 if (r == topActivity) { 733 if (r == mToCheck) { 734 // It is the top activity in a visible root task. 735 mBehindFullscreenActivity = false; 736 return true; 737 } 738 mAboveTop = false; 739 } 740 mBehindFullscreenActivity |= r.occludesParent(); 741 return false; 742 } 743 744 if (mHandlingOccluded) { 745 // Iterating through all occluded activities. 746 if (mBehindFullscreenActivity) { 747 mHandleBehindFullscreenActivity.accept(r); 748 } 749 } else if (r == mToCheck) { 750 return true; 751 } else if (mBehindFullscreenActivity) { 752 // It is occluded before {@param toCheck} is found. 753 return true; 754 } 755 mBehindFullscreenActivity |= r.occludesParent(); 756 return false; 757 } 758 } 759 760 private final FindRootHelper mFindRootHelper = new FindRootHelper(); 761 private class FindRootHelper { 762 private ActivityRecord mRoot; 763 clear()764 private void clear() { 765 mRoot = null; 766 } 767 findRoot(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone)768 ActivityRecord findRoot(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) { 769 final PooledFunction f = PooledLambda.obtainFunction(FindRootHelper::processActivity, 770 this, PooledLambda.__(ActivityRecord.class), ignoreRelinquishIdentity, 771 setToBottomIfNone); 772 clear(); 773 forAllActivities(f, false /*traverseTopToBottom*/); 774 f.recycle(); 775 return mRoot; 776 } 777 processActivity(ActivityRecord r, boolean ignoreRelinquishIdentity, boolean setToBottomIfNone)778 private boolean processActivity(ActivityRecord r, 779 boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) { 780 if (mRoot == null && setToBottomIfNone) { 781 // This is the first activity we are process. Set it as the candidate root in case 782 // we don't find a better one. 783 mRoot = r; 784 } 785 786 if (r.finishing) return false; 787 788 // Set this as the candidate root since it isn't finishing. 789 mRoot = r; 790 791 // Only end search if we are ignore relinquishing identity or we are not relinquishing. 792 return ignoreRelinquishIdentity || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0; 793 } 794 } 795 796 /** 797 * The TaskOrganizer which is delegated presentation of this task. If set the Task will 798 * emit an WindowContainerToken (allowing access to it's SurfaceControl leash) to the organizers 799 * taskAppeared callback, and emit a taskRemoved callback when the Task is vanished. 800 */ 801 ITaskOrganizer mTaskOrganizer; 802 803 /** 804 * Prevent duplicate calls to onTaskAppeared. 805 */ 806 boolean mTaskAppearedSent; 807 808 // If the sending of the task appear signal should be deferred until this flag is set back to 809 // false. 810 private boolean mDeferTaskAppear; 811 812 /** 813 * Forces this task to be unorganized. Currently it is used for deferring the control of 814 * organizer when windowing mode is changing from PiP to fullscreen with orientation change. 815 * It is true only during Task#setWindowingMode ~ DisplayRotation#continueRotation. 816 * 817 * TODO(b/179235349): Remove this field by making surface operations from task organizer sync 818 * with display rotation. 819 */ 820 private boolean mForceNotOrganized; 821 822 /** 823 * This task was created by the task organizer which has the following implementations. 824 * <ul> 825 * <lis>The task won't be removed when it is empty. Removal has to be an explicit request 826 * from the task organizer.</li> 827 * <li>Unlike other non-root tasks, it's direct children are visible to the task 828 * organizer for ordering purposes.</li> 829 * </ul> 830 */ 831 @VisibleForTesting 832 boolean mCreatedByOrganizer; 833 834 // Tracking cookie for the creation of this task. 835 IBinder mLaunchCookie; 836 837 // The task will be removed when TaskOrganizer, which is managing the task, is destroyed. 838 boolean mRemoveWithTaskOrganizer; 839 840 /** 841 * Reference to the pinned activity that is logically parented to this task, ie. 842 * the previous top activity within this task is put into pinned mode. 843 * This always gets cleared in pair with the ActivityRecord-to-Task link as seen in 844 * {@link ActivityRecord#clearLastParentBeforePip()}. 845 */ 846 ActivityRecord mChildPipActivity; 847 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)848 private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent, 849 Intent _affinityIntent, String _affinity, String _rootAffinity, 850 ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, 851 boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, int _effectiveUid, 852 String _lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity, 853 TaskDescription _lastTaskDescription, PersistedTaskSnapshotData _lastSnapshotData, 854 int taskAffiliation, int prevTaskId, int nextTaskId, int callingUid, 855 String callingPackage, @Nullable String callingFeatureId, int resizeMode, 856 boolean supportsPictureInPicture, boolean _realActivitySuspended, 857 boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info, 858 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, 859 boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear, 860 boolean _removeWithTaskOrganizer) { 861 super(atmService.mWindowManager); 862 863 mAtmService = atmService; 864 mTaskSupervisor = atmService.mTaskSupervisor; 865 mRootWindowContainer = mAtmService.mRootWindowContainer; 866 mTaskId = _taskId; 867 mUserId = _userId; 868 mResizeMode = resizeMode; 869 mSupportsPictureInPicture = supportsPictureInPicture; 870 mTaskDescription = _lastTaskDescription != null 871 ? _lastTaskDescription 872 : new TaskDescription(); 873 mLastTaskSnapshotData = _lastSnapshotData != null 874 ? _lastSnapshotData 875 : new PersistedTaskSnapshotData(); 876 // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED). 877 setOrientation(SCREEN_ORIENTATION_UNSET); 878 mRemoteToken = new RemoteToken(this); 879 affinityIntent = _affinityIntent; 880 affinity = _affinity; 881 rootAffinity = _rootAffinity; 882 voiceSession = _voiceSession; 883 voiceInteractor = _voiceInteractor; 884 realActivity = _realActivity; 885 realActivitySuspended = _realActivitySuspended; 886 origActivity = _origActivity; 887 rootWasReset = _rootWasReset; 888 isAvailable = true; 889 autoRemoveRecents = _autoRemoveRecents; 890 askedCompatMode = _askedCompatMode; 891 mUserSetupComplete = userSetupComplete; 892 effectiveUid = _effectiveUid; 893 touchActiveTime(); 894 lastDescription = _lastDescription; 895 mLastTimeMoved = lastTimeMoved; 896 mNeverRelinquishIdentity = neverRelinquishIdentity; 897 mAffiliatedTaskId = taskAffiliation; 898 mPrevAffiliateTaskId = prevTaskId; 899 mNextAffiliateTaskId = nextTaskId; 900 mCallingUid = callingUid; 901 mCallingPackage = callingPackage; 902 mCallingFeatureId = callingFeatureId; 903 mResizeMode = resizeMode; 904 if (info != null) { 905 setIntent(_intent, info); 906 setMinDimensions(info); 907 } else { 908 intent = _intent; 909 mMinWidth = minWidth; 910 mMinHeight = minHeight; 911 } 912 mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity); 913 mHandler = new ActivityTaskHandler(mTaskSupervisor.mLooper); 914 mCurrentUser = mAtmService.mAmInternal.getCurrentUserId(); 915 916 mCreatedByOrganizer = _createdByOrganizer; 917 mLaunchCookie = _launchCookie; 918 mDeferTaskAppear = _deferTaskAppear; 919 mRemoveWithTaskOrganizer = _removeWithTaskOrganizer; 920 EventLogTags.writeWmTaskCreated(mTaskId, isRootTask() ? INVALID_TASK_ID : getRootTaskId()); 921 } 922 fromWindowContainerToken(WindowContainerToken token)923 static Task fromWindowContainerToken(WindowContainerToken token) { 924 if (token == null) return null; 925 return fromBinder(token.asBinder()).asTask(); 926 } 927 reuseAsLeafTask(IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, Intent intent, ActivityInfo info, ActivityRecord activity)928 Task reuseAsLeafTask(IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, 929 Intent intent, ActivityInfo info, ActivityRecord activity) { 930 voiceSession = _voiceSession; 931 voiceInteractor = _voiceInteractor; 932 setIntent(activity, intent, info); 933 setMinDimensions(info); 934 // Before we began to reuse a root task as the leaf task, we used to 935 // create a leaf task in this case. Therefore now we won't send out the task created 936 // notification when we decide to reuse it here, so we send out the notification below. 937 // The reason why the created notification sent out when root task is created doesn't work 938 // is that realActivity isn't set until setIntent() method above is called for the first 939 // time. Eventually this notification will be removed when we can populate those information 940 // when root task is created. 941 mAtmService.getTaskChangeNotificationController().notifyTaskCreated(mTaskId, realActivity); 942 return this; 943 } 944 cleanUpResourcesForDestroy(ConfigurationContainer oldParent)945 private void cleanUpResourcesForDestroy(ConfigurationContainer oldParent) { 946 if (hasChild()) { 947 return; 948 } 949 950 // This task is going away, so save the last state if necessary. 951 saveLaunchingStateIfNeeded(((WindowContainer) oldParent).getDisplayContent()); 952 953 // TODO: VI what about activity? 954 final boolean isVoiceSession = voiceSession != null; 955 if (isVoiceSession) { 956 try { 957 voiceSession.taskFinished(intent, mTaskId); 958 } catch (RemoteException e) { 959 } 960 } 961 if (autoRemoveFromRecents() || isVoiceSession) { 962 // Task creator asked to remove this when done, or this task was a voice 963 // interaction, so it should not remain on the recent tasks list. 964 mTaskSupervisor.mRecentTasks.remove(this); 965 } 966 967 removeIfPossible("cleanUpResourcesForDestroy"); 968 } 969 970 @VisibleForTesting 971 @Override removeIfPossible()972 void removeIfPossible() { 973 removeIfPossible("removeTaskIfPossible"); 974 } 975 removeIfPossible(String reason)976 void removeIfPossible(String reason) { 977 mAtmService.getLockTaskController().clearLockedTask(this); 978 if (shouldDeferRemoval()) { 979 if (DEBUG_ROOT_TASK) Slog.i(TAG, 980 "removeTask:" + reason + " deferring removing taskId=" + mTaskId); 981 return; 982 } 983 removeImmediately(reason); 984 if (isLeafTask()) { 985 mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId); 986 987 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 988 if (taskDisplayArea != null) { 989 taskDisplayArea.onLeafTaskRemoved(mTaskId); 990 } 991 } 992 } 993 setResizeMode(int resizeMode)994 void setResizeMode(int resizeMode) { 995 if (mResizeMode == resizeMode) { 996 return; 997 } 998 mResizeMode = resizeMode; 999 mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); 1000 mRootWindowContainer.resumeFocusedTasksTopActivities(); 1001 updateTaskDescription(); 1002 } 1003 resize(Rect bounds, int resizeMode, boolean preserveWindow)1004 boolean resize(Rect bounds, int resizeMode, boolean preserveWindow) { 1005 mAtmService.deferWindowLayout(); 1006 1007 try { 1008 final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0; 1009 1010 if (getParent() == null) { 1011 // Task doesn't exist in window manager yet (e.g. was restored from recents). 1012 // All we can do for now is update the bounds so it can be used when the task is 1013 // added to window manager. 1014 setBounds(bounds); 1015 if (!inFreeformWindowingMode()) { 1016 // re-restore the task so it can have the proper root task association. 1017 mTaskSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP); 1018 } 1019 return true; 1020 } 1021 1022 if (!canResizeToBounds(bounds)) { 1023 throw new IllegalArgumentException("resizeTask: Can not resize task=" + this 1024 + " to bounds=" + bounds + " resizeMode=" + mResizeMode); 1025 } 1026 1027 // Do not move the task to another root task here. 1028 // This method assumes that the task is already placed in the right root task. 1029 // we do not mess with that decision and we only do the resize! 1030 1031 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizeTask_" + mTaskId); 1032 1033 boolean updatedConfig = false; 1034 mTmpConfig.setTo(getResolvedOverrideConfiguration()); 1035 if (setBounds(bounds) != BOUNDS_CHANGE_NONE) { 1036 updatedConfig = !mTmpConfig.equals(getResolvedOverrideConfiguration()); 1037 } 1038 // This variable holds information whether the configuration didn't change in a 1039 // significant way and the activity was kept the way it was. If it's false, it means 1040 // the activity had to be relaunched due to configuration change. 1041 boolean kept = true; 1042 if (updatedConfig) { 1043 final ActivityRecord r = topRunningActivityLocked(); 1044 if (r != null) { 1045 kept = r.ensureActivityConfiguration(0 /* globalChanges */, 1046 preserveWindow); 1047 // Preserve other windows for resizing because if resizing happens when there 1048 // is a dialog activity in the front, the activity that still shows some 1049 // content to the user will become black and cause flickers. Note in most cases 1050 // this won't cause tons of irrelevant windows being preserved because only 1051 // activities in this task may experience a bounds change. Configs for other 1052 // activities stay the same. 1053 mRootWindowContainer.ensureActivitiesVisible(r, 0, preserveWindow); 1054 if (!kept) { 1055 mRootWindowContainer.resumeFocusedTasksTopActivities(); 1056 } 1057 } 1058 } 1059 resize(kept, forced); 1060 1061 saveLaunchingStateIfNeeded(); 1062 1063 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 1064 return kept; 1065 } finally { 1066 mAtmService.continueWindowLayout(); 1067 } 1068 } 1069 1070 /** 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)1071 boolean reparent(Task preferredRootTask, boolean toTop, 1072 @ReparentMoveRootTaskMode int moveRootTaskMode, boolean animate, boolean deferResume, 1073 String reason) { 1074 return reparent(preferredRootTask, toTop ? MAX_VALUE : 0, moveRootTaskMode, animate, 1075 deferResume, true /* schedulePictureInPictureModeChange */, reason); 1076 } 1077 1078 /** 1079 * Reparents the task into a preferred root task, creating it if necessary. 1080 * 1081 * @param preferredRootTask the target root task to move this task 1082 * @param position the position to place this task in the new root task 1083 * @param animate whether or not we should wait for the new window created as a part of the 1084 * reparenting to be drawn and animated in 1085 * @param moveRootTaskMode whether or not to move the root task to the front always, only if 1086 * it was previously focused & in front, or never 1087 * @param deferResume whether or not to update the visibility of other tasks and root tasks 1088 * that may have changed as a result of this reparenting 1089 * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode 1090 * change. Callers may set this to false if they are explicitly scheduling PiP mode 1091 * changes themselves, like during the PiP animation 1092 * @param reason the caller of this reparenting 1093 * @return whether the task was reparented 1094 */ 1095 // TODO: Inspect all call sites and change to just changing windowing mode of the root task vs. 1096 // 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)1097 boolean reparent(Task preferredRootTask, int position, 1098 @ReparentMoveRootTaskMode int moveRootTaskMode, boolean animate, boolean deferResume, 1099 boolean schedulePictureInPictureModeChange, String reason) { 1100 final ActivityTaskSupervisor supervisor = mTaskSupervisor; 1101 final RootWindowContainer root = mRootWindowContainer; 1102 final WindowManagerService windowManager = mAtmService.mWindowManager; 1103 final Task sourceRootTask = getRootTask(); 1104 final Task toRootTask = supervisor.getReparentTargetRootTask(this, preferredRootTask, 1105 position == MAX_VALUE); 1106 if (toRootTask == sourceRootTask) { 1107 return false; 1108 } 1109 if (!canBeLaunchedOnDisplay(toRootTask.getDisplayId())) { 1110 return false; 1111 } 1112 1113 final int toRootTaskWindowingMode = toRootTask.getWindowingMode(); 1114 final ActivityRecord topActivity = getTopNonFinishingActivity(); 1115 1116 final boolean mightReplaceWindow = topActivity != null 1117 && replaceWindowsOnTaskMove(getWindowingMode(), toRootTaskWindowingMode); 1118 if (mightReplaceWindow) { 1119 // We are about to relaunch the activity because its configuration changed due to 1120 // being maximized, i.e. size change. The activity will first remove the old window 1121 // and then add a new one. This call will tell window manager about this, so it can 1122 // preserve the old window until the new one is drawn. This prevents having a gap 1123 // between the removal and addition, in which no window is visible. We also want the 1124 // entrance of the new window to be properly animated. 1125 // Note here we always set the replacing window first, as the flags might be needed 1126 // during the relaunch. If we end up not doing any relaunch, we clear the flags later. 1127 windowManager.setWillReplaceWindow(topActivity.appToken, animate); 1128 } 1129 1130 mAtmService.deferWindowLayout(); 1131 boolean kept = true; 1132 try { 1133 final ActivityRecord r = topRunningActivityLocked(); 1134 final boolean wasFocused = r != null && root.isTopDisplayFocusedRootTask(sourceRootTask) 1135 && (topRunningActivityLocked() == r); 1136 1137 // In some cases the focused root task isn't the front root task. E.g. root pinned task. 1138 // Whenever we are moving the top activity from the front root task we want to make 1139 // sure to move the root task to the front. 1140 final boolean wasFront = r != null && sourceRootTask.isTopRootTaskInDisplayArea() 1141 && (sourceRootTask.topRunningActivity() == r); 1142 1143 final boolean moveRootTaskToFront = moveRootTaskMode == REPARENT_MOVE_ROOT_TASK_TO_FRONT 1144 || (moveRootTaskMode == REPARENT_KEEP_ROOT_TASK_AT_FRONT 1145 && (wasFocused || wasFront)); 1146 1147 reparent(toRootTask, position, moveRootTaskToFront, reason); 1148 1149 if (schedulePictureInPictureModeChange) { 1150 // Notify of picture-in-picture mode changes 1151 supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceRootTask); 1152 } 1153 1154 // If the task had focus before (or we're requested to move focus), move focus to the 1155 // new root task by moving the root task to the front. 1156 if (r != null && moveRootTaskToFront) { 1157 // Move the root task in which we are placing the activity to the front. 1158 toRootTask.moveToFront(reason); 1159 1160 // If the original state is resumed, there is no state change to update focused app. 1161 // So here makes sure the activity focus is set if it is the top. 1162 if (r.isState(RESUMED) && r == mRootWindowContainer.getTopResumedActivity()) { 1163 mAtmService.setResumedActivityUncheckLocked(r, reason); 1164 } 1165 } 1166 if (!animate) { 1167 mTaskSupervisor.mNoAnimActivities.add(topActivity); 1168 } 1169 1170 if (toRootTaskWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY 1171 && moveRootTaskMode == REPARENT_KEEP_ROOT_TASK_AT_FRONT) { 1172 // Move recents to front so it is not behind root home task when going into docked 1173 // mode 1174 mTaskSupervisor.moveRecentsRootTaskToFront(reason); 1175 } 1176 } finally { 1177 mAtmService.continueWindowLayout(); 1178 } 1179 1180 if (mightReplaceWindow) { 1181 // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old 1182 // window), we need to clear the replace window settings. Otherwise, we schedule a 1183 // timeout to remove the old window if the replacing window is not coming in time. 1184 windowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept); 1185 } 1186 1187 if (!deferResume) { 1188 // The task might have already been running and its visibility needs to be synchronized 1189 // with the visibility of the root task / windows. 1190 root.ensureActivitiesVisible(null, 0, !mightReplaceWindow); 1191 root.resumeFocusedTasksTopActivities(); 1192 } 1193 1194 // TODO: Handle incorrect request to move before the actual move, not after. 1195 supervisor.handleNonResizableTaskIfNeeded(this, preferredRootTask.getWindowingMode(), 1196 mRootWindowContainer.getDefaultTaskDisplayArea(), toRootTask); 1197 1198 return (preferredRootTask == toRootTask); 1199 } 1200 1201 /** 1202 * @return {@code true} if the windows of tasks being moved to the target root task from the 1203 * source root task should be replaced, meaning that window manager will keep the old window 1204 * around until the new is ready. 1205 */ replaceWindowsOnTaskMove( int sourceWindowingMode, int targetWindowingMode)1206 private static boolean replaceWindowsOnTaskMove( 1207 int sourceWindowingMode, int targetWindowingMode) { 1208 return sourceWindowingMode == WINDOWING_MODE_FREEFORM 1209 || targetWindowingMode == WINDOWING_MODE_FREEFORM; 1210 } 1211 1212 /** 1213 * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD! 1214 */ getSnapshot(boolean isLowResolution, boolean restoreFromDisk)1215 TaskSnapshot getSnapshot(boolean isLowResolution, boolean restoreFromDisk) { 1216 1217 // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more 1218 // synchronized between AM and WM. 1219 return mAtmService.mWindowManager.getTaskSnapshot(mTaskId, mUserId, isLowResolution, 1220 restoreFromDisk); 1221 } 1222 touchActiveTime()1223 void touchActiveTime() { 1224 lastActiveTime = SystemClock.elapsedRealtime(); 1225 } 1226 getInactiveDuration()1227 long getInactiveDuration() { 1228 return SystemClock.elapsedRealtime() - lastActiveTime; 1229 } 1230 1231 /** @see #setIntent(ActivityRecord, Intent, ActivityInfo) */ setIntent(ActivityRecord r)1232 void setIntent(ActivityRecord r) { 1233 setIntent(r, null /* intent */, null /* info */); 1234 } 1235 1236 /** 1237 * Sets the original intent, and the calling uid and package. 1238 * 1239 * @param r The activity that started the task 1240 * @param intent The task info which could be different from {@code r.intent} if set. 1241 * @param info The activity info which could be different from {@code r.info} if set. 1242 */ setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info)1243 void setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info) { 1244 if (this.intent == null || !mNeverRelinquishIdentity) { 1245 mCallingUid = r.launchedFromUid; 1246 mCallingPackage = r.launchedFromPackage; 1247 mCallingFeatureId = r.launchedFromFeatureId; 1248 setIntent(intent != null ? intent : r.intent, info != null ? info : r.info); 1249 return; 1250 } 1251 setLockTaskAuth(r); 1252 } 1253 1254 /** Sets the original intent, _without_ updating the calling uid or package. */ setIntent(Intent _intent, ActivityInfo info)1255 private void setIntent(Intent _intent, ActivityInfo info) { 1256 if (!isLeafTask()) return; 1257 1258 mNeverRelinquishIdentity = (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0; 1259 affinity = info.taskAffinity; 1260 if (intent == null) { 1261 // If this task already has an intent associated with it, don't set the root 1262 // affinity -- we don't want it changing after initially set, but the initially 1263 // set value may be null. 1264 rootAffinity = affinity; 1265 } 1266 effectiveUid = info.applicationInfo.uid; 1267 stringName = null; 1268 1269 if (info.targetActivity == null) { 1270 if (_intent != null) { 1271 // If this Intent has a selector, we want to clear it for the 1272 // recent task since it is not relevant if the user later wants 1273 // to re-launch the app. 1274 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) { 1275 _intent = new Intent(_intent); 1276 _intent.setSelector(null); 1277 _intent.setSourceBounds(null); 1278 } 1279 } 1280 ProtoLog.v(WM_DEBUG_TASKS, "Setting Intent of %s to %s", this, _intent); 1281 intent = _intent; 1282 realActivity = _intent != null ? _intent.getComponent() : null; 1283 origActivity = null; 1284 } else { 1285 ComponentName targetComponent = new ComponentName( 1286 info.packageName, info.targetActivity); 1287 if (_intent != null) { 1288 Intent targetIntent = new Intent(_intent); 1289 targetIntent.setSelector(null); 1290 targetIntent.setSourceBounds(null); 1291 ProtoLog.v(WM_DEBUG_TASKS, "Setting Intent of %s to target %s", this, targetIntent); 1292 intent = targetIntent; 1293 realActivity = targetComponent; 1294 origActivity = _intent.getComponent(); 1295 } else { 1296 intent = null; 1297 realActivity = targetComponent; 1298 origActivity = new ComponentName(info.packageName, info.name); 1299 } 1300 } 1301 mWindowLayoutAffinity = 1302 info.windowLayout == null ? null : info.windowLayout.windowLayoutAffinity; 1303 1304 final int intentFlags = intent == null ? 0 : intent.getFlags(); 1305 if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { 1306 // Once we are set to an Intent with this flag, we count this 1307 // task as having a true root activity. 1308 rootWasReset = true; 1309 } 1310 mUserId = UserHandle.getUserId(info.applicationInfo.uid); 1311 mUserSetupComplete = Settings.Secure.getIntForUser( 1312 mAtmService.mContext.getContentResolver(), USER_SETUP_COMPLETE, 0, mUserId) != 0; 1313 if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) { 1314 // If the activity itself has requested auto-remove, then just always do it. 1315 autoRemoveRecents = true; 1316 } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS)) 1317 == FLAG_ACTIVITY_NEW_DOCUMENT) { 1318 // If the caller has not asked for the document to be retained, then we may 1319 // want to turn on auto-remove, depending on whether the target has set its 1320 // own document launch mode. 1321 if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) { 1322 autoRemoveRecents = false; 1323 } else { 1324 autoRemoveRecents = true; 1325 } 1326 } else { 1327 autoRemoveRecents = false; 1328 } 1329 if (mResizeMode != info.resizeMode) { 1330 mResizeMode = info.resizeMode; 1331 updateTaskDescription(); 1332 } 1333 mSupportsPictureInPicture = info.supportsPictureInPicture(); 1334 } 1335 1336 /** Sets the original minimal width and height. */ setMinDimensions(ActivityInfo info)1337 void setMinDimensions(ActivityInfo info) { 1338 if (info != null && info.windowLayout != null) { 1339 mMinWidth = info.windowLayout.minWidth; 1340 mMinHeight = info.windowLayout.minHeight; 1341 } else { 1342 mMinWidth = INVALID_MIN_SIZE; 1343 mMinHeight = INVALID_MIN_SIZE; 1344 } 1345 } 1346 1347 /** 1348 * Return true if the input activity has the same intent filter as the intent this task 1349 * record is based on (normally the root activity intent). 1350 */ isSameIntentFilter(ActivityRecord r)1351 boolean isSameIntentFilter(ActivityRecord r) { 1352 final Intent intent = new Intent(r.intent); 1353 // Make sure the component are the same if the input activity has the same real activity 1354 // as the one in the task because either one of them could be the alias activity. 1355 if (Objects.equals(realActivity, r.mActivityComponent) && this.intent != null) { 1356 intent.setComponent(this.intent.getComponent()); 1357 } 1358 return intent.filterEquals(this.intent); 1359 } 1360 returnsToHomeRootTask()1361 boolean returnsToHomeRootTask() { 1362 if (inMultiWindowMode() || !hasChild()) return false; 1363 if (intent != null) { 1364 final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME; 1365 return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags; 1366 } 1367 final Task bottomTask = getBottomMostTask(); 1368 return bottomTask != this && bottomTask.returnsToHomeRootTask(); 1369 } 1370 setPrevAffiliate(Task prevAffiliate)1371 void setPrevAffiliate(Task prevAffiliate) { 1372 mPrevAffiliate = prevAffiliate; 1373 mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.mTaskId; 1374 } 1375 setNextAffiliate(Task nextAffiliate)1376 void setNextAffiliate(Task nextAffiliate) { 1377 mNextAffiliate = nextAffiliate; 1378 mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.mTaskId; 1379 } 1380 1381 @Override onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent)1382 void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { 1383 final DisplayContent display = newParent != null 1384 ? ((WindowContainer) newParent).getDisplayContent() : null; 1385 final DisplayContent oldDisplay = oldParent != null 1386 ? ((WindowContainer) oldParent).getDisplayContent() : null; 1387 1388 mPrevDisplayId = (oldDisplay != null) ? oldDisplay.mDisplayId : INVALID_DISPLAY; 1389 1390 if (oldParent != null && newParent == null) { 1391 cleanUpResourcesForDestroy(oldParent); 1392 } 1393 1394 if (display != null) { 1395 // TODO(b/168037178): Chat with the erosky@ of this code to see if this really makes 1396 // sense here... 1397 // Rotations are relative to the display. This means if there are 2 displays rotated 1398 // differently (eg. 2 monitors with one landscape and one portrait), moving a root task 1399 // from one to the other could look like a rotation change. To prevent this 1400 // apparent rotation change (and corresponding bounds rotation), pretend like our 1401 // current rotation is already the same as the new display. 1402 // Note, if Task or related logic ever gets nested, this logic will need 1403 // to move to onConfigurationChanged. 1404 getConfiguration().windowConfiguration.setRotation( 1405 display.getWindowConfiguration().getRotation()); 1406 } 1407 1408 super.onParentChanged(newParent, oldParent); 1409 1410 // Call this again after super onParentChanged in-case the surface wasn't created yet 1411 // (happens when the task is first inserted into the hierarchy). It's a no-op if it 1412 // already ran fully within super.onParentChanged 1413 updateTaskOrganizerState(false /* forceUpdate */); 1414 1415 // TODO(b/168037178): The check for null display content and setting it to null doesn't 1416 // really make sense here... 1417 1418 // TODO(b/168037178): This is mostly taking care of the case where the stask is removing 1419 // from the display, so we should probably consolidate it there instead. 1420 1421 if (getParent() == null && mDisplayContent != null) { 1422 mDisplayContent = null; 1423 mWmService.mWindowPlacerLocked.requestTraversal(); 1424 } 1425 1426 if (oldParent != null) { 1427 final Task oldParentTask = ((WindowContainer) oldParent).asTask(); 1428 if (oldParentTask != null) { 1429 final PooledConsumer c = PooledLambda.obtainConsumer( 1430 Task::cleanUpActivityReferences, oldParentTask, 1431 PooledLambda.__(ActivityRecord.class)); 1432 forAllActivities(c); 1433 c.recycle(); 1434 } 1435 1436 if (oldParent.inPinnedWindowingMode() 1437 && (newParent == null || !newParent.inPinnedWindowingMode())) { 1438 // Notify if a task from the root pinned task is being removed 1439 // (or moved depending on the mode). 1440 mRootWindowContainer.notifyActivityPipModeChanged(this, null); 1441 } 1442 } 1443 1444 if (newParent != null) { 1445 // TODO: Ensure that this is actually necessary here 1446 // Notify the voice session if required 1447 if (voiceSession != null) { 1448 try { 1449 voiceSession.taskStarted(intent, mTaskId); 1450 } catch (RemoteException e) { 1451 } 1452 } 1453 } 1454 1455 // First time we are adding the task to the system. 1456 if (oldParent == null && newParent != null) { 1457 1458 // TODO: Super random place to be doing this, but aligns with what used to be done 1459 // before we unified Task level. Look into if this can be done in a better place. 1460 updateOverrideConfigurationFromLaunchBounds(); 1461 } 1462 1463 // Update task bounds if needed. 1464 adjustBoundsForDisplayChangeIfNeeded(getDisplayContent()); 1465 1466 mRootWindowContainer.updateUIDsPresentOnDisplay(); 1467 } 1468 cleanUpActivityReferences(ActivityRecord r)1469 void cleanUpActivityReferences(ActivityRecord r) { 1470 // mPausingActivity is set at leaf task 1471 if (mPausingActivity != null && mPausingActivity == r) { 1472 mPausingActivity = null; 1473 } 1474 1475 if (mResumedActivity != null && mResumedActivity == r) { 1476 setResumedActivity(null, "cleanUpActivityReferences"); 1477 } 1478 1479 final WindowContainer parent = getParent(); 1480 if (parent != null && parent.asTask() != null) { 1481 parent.asTask().cleanUpActivityReferences(r); 1482 return; 1483 } 1484 r.removeTimeouts(); 1485 mExitingActivities.remove(r); 1486 } 1487 1488 /** @return the currently resumed activity. */ getResumedActivity()1489 ActivityRecord getResumedActivity() { 1490 if (isLeafTask()) { 1491 return mResumedActivity; 1492 } 1493 1494 final Task task = getTask(t -> t.mResumedActivity != null, true /* traverseTopToBottom */); 1495 return task != null ? task.mResumedActivity : null; 1496 } 1497 1498 @VisibleForTesting setPausingActivity(ActivityRecord pausing)1499 void setPausingActivity(ActivityRecord pausing) { 1500 mPausingActivity = pausing; 1501 } 1502 1503 /** 1504 * @return the currently pausing activity of this task or the topmost pausing activity of the 1505 * child tasks 1506 */ getPausingActivity()1507 ActivityRecord getPausingActivity() { 1508 if (isLeafTask()) { 1509 return mPausingActivity; 1510 } 1511 1512 final Task task = getTask(t -> t.mPausingActivity != null, true /* traverseTopToBottom */); 1513 return task != null ? task.mPausingActivity : null; 1514 } 1515 setResumedActivity(ActivityRecord r, String reason)1516 void setResumedActivity(ActivityRecord r, String reason) { 1517 warnForNonLeafTask("setResumedActivity"); 1518 if (mResumedActivity == r) { 1519 return; 1520 } 1521 1522 if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) Slog.d(TAG_ROOT_TASK, 1523 "setResumedActivity task:" + this + " + from: " 1524 + mResumedActivity + " to:" + r + " reason:" + reason); 1525 mResumedActivity = r; 1526 mTaskSupervisor.updateTopResumedActivityIfNeeded(); 1527 } 1528 updateTaskMovement(boolean toTop, int position)1529 void updateTaskMovement(boolean toTop, int position) { 1530 EventLogTags.writeWmTaskMoved(mTaskId, toTop ? 1 : 0, position); 1531 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 1532 if (taskDisplayArea != null && isLeafTask()) { 1533 taskDisplayArea.onLeafTaskMoved(this, toTop); 1534 } 1535 if (isPersistable) { 1536 mLastTimeMoved = System.currentTimeMillis(); 1537 } 1538 } 1539 1540 // Close up recents linked list. closeRecentsChain()1541 private void closeRecentsChain() { 1542 if (mPrevAffiliate != null) { 1543 mPrevAffiliate.setNextAffiliate(mNextAffiliate); 1544 } 1545 if (mNextAffiliate != null) { 1546 mNextAffiliate.setPrevAffiliate(mPrevAffiliate); 1547 } 1548 setPrevAffiliate(null); 1549 setNextAffiliate(null); 1550 } 1551 removedFromRecents()1552 void removedFromRecents() { 1553 closeRecentsChain(); 1554 if (inRecents) { 1555 inRecents = false; 1556 mAtmService.notifyTaskPersisterLocked(this, false); 1557 } 1558 1559 clearRootProcess(); 1560 1561 mAtmService.mWindowManager.mTaskSnapshotController.notifyTaskRemovedFromRecents( 1562 mTaskId, mUserId); 1563 } 1564 setAdjacentTask(Task adjacent)1565 void setAdjacentTask(Task adjacent) { 1566 mAdjacentTask = adjacent; 1567 adjacent.mAdjacentTask = this; 1568 } 1569 setTaskToAffiliateWith(Task taskToAffiliateWith)1570 void setTaskToAffiliateWith(Task taskToAffiliateWith) { 1571 closeRecentsChain(); 1572 mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId; 1573 // Find the end 1574 while (taskToAffiliateWith.mNextAffiliate != null) { 1575 final Task nextRecents = taskToAffiliateWith.mNextAffiliate; 1576 if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) { 1577 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId=" 1578 + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId); 1579 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) { 1580 nextRecents.setPrevAffiliate(null); 1581 } 1582 taskToAffiliateWith.setNextAffiliate(null); 1583 break; 1584 } 1585 taskToAffiliateWith = nextRecents; 1586 } 1587 taskToAffiliateWith.setNextAffiliate(this); 1588 setPrevAffiliate(taskToAffiliateWith); 1589 setNextAffiliate(null); 1590 } 1591 1592 /** Returns the intent for the root activity for this task */ getBaseIntent()1593 Intent getBaseIntent() { 1594 if (intent != null) return intent; 1595 if (affinityIntent != null) return affinityIntent; 1596 // Probably a task that contains other tasks, so return the intent for the top task? 1597 final Task topTask = getTopMostTask(); 1598 return (topTask != this && topTask != null) ? topTask.getBaseIntent() : null; 1599 } 1600 1601 /** Returns the first non-finishing activity from the bottom. */ getRootActivity()1602 ActivityRecord getRootActivity() { 1603 // TODO: Figure out why we historical ignore relinquish identity for this case... 1604 return getRootActivity(true /*ignoreRelinquishIdentity*/, false /*setToBottomIfNone*/); 1605 } 1606 getRootActivity(boolean setToBottomIfNone)1607 ActivityRecord getRootActivity(boolean setToBottomIfNone) { 1608 return getRootActivity(false /*ignoreRelinquishIdentity*/, setToBottomIfNone); 1609 } 1610 getRootActivity(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone)1611 ActivityRecord getRootActivity(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) { 1612 return mFindRootHelper.findRoot(ignoreRelinquishIdentity, setToBottomIfNone); 1613 } 1614 getTopNonFinishingActivity()1615 ActivityRecord getTopNonFinishingActivity() { 1616 return getTopNonFinishingActivity(true /* includeOverlays */); 1617 } 1618 getTopNonFinishingActivity(boolean includeOverlays)1619 ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) { 1620 return getTopActivity(false /*includeFinishing*/, includeOverlays); 1621 } 1622 topRunningActivityLocked()1623 ActivityRecord topRunningActivityLocked() { 1624 if (getParent() == null) { 1625 return null; 1626 } 1627 return getActivity(ActivityRecord::canBeTopRunning); 1628 } 1629 1630 /** 1631 * Return true if any activities in this task belongs to input uid. 1632 */ isUidPresent(int uid)1633 boolean isUidPresent(int uid) { 1634 final PooledPredicate p = PooledLambda.obtainPredicate( 1635 ActivityRecord::isUid, PooledLambda.__(ActivityRecord.class), uid); 1636 final boolean isUidPresent = getActivity(p) != null; 1637 p.recycle(); 1638 return isUidPresent; 1639 } 1640 topActivityContainsStartingWindow()1641 ActivityRecord topActivityContainsStartingWindow() { 1642 if (getParent() == null) { 1643 return null; 1644 } 1645 return getActivity((r) -> r.getWindow(window -> 1646 window.getBaseType() == TYPE_APPLICATION_STARTING) != null); 1647 } 1648 topActivityWithStartingWindow()1649 ActivityRecord topActivityWithStartingWindow() { 1650 if (getParent() == null) { 1651 return null; 1652 } 1653 return getActivity((r) -> r.mStartingWindowState == STARTING_WINDOW_SHOWN 1654 && r.okToShowLocked()); 1655 } 1656 1657 /** 1658 * Return the number of running activities, and the number of non-finishing/initializing 1659 * activities in the provided {@param reportOut} respectively. 1660 */ getNumRunningActivities(TaskActivitiesReport reportOut)1661 private void getNumRunningActivities(TaskActivitiesReport reportOut) { 1662 reportOut.reset(); 1663 forAllActivities(reportOut); 1664 } 1665 1666 /** 1667 * Reorder the history task so that the passed activity is brought to the front. 1668 */ moveActivityToFrontLocked(ActivityRecord newTop)1669 final void moveActivityToFrontLocked(ActivityRecord newTop) { 1670 ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing and adding activity %s to root task at top " 1671 + "callers=%s", newTop, Debug.getCallers(4)); 1672 1673 positionChildAtTop(newTop); 1674 updateEffectiveIntent(); 1675 } 1676 1677 @Override getActivityType()1678 public int getActivityType() { 1679 final int applicationType = super.getActivityType(); 1680 if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) { 1681 return applicationType; 1682 } 1683 return getTopChild().getActivityType(); 1684 } 1685 1686 @Override addChild(WindowContainer child, int index)1687 void addChild(WindowContainer child, int index) { 1688 // If this task had any child before we added this one. 1689 boolean hadChild = hasChild(); 1690 // getActivityType() looks at the top child, so we need to read the type before adding 1691 // a new child in case the new child is on top and UNDEFINED. 1692 final int activityType = getActivityType(); 1693 1694 index = getAdjustedChildPosition(child, index); 1695 super.addChild(child, index); 1696 1697 ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this); 1698 1699 // A rootable task that is now being added to be the child of an organized task. Making 1700 // sure the root task references is keep updated. 1701 if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) { 1702 getDisplayArea().addRootTaskReferenceIfNeeded((Task) child); 1703 } 1704 1705 // Make sure the list of display UID allowlists is updated 1706 // now that this record is in a new task. 1707 mRootWindowContainer.updateUIDsPresentOnDisplay(); 1708 1709 final ActivityRecord r = child.asActivityRecord(); 1710 if (r == null) return; 1711 1712 r.inHistory = true; 1713 1714 // Only set this based on the first activity 1715 if (!hadChild) { 1716 if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) { 1717 // Normally non-standard activity type for the activity record will be set when the 1718 // object is created, however we delay setting the standard application type until 1719 // this point so that the task can set the type for additional activities added in 1720 // the else condition below. 1721 r.setActivityType(ACTIVITY_TYPE_STANDARD); 1722 } 1723 setActivityType(r.getActivityType()); 1724 isPersistable = r.isPersistable(); 1725 mCallingUid = r.launchedFromUid; 1726 mCallingPackage = r.launchedFromPackage; 1727 mCallingFeatureId = r.launchedFromFeatureId; 1728 // Clamp to [1, max]. 1729 maxRecents = Math.min(Math.max(r.info.maxRecents, 1), 1730 ActivityTaskManager.getMaxAppRecentsLimitStatic()); 1731 } else { 1732 // Otherwise make all added activities match this one. 1733 r.setActivityType(activityType); 1734 } 1735 1736 updateEffectiveIntent(); 1737 } 1738 addChild(ActivityRecord r)1739 void addChild(ActivityRecord r) { 1740 addChild(r, Integer.MAX_VALUE /* add on top */); 1741 } 1742 1743 @Override removeChild(WindowContainer child)1744 void removeChild(WindowContainer child) { 1745 removeChild(child, "removeChild"); 1746 } 1747 removeChild(WindowContainer r, String reason)1748 void removeChild(WindowContainer r, String reason) { 1749 // A rootable child task that is now being removed from an organized task. Making sure 1750 // the root task references is keep updated. 1751 if (mCreatedByOrganizer && r.asTask() != null) { 1752 getDisplayArea().removeRootTaskReferenceIfNeeded((Task) r); 1753 } 1754 if (!mChildren.contains(r)) { 1755 Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this); 1756 return; 1757 } 1758 1759 if (DEBUG_TASK_MOVEMENT) { 1760 Slog.d(TAG_WM, "removeChild: child=" + r + " reason=" + reason); 1761 } 1762 super.removeChild(r); 1763 1764 if (inPinnedWindowingMode()) { 1765 // We normally notify listeners of task stack changes on pause, however root pinned task 1766 // activities are normally in the paused state so no notification will be sent there 1767 // before the activity is removed. We send it here so instead. 1768 mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged(); 1769 } 1770 1771 if (hasChild()) { 1772 updateEffectiveIntent(); 1773 1774 // The following block can be executed multiple times if there is more than one overlay. 1775 // {@link ActivityTaskSupervisor#removeTaskByIdLocked} handles this by reverse lookup 1776 // of the task by id and exiting early if not found. 1777 if (onlyHasTaskOverlayActivities(true /*includeFinishing*/)) { 1778 // When destroying a task, tell the supervisor to remove it so that any activity it 1779 // has can be cleaned up correctly. This is currently the only place where we remove 1780 // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays 1781 // state into removeChild(), we just clear the task here before the other residual 1782 // work. 1783 // TODO: If the callers to removeChild() changes such that we have multiple places 1784 // where we are destroying the task, move this back into removeChild() 1785 mTaskSupervisor.removeTask(this, false /* killProcess */, 1786 !REMOVE_FROM_RECENTS, reason); 1787 } 1788 } else if (!mReuseTask && !mCreatedByOrganizer) { 1789 // Remove entire task if it doesn't have any activity left and it isn't marked for reuse 1790 // or created by task organizer. 1791 if (!isRootTask()) { 1792 getRootTask().removeChild(this, reason); 1793 } 1794 EventLogTags.writeWmTaskRemoved(mTaskId, 1795 "removeChild:" + reason + " last r=" + r + " in t=" + this); 1796 removeIfPossible(reason); 1797 } 1798 } 1799 1800 /** 1801 * @return whether or not there are ONLY task overlay activities in the task. 1802 * If {@param includeFinishing} is set, then don't ignore finishing activities in the 1803 * check. If there are no task overlay activities, this call returns false. 1804 */ onlyHasTaskOverlayActivities(boolean includeFinishing)1805 boolean onlyHasTaskOverlayActivities(boolean includeFinishing) { 1806 int count = 0; 1807 for (int i = getChildCount() - 1; i >= 0; i--) { 1808 final ActivityRecord r = getChildAt(i).asActivityRecord(); 1809 if (r == null) { 1810 // Has a child that is other than Activity. 1811 return false; 1812 } 1813 if (!includeFinishing && r.finishing) { 1814 continue; 1815 } 1816 if (!r.isTaskOverlay()) { 1817 return false; 1818 } 1819 count++; 1820 } 1821 return count > 0; 1822 } 1823 autoRemoveFromRecents()1824 private boolean autoRemoveFromRecents() { 1825 // We will automatically remove the task either if it has explicitly asked for 1826 // this, or it is empty and has never contained an activity that got shown to 1827 // the user. 1828 return autoRemoveRecents || (!hasChild() && !getHasBeenVisible()); 1829 } 1830 clearPinnedTaskIfNeed()1831 private void clearPinnedTaskIfNeed() { 1832 // The original task is to be removed, try remove also the pinned task. 1833 if (mChildPipActivity != null && mChildPipActivity.getTask() != null) { 1834 mTaskSupervisor.removeRootTask(mChildPipActivity.getTask()); 1835 } 1836 } 1837 1838 /** Completely remove all activities associated with an existing task. */ performClearTask(String reason)1839 void performClearTask(String reason) { 1840 clearPinnedTaskIfNeed(); 1841 // Broken down into to cases to avoid object create due to capturing mStack. 1842 if (getRootTask() == null) { 1843 forAllActivities((r) -> { 1844 if (r.finishing) return; 1845 // Task was restored from persistent storage. 1846 r.takeFromHistory(); 1847 removeChild(r, reason); 1848 }); 1849 } else { 1850 forAllActivities((r) -> { 1851 if (r.finishing) return; 1852 // TODO: figure-out how to avoid object creation due to capture of reason variable. 1853 r.finishIfPossible(Activity.RESULT_CANCELED, 1854 null /* resultData */, null /* resultGrants */, reason, false /* oomAdj */); 1855 }); 1856 } 1857 } 1858 1859 /** 1860 * Completely remove all activities associated with an existing task. 1861 */ performClearTaskLocked()1862 void performClearTaskLocked() { 1863 mReuseTask = true; 1864 mTaskSupervisor.beginDeferResume(); 1865 try { 1866 performClearTask("clear-task-all"); 1867 } finally { 1868 mTaskSupervisor.endDeferResume(); 1869 mReuseTask = false; 1870 } 1871 } 1872 performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags)1873 ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) { 1874 mReuseTask = true; 1875 mTaskSupervisor.beginDeferResume(); 1876 final ActivityRecord result; 1877 try { 1878 result = performClearTaskLocked(newR, launchFlags); 1879 } finally { 1880 mTaskSupervisor.endDeferResume(); 1881 mReuseTask = false; 1882 } 1883 return result; 1884 } 1885 1886 /** 1887 * Perform clear operation as requested by 1888 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the 1889 * root task to the given task, then look for 1890 * an instance of that activity in the root task and, if found, finish all 1891 * activities on top of it and return the instance. 1892 * 1893 * @param newR Description of the new activity being started. 1894 * @return Returns the old activity that should be continued to be used, 1895 * or {@code null} if none was found. 1896 */ performClearTaskLocked(ActivityRecord newR, int launchFlags)1897 private ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) { 1898 final ActivityRecord r = findActivityInHistory(newR.mActivityComponent); 1899 if (r == null) return null; 1900 1901 final PooledFunction f = PooledLambda.obtainFunction(Task::finishActivityAbove, 1902 PooledLambda.__(ActivityRecord.class), r); 1903 forAllActivities(f); 1904 f.recycle(); 1905 1906 // Finally, if this is a normal launch mode (that is, not expecting onNewIntent()), then we 1907 // will finish the current instance of the activity so a new fresh one can be started. 1908 if (r.launchMode == ActivityInfo.LAUNCH_MULTIPLE 1909 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0 1910 && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) { 1911 if (!r.finishing) { 1912 r.finishIfPossible("clear-task-top", false /* oomAdj */); 1913 return null; 1914 } 1915 } 1916 1917 return r; 1918 } 1919 finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity)1920 private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity) { 1921 // Stop operation once we reach the boundary activity. 1922 if (r == boundaryActivity) return true; 1923 1924 if (!r.finishing) { 1925 final ActivityOptions opts = r.getOptions(); 1926 if (opts != null) { 1927 r.clearOptionsAnimation(); 1928 // TODO: Why is this updating the boundary activity vs. the current activity??? 1929 boundaryActivity.updateOptionsLocked(opts); 1930 } 1931 r.finishIfPossible("clear-task-stack", false /* oomAdj */); 1932 } 1933 1934 return false; 1935 } 1936 lockTaskAuthToString()1937 String lockTaskAuthToString() { 1938 switch (mLockTaskAuth) { 1939 case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK"; 1940 case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE"; 1941 case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE"; 1942 case LOCK_TASK_AUTH_ALLOWLISTED: return "LOCK_TASK_AUTH_ALLOWLISTED"; 1943 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV"; 1944 default: return "unknown=" + mLockTaskAuth; 1945 } 1946 } 1947 setLockTaskAuth()1948 void setLockTaskAuth() { 1949 setLockTaskAuth(getRootActivity()); 1950 } 1951 setLockTaskAuth(@ullable ActivityRecord r)1952 private void setLockTaskAuth(@Nullable ActivityRecord r) { 1953 mLockTaskAuth = mAtmService.getLockTaskController().getLockTaskAuth(r, this); 1954 ProtoLog.d(WM_DEBUG_LOCKTASK, "setLockTaskAuth: task=%s mLockTaskAuth=%s", this, 1955 lockTaskAuthToString()); 1956 } 1957 1958 @Override supportsSplitScreenWindowingMode()1959 public boolean supportsSplitScreenWindowingMode() { 1960 return supportsSplitScreenWindowingModeInDisplayArea(getDisplayArea()); 1961 } 1962 supportsSplitScreenWindowingModeInDisplayArea(@ullable TaskDisplayArea tda)1963 boolean supportsSplitScreenWindowingModeInDisplayArea(@Nullable TaskDisplayArea tda) { 1964 final Task topTask = getTopMostTask(); 1965 return super.supportsSplitScreenWindowingMode() 1966 && (topTask == null || topTask.supportsSplitScreenWindowingModeInner(tda)); 1967 } 1968 supportsSplitScreenWindowingModeInner(@ullable TaskDisplayArea tda)1969 private boolean supportsSplitScreenWindowingModeInner(@Nullable TaskDisplayArea tda) { 1970 return super.supportsSplitScreenWindowingMode() 1971 && mAtmService.mSupportsSplitScreenMultiWindow 1972 && supportsMultiWindowInDisplayArea(tda); 1973 } 1974 supportsFreeform()1975 boolean supportsFreeform() { 1976 return supportsFreeformInDisplayArea(getDisplayArea()); 1977 } 1978 1979 /** 1980 * @return whether this task supports freeform multi-window if it is in the given 1981 * {@link TaskDisplayArea}. 1982 */ supportsFreeformInDisplayArea(@ullable TaskDisplayArea tda)1983 boolean supportsFreeformInDisplayArea(@Nullable TaskDisplayArea tda) { 1984 return mAtmService.mSupportsFreeformWindowManagement 1985 && supportsMultiWindowInDisplayArea(tda); 1986 } 1987 supportsMultiWindow()1988 boolean supportsMultiWindow() { 1989 return supportsMultiWindowInDisplayArea(getDisplayArea()); 1990 } 1991 1992 /** 1993 * @return whether this task supports multi-window if it is in the given 1994 * {@link TaskDisplayArea}. 1995 */ supportsMultiWindowInDisplayArea(@ullable TaskDisplayArea tda)1996 boolean supportsMultiWindowInDisplayArea(@Nullable TaskDisplayArea tda) { 1997 if (!mAtmService.mSupportsMultiWindow) { 1998 return false; 1999 } 2000 if (tda == null) { 2001 Slog.w(TAG_TASKS, "Can't find TaskDisplayArea to determine support for multi" 2002 + " window. Task id=" + mTaskId + " attached=" + isAttached()); 2003 return false; 2004 } 2005 2006 if (!isResizeable() && !tda.supportsNonResizableMultiWindow()) { 2007 // Not support non-resizable in multi window. 2008 return false; 2009 } 2010 2011 return tda.supportsActivityMinWidthHeightMultiWindow(mMinWidth, mMinHeight); 2012 } 2013 2014 /** 2015 * Check whether this task can be launched on the specified display. 2016 * 2017 * @param displayId Target display id. 2018 * @return {@code true} if either it is the default display or this activity can be put on a 2019 * secondary display. 2020 */ canBeLaunchedOnDisplay(int displayId)2021 boolean canBeLaunchedOnDisplay(int displayId) { 2022 return mTaskSupervisor.canPlaceEntityOnDisplay(displayId, 2023 -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */); 2024 } 2025 2026 /** 2027 * Check that a given bounds matches the application requested orientation. 2028 * 2029 * @param bounds The bounds to be tested. 2030 * @return True if the requested bounds are okay for a resizing request. 2031 */ canResizeToBounds(Rect bounds)2032 private boolean canResizeToBounds(Rect bounds) { 2033 if (bounds == null || !inFreeformWindowingMode()) { 2034 // Note: If not on the freeform workspace, we ignore the bounds. 2035 return true; 2036 } 2037 final boolean landscape = bounds.width() > bounds.height(); 2038 final Rect configBounds = getRequestedOverrideBounds(); 2039 if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) { 2040 return configBounds.isEmpty() 2041 || landscape == (configBounds.width() > configBounds.height()); 2042 } 2043 return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape) 2044 && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape); 2045 } 2046 2047 /** 2048 * @return {@code true} if the task is being cleared for the purposes of being reused. 2049 */ isClearingToReuseTask()2050 boolean isClearingToReuseTask() { 2051 return mReuseTask; 2052 } 2053 2054 /** 2055 * Find the activity in the history task within the given task. Returns 2056 * the index within the history at which it's found, or < 0 if not found. 2057 */ findActivityInHistory(ComponentName component)2058 ActivityRecord findActivityInHistory(ComponentName component) { 2059 final PooledPredicate p = PooledLambda.obtainPredicate(Task::matchesActivityInHistory, 2060 PooledLambda.__(ActivityRecord.class), component); 2061 final ActivityRecord r = getActivity(p); 2062 p.recycle(); 2063 return r; 2064 } 2065 matchesActivityInHistory( ActivityRecord r, ComponentName activityComponent)2066 private static boolean matchesActivityInHistory( 2067 ActivityRecord r, ComponentName activityComponent) { 2068 return !r.finishing && r.mActivityComponent.equals(activityComponent); 2069 } 2070 2071 /** Updates the last task description values. */ updateTaskDescription()2072 void updateTaskDescription() { 2073 final ActivityRecord root = getRootActivity(true); 2074 if (root == null) return; 2075 2076 final TaskDescription taskDescription = new TaskDescription(); 2077 final PooledFunction f = PooledLambda.obtainFunction( 2078 Task::setTaskDescriptionFromActivityAboveRoot, 2079 PooledLambda.__(ActivityRecord.class), root, taskDescription); 2080 forAllActivities(f); 2081 f.recycle(); 2082 taskDescription.setResizeMode(mResizeMode); 2083 taskDescription.setMinWidth(mMinWidth); 2084 taskDescription.setMinHeight(mMinHeight); 2085 setTaskDescription(taskDescription); 2086 mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged( 2087 getTaskInfo()); 2088 2089 final WindowContainer parent = getParent(); 2090 if (parent != null) { 2091 final Task t = parent.asTask(); 2092 if (t != null) { 2093 t.updateTaskDescription(); 2094 } 2095 } 2096 2097 dispatchTaskInfoChangedIfNeeded(false /* force */); 2098 } 2099 setTaskDescriptionFromActivityAboveRoot( ActivityRecord r, ActivityRecord root, TaskDescription td)2100 private static boolean setTaskDescriptionFromActivityAboveRoot( 2101 ActivityRecord r, ActivityRecord root, TaskDescription td) { 2102 if (!r.isTaskOverlay() && r.taskDescription != null) { 2103 final TaskDescription atd = r.taskDescription; 2104 if (td.getLabel() == null) { 2105 td.setLabel(atd.getLabel()); 2106 } 2107 if (td.getRawIcon() == null) { 2108 td.setIcon(atd.getRawIcon()); 2109 } 2110 if (td.getIconFilename() == null) { 2111 td.setIconFilename(atd.getIconFilename()); 2112 } 2113 if (td.getPrimaryColor() == 0) { 2114 td.setPrimaryColor(atd.getPrimaryColor()); 2115 } 2116 if (td.getBackgroundColor() == 0) { 2117 td.setBackgroundColor(atd.getBackgroundColor()); 2118 } 2119 if (td.getStatusBarColor() == 0) { 2120 td.setStatusBarColor(atd.getStatusBarColor()); 2121 td.setEnsureStatusBarContrastWhenTransparent( 2122 atd.getEnsureStatusBarContrastWhenTransparent()); 2123 } 2124 if (td.getNavigationBarColor() == 0) { 2125 td.setNavigationBarColor(atd.getNavigationBarColor()); 2126 td.setEnsureNavigationBarContrastWhenTransparent( 2127 atd.getEnsureNavigationBarContrastWhenTransparent()); 2128 } 2129 if (td.getBackgroundColorFloating() == 0) { 2130 td.setBackgroundColorFloating(atd.getBackgroundColorFloating()); 2131 } 2132 } 2133 2134 // End search once we get to root. 2135 return r == root; 2136 } 2137 2138 // TODO (AM refactor): Invoke automatically when there is a change in children 2139 @VisibleForTesting updateEffectiveIntent()2140 void updateEffectiveIntent() { 2141 final ActivityRecord root = getRootActivity(true /*setToBottomIfNone*/); 2142 if (root != null) { 2143 setIntent(root); 2144 // Update the task description when the activities change 2145 updateTaskDescription(); 2146 } 2147 } 2148 adjustForMinimalTaskDimensions(@onNull Rect bounds, @NonNull Rect previousBounds, @NonNull Configuration parentConfig)2149 void adjustForMinimalTaskDimensions(@NonNull Rect bounds, @NonNull Rect previousBounds, 2150 @NonNull Configuration parentConfig) { 2151 int minWidth = mMinWidth; 2152 int minHeight = mMinHeight; 2153 // If the task has no requested minimal size, we'd like to enforce a minimal size 2154 // so that the user can not render the task too small to manipulate. We don't need 2155 // to do this for the root pinned task as the bounds are controlled by the system. 2156 if (!inPinnedWindowingMode()) { 2157 final int defaultMinSizeDp = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp; 2158 final float density = (float) parentConfig.densityDpi / DisplayMetrics.DENSITY_DEFAULT; 2159 final int defaultMinSize = (int) (defaultMinSizeDp * density); 2160 2161 if (minWidth == INVALID_MIN_SIZE) { 2162 minWidth = defaultMinSize; 2163 } 2164 if (minHeight == INVALID_MIN_SIZE) { 2165 minHeight = defaultMinSize; 2166 } 2167 } 2168 if (bounds.isEmpty()) { 2169 // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they 2170 // do, we can just skip. 2171 final Rect parentBounds = parentConfig.windowConfiguration.getBounds(); 2172 if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) { 2173 return; 2174 } 2175 bounds.set(parentBounds); 2176 } 2177 final boolean adjustWidth = minWidth > bounds.width(); 2178 final boolean adjustHeight = minHeight > bounds.height(); 2179 if (!(adjustWidth || adjustHeight)) { 2180 return; 2181 } 2182 2183 if (adjustWidth) { 2184 if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) { 2185 bounds.left = bounds.right - minWidth; 2186 } else { 2187 // Either left bounds match, or neither match, or the previous bounds were 2188 // fullscreen and we default to keeping left. 2189 bounds.right = bounds.left + minWidth; 2190 } 2191 } 2192 if (adjustHeight) { 2193 if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) { 2194 bounds.top = bounds.bottom - minHeight; 2195 } else { 2196 // Either top bounds match, or neither match, or the previous bounds were 2197 // fullscreen and we default to keeping top. 2198 bounds.bottom = bounds.top + minHeight; 2199 } 2200 } 2201 } 2202 setLastNonFullscreenBounds(Rect bounds)2203 void setLastNonFullscreenBounds(Rect bounds) { 2204 if (mLastNonFullscreenBounds == null) { 2205 mLastNonFullscreenBounds = new Rect(bounds); 2206 } else { 2207 mLastNonFullscreenBounds.set(bounds); 2208 } 2209 } 2210 2211 /** 2212 * This should be called when an child activity changes state. This should only 2213 * be called from 2214 * {@link ActivityRecord#setState(ActivityState, String)} . 2215 * @param record The {@link ActivityRecord} whose state has changed. 2216 * @param state The new state. 2217 * @param reason The reason for the change. 2218 */ onActivityStateChanged(ActivityRecord record, ActivityState state, String reason)2219 void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) { 2220 warnForNonLeafTask("onActivityStateChanged"); 2221 if (record == mResumedActivity && state != RESUMED) { 2222 setResumedActivity(null, reason + " - onActivityStateChanged"); 2223 } 2224 2225 if (state == RESUMED) { 2226 if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) { 2227 Slog.v(TAG_ROOT_TASK, "set resumed activity to:" + record + " reason:" + reason); 2228 } 2229 setResumedActivity(record, reason + " - onActivityStateChanged"); 2230 if (record == mRootWindowContainer.getTopResumedActivity()) { 2231 mAtmService.setResumedActivityUncheckLocked(record, reason); 2232 } 2233 mTaskSupervisor.mRecentTasks.add(record.getTask()); 2234 } 2235 } 2236 onConfigurationChangedInner(Configuration newParentConfig)2237 private void onConfigurationChangedInner(Configuration newParentConfig) { 2238 // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so 2239 // restore the last recorded non-fullscreen bounds. 2240 final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds(); 2241 boolean nextPersistTaskBounds = 2242 getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds(); 2243 if (getRequestedOverrideWindowingMode() == WINDOWING_MODE_UNDEFINED) { 2244 nextPersistTaskBounds = newParentConfig.windowConfiguration.persistTaskBounds(); 2245 } 2246 if (!prevPersistTaskBounds && nextPersistTaskBounds 2247 && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) { 2248 // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop. 2249 getRequestedOverrideConfiguration().windowConfiguration 2250 .setBounds(mLastNonFullscreenBounds); 2251 } 2252 2253 final int prevWinMode = getWindowingMode(); 2254 mTmpPrevBounds.set(getBounds()); 2255 final boolean wasInMultiWindowMode = inMultiWindowMode(); 2256 final boolean wasInPictureInPicture = inPinnedWindowingMode(); 2257 super.onConfigurationChanged(newParentConfig); 2258 // Only need to update surface size here since the super method will handle updating 2259 // surface position. 2260 updateSurfaceSize(getSyncTransaction()); 2261 2262 final boolean pipChanging = wasInPictureInPicture != inPinnedWindowingMode(); 2263 if (pipChanging) { 2264 mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, getRootTask()); 2265 } else if (wasInMultiWindowMode != inMultiWindowMode()) { 2266 mTaskSupervisor.scheduleUpdateMultiWindowMode(this); 2267 } 2268 2269 final int newWinMode = getWindowingMode(); 2270 if ((prevWinMode != newWinMode) && (mDisplayContent != null) 2271 && shouldStartChangeTransition(prevWinMode, newWinMode)) { 2272 initializeChangeTransition(mTmpPrevBounds); 2273 } 2274 2275 // If the configuration supports persistent bounds (eg. Freeform), keep track of the 2276 // current (non-fullscreen) bounds for persistence. 2277 if (getWindowConfiguration().persistTaskBounds()) { 2278 final Rect currentBounds = getRequestedOverrideBounds(); 2279 if (!currentBounds.isEmpty()) { 2280 setLastNonFullscreenBounds(currentBounds); 2281 } 2282 } 2283 2284 if (pipChanging) { 2285 // If the top activity is using fixed rotation, it should be changing from PiP to 2286 // fullscreen with display orientation change. Do not notify fullscreen task organizer 2287 // because the restoration of task surface and the transformation of activity surface 2288 // need to be done synchronously. 2289 final ActivityRecord r = topRunningActivity(); 2290 if (r != null && mDisplayContent.isFixedRotationLaunchingApp(r)) { 2291 mForceNotOrganized = true; 2292 } 2293 } else { 2294 // If the display orientation change is done, let the corresponding task organizer take 2295 // back the control of this task. 2296 mForceNotOrganized = false; 2297 } 2298 2299 saveLaunchingStateIfNeeded(); 2300 final boolean taskOrgChanged = updateTaskOrganizerState(false /* forceUpdate */); 2301 if (taskOrgChanged) { 2302 updateSurfacePosition(getSyncTransaction()); 2303 if (!isOrganized()) { 2304 // Surface-size update was skipped before (since internally it no-ops if 2305 // isOrganized() is true); however, now that this is not organized, the surface 2306 // size needs to be updated by WM. 2307 updateSurfaceSize(getSyncTransaction()); 2308 } 2309 } 2310 // If the task organizer has changed, then it will already be receiving taskAppeared with 2311 // the latest task-info thus the task-info won't have changed. 2312 if (!taskOrgChanged) { 2313 dispatchTaskInfoChangedIfNeeded(false /* force */); 2314 } 2315 } 2316 2317 @Override onConfigurationChanged(Configuration newParentConfig)2318 public void onConfigurationChanged(Configuration newParentConfig) { 2319 if (mDisplayContent != null 2320 && mDisplayContent.mPinnedTaskController.isFreezingTaskConfig(this)) { 2321 // It happens when animating from fullscreen to PiP with orientation change. Because 2322 // the activity in this pinned task is in fullscreen windowing mode (see 2323 // RootWindowContainer#moveActivityToPinnedRootTask) and the activity will be set to 2324 // pinned mode after the animation is done, the configuration change by orientation 2325 // change is just an intermediate state that should be ignored to avoid flickering. 2326 return; 2327 } 2328 // Calling Task#onConfigurationChanged() for leaf task since the ops in this method are 2329 // particularly for root tasks, like preventing bounds changes when inheriting certain 2330 // windowing mode. 2331 if (!isRootTask()) { 2332 onConfigurationChangedInner(newParentConfig); 2333 return; 2334 } 2335 2336 final int prevWindowingMode = getWindowingMode(); 2337 final boolean prevIsAlwaysOnTop = isAlwaysOnTop(); 2338 final int prevRotation = getWindowConfiguration().getRotation(); 2339 final Rect newBounds = mTmpRect; 2340 // Initialize the new bounds by previous bounds as the input and output for calculating 2341 // override bounds in pinned (pip) or split-screen mode. 2342 getBounds(newBounds); 2343 2344 onConfigurationChangedInner(newParentConfig); 2345 2346 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 2347 if (taskDisplayArea == null) { 2348 return; 2349 } 2350 2351 if (prevWindowingMode != getWindowingMode()) { 2352 taskDisplayArea.onRootTaskWindowingModeChanged(this); 2353 } 2354 2355 if (mDisplayContent == null) { 2356 return; 2357 } 2358 2359 // Use override windowing mode to prevent extra bounds changes if inheriting the mode. 2360 final int overrideWindowingMode = getRequestedOverrideWindowingMode(); 2361 if (overrideWindowingMode != WINDOWING_MODE_PINNED 2362 && !getRequestedOverrideBounds().isEmpty()) { 2363 // If the parent (display) has rotated, rotate our bounds to best-fit where their 2364 // bounds were on the pre-rotated display. 2365 final int newRotation = getWindowConfiguration().getRotation(); 2366 final boolean rotationChanged = prevRotation != newRotation; 2367 if (rotationChanged) { 2368 mDisplayContent.rotateBounds(prevRotation, newRotation, newBounds); 2369 setBounds(newBounds); 2370 } 2371 } 2372 2373 if (prevIsAlwaysOnTop != isAlwaysOnTop()) { 2374 // Since always on top is only on when the root task is freeform or pinned, the state 2375 // can be toggled when the windowing mode changes. We must make sure the root task is 2376 // placed properly when always on top state changes. 2377 taskDisplayArea.positionChildAt(POSITION_TOP, this, false /* includingParents */); 2378 } 2379 } 2380 2381 /** 2382 * Initializes a change transition. See {@link SurfaceFreezer} for more information. 2383 */ initializeChangeTransition(Rect startBounds)2384 private void initializeChangeTransition(Rect startBounds) { 2385 mDisplayContent.prepareAppTransition(TRANSIT_CHANGE); 2386 mDisplayContent.mChangingContainers.add(this); 2387 2388 mSurfaceFreezer.freeze(getPendingTransaction(), startBounds); 2389 } 2390 shouldStartChangeTransition(int prevWinMode, int newWinMode)2391 private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) { 2392 if (mWmService.mDisableTransitionAnimation 2393 || !isVisible() 2394 || getSurfaceControl() == null 2395 || !isLeafTask()) { 2396 return false; 2397 } 2398 // Only do an animation into and out-of freeform mode for now. Other mode 2399 // transition animations are currently handled by system-ui. 2400 return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM); 2401 } 2402 2403 @Override migrateToNewSurfaceControl(SurfaceControl.Transaction t)2404 void migrateToNewSurfaceControl(SurfaceControl.Transaction t) { 2405 super.migrateToNewSurfaceControl(t); 2406 mLastSurfaceSize.x = 0; 2407 mLastSurfaceSize.y = 0; 2408 updateSurfaceSize(t); 2409 } 2410 updateSurfaceSize(SurfaceControl.Transaction transaction)2411 void updateSurfaceSize(SurfaceControl.Transaction transaction) { 2412 if (mSurfaceControl == null || isOrganized()) { 2413 return; 2414 } 2415 2416 // Apply crop to root tasks only and clear the crops of the descendant tasks. 2417 int width = 0; 2418 int height = 0; 2419 if (isRootTask()) { 2420 final Rect taskBounds = getBounds(); 2421 width = taskBounds.width(); 2422 height = taskBounds.height(); 2423 2424 final int outset = getTaskOutset(); 2425 width += 2 * outset; 2426 height += 2 * outset; 2427 } 2428 if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) { 2429 return; 2430 } 2431 transaction.setWindowCrop(mSurfaceControl, width, height); 2432 mLastSurfaceSize.set(width, height); 2433 } 2434 2435 /** 2436 * Calculate an amount by which to expand the task bounds in each direction. 2437 * Used to make room for shadows in the pinned windowing mode. 2438 */ getTaskOutset()2439 int getTaskOutset() { 2440 // If we are drawing shadows on the task then don't outset the root task. 2441 if (mWmService.mRenderShadowsInCompositor) { 2442 return 0; 2443 } 2444 DisplayContent displayContent = getDisplayContent(); 2445 if (inPinnedWindowingMode() && displayContent != null) { 2446 final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics(); 2447 2448 // We multiply by two to match the client logic for converting view elevation 2449 // to insets, as in {@link WindowManager.LayoutParams#setSurfaceInsets} 2450 return (int) Math.ceil( 2451 mWmService.dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP, displayMetrics) 2452 * 2); 2453 } 2454 return 0; 2455 } 2456 2457 @VisibleForTesting getLastSurfaceSize()2458 Point getLastSurfaceSize() { 2459 return mLastSurfaceSize; 2460 } 2461 2462 @VisibleForTesting isInChangeTransition()2463 boolean isInChangeTransition() { 2464 return mSurfaceFreezer.hasLeash() || AppTransition.isChangeTransitOld(mTransit); 2465 } 2466 2467 @Override getFreezeSnapshotTarget()2468 public SurfaceControl getFreezeSnapshotTarget() { 2469 if (!mDisplayContent.mAppTransition.containsTransitRequest(TRANSIT_CHANGE)) { 2470 return null; 2471 } 2472 // Skip creating snapshot if this transition is controlled by a remote animator which 2473 // doesn't need it. 2474 final ArraySet<Integer> activityTypes = new ArraySet<>(); 2475 activityTypes.add(getActivityType()); 2476 final RemoteAnimationAdapter adapter = 2477 mDisplayContent.mAppTransitionController.getRemoteAnimationOverride( 2478 this, TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE, activityTypes); 2479 if (adapter != null && !adapter.getChangeNeedsSnapshot()) { 2480 return null; 2481 } 2482 return getSurfaceControl(); 2483 } 2484 2485 @Override writeIdentifierToProto(ProtoOutputStream proto, long fieldId)2486 void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { 2487 final long token = proto.start(fieldId); 2488 proto.write(HASH_CODE, System.identityHashCode(this)); 2489 proto.write(USER_ID, mUserId); 2490 proto.write(TITLE, intent != null && intent.getComponent() != null 2491 ? intent.getComponent().flattenToShortString() : "Task"); 2492 proto.end(token); 2493 } 2494 2495 /** 2496 * Saves launching state if necessary so that we can launch the activity to its latest state. 2497 */ saveLaunchingStateIfNeeded()2498 private void saveLaunchingStateIfNeeded() { 2499 saveLaunchingStateIfNeeded(getDisplayContent()); 2500 } 2501 saveLaunchingStateIfNeeded(DisplayContent display)2502 private void saveLaunchingStateIfNeeded(DisplayContent display) { 2503 if (!isLeafTask()) { 2504 return; 2505 } 2506 2507 if (!getHasBeenVisible()) { 2508 // Not ever visible to user. 2509 return; 2510 } 2511 2512 final int windowingMode = getWindowingMode(); 2513 if (windowingMode != WINDOWING_MODE_FULLSCREEN 2514 && windowingMode != WINDOWING_MODE_FREEFORM) { 2515 return; 2516 } 2517 2518 // Don't persist state if display isn't in freeform mode. Then the task will be launched 2519 // back to its last state in a freeform display when it's launched in a freeform display 2520 // next time. 2521 if (getWindowConfiguration().getDisplayWindowingMode() != WINDOWING_MODE_FREEFORM) { 2522 return; 2523 } 2524 2525 // Saves the new state so that we can launch the activity at the same location. 2526 mTaskSupervisor.mLaunchParamsPersister.saveTask(this, display); 2527 } 2528 2529 /** 2530 * Adjust bounds to stay within root task bounds. 2531 * 2532 * Since bounds might be outside of root task bounds, this method tries to move the bounds in 2533 * a way that keep them unchanged, but be contained within the root task bounds. 2534 * 2535 * @param bounds Bounds to be adjusted. 2536 * @param rootTaskBounds Bounds within which the other bounds should remain. 2537 * @param overlapPxX The amount of px required to be visible in the X dimension. 2538 * @param overlapPxY The amount of px required to be visible in the Y dimension. 2539 */ fitWithinBounds(Rect bounds, Rect rootTaskBounds, int overlapPxX, int overlapPxY)2540 private static void fitWithinBounds(Rect bounds, Rect rootTaskBounds, int overlapPxX, 2541 int overlapPxY) { 2542 if (rootTaskBounds == null || rootTaskBounds.isEmpty() || rootTaskBounds.contains(bounds)) { 2543 return; 2544 } 2545 2546 // For each side of the parent (eg. left), check if the opposing side of the window (eg. 2547 // right) is at least overlap pixels away. If less, offset the window by that difference. 2548 int horizontalDiff = 0; 2549 // If window is smaller than overlap, use it's smallest dimension instead 2550 int overlapLR = Math.min(overlapPxX, bounds.width()); 2551 if (bounds.right < (rootTaskBounds.left + overlapLR)) { 2552 horizontalDiff = overlapLR - (bounds.right - rootTaskBounds.left); 2553 } else if (bounds.left > (rootTaskBounds.right - overlapLR)) { 2554 horizontalDiff = -(overlapLR - (rootTaskBounds.right - bounds.left)); 2555 } 2556 int verticalDiff = 0; 2557 int overlapTB = Math.min(overlapPxY, bounds.width()); 2558 if (bounds.bottom < (rootTaskBounds.top + overlapTB)) { 2559 verticalDiff = overlapTB - (bounds.bottom - rootTaskBounds.top); 2560 } else if (bounds.top > (rootTaskBounds.bottom - overlapTB)) { 2561 verticalDiff = -(overlapTB - (rootTaskBounds.bottom - bounds.top)); 2562 } 2563 bounds.offset(horizontalDiff, verticalDiff); 2564 } 2565 2566 /** 2567 * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than 2568 * intersectBounds on a side, then the respective side will not be intersected. 2569 * 2570 * The assumption is that if inOutBounds is initially larger than intersectBounds, then the 2571 * inset on that side is no-longer applicable. This scenario happens when a task's minimal 2572 * bounds are larger than the provided parent/display bounds. 2573 * 2574 * @param inOutBounds the bounds to intersect. 2575 * @param intersectBounds the bounds to intersect with. 2576 * @param intersectInsets insets to apply to intersectBounds before intersecting. 2577 */ intersectWithInsetsIfFits( Rect inOutBounds, Rect intersectBounds, Rect intersectInsets)2578 static void intersectWithInsetsIfFits( 2579 Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) { 2580 if (inOutBounds.right <= intersectBounds.right) { 2581 inOutBounds.right = 2582 Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right); 2583 } 2584 if (inOutBounds.bottom <= intersectBounds.bottom) { 2585 inOutBounds.bottom = 2586 Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom); 2587 } 2588 if (inOutBounds.left >= intersectBounds.left) { 2589 inOutBounds.left = 2590 Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left); 2591 } 2592 if (inOutBounds.top >= intersectBounds.top) { 2593 inOutBounds.top = 2594 Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top); 2595 } 2596 } 2597 2598 /** 2599 * Gets bounds with non-decor and stable insets applied respectively. 2600 * 2601 * If bounds overhangs the display, those edges will not get insets. See 2602 * {@link #intersectWithInsetsIfFits} 2603 * 2604 * @param outNonDecorBounds where to place bounds with non-decor insets applied. 2605 * @param outStableBounds where to place bounds with stable insets applied. 2606 * @param bounds the bounds to inset. 2607 */ calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, DisplayInfo displayInfo)2608 private void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, 2609 DisplayInfo displayInfo) { 2610 outNonDecorBounds.set(bounds); 2611 outStableBounds.set(bounds); 2612 final Task rootTask = getRootTask(); 2613 if (rootTask == null || rootTask.mDisplayContent == null) { 2614 return; 2615 } 2616 mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); 2617 2618 final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy(); 2619 policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth, 2620 displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets); 2621 intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets); 2622 2623 policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation); 2624 intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets); 2625 } 2626 2627 /** 2628 * Forces the app bounds related configuration can be computed by 2629 * {@link #computeConfigResourceOverrides(Configuration, Configuration, DisplayInfo, 2630 * ActivityRecord.CompatDisplayInsets)}. 2631 */ invalidateAppBoundsConfig(@onNull Configuration inOutConfig)2632 private static void invalidateAppBoundsConfig(@NonNull Configuration inOutConfig) { 2633 final Rect appBounds = inOutConfig.windowConfiguration.getAppBounds(); 2634 if (appBounds != null) { 2635 appBounds.setEmpty(); 2636 } 2637 inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED; 2638 inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED; 2639 } 2640 computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo)2641 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, 2642 @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) { 2643 if (overrideDisplayInfo != null) { 2644 // Make sure the screen related configs can be computed by the provided display info. 2645 inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED; 2646 invalidateAppBoundsConfig(inOutConfig); 2647 } 2648 computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo, 2649 null /* compatInsets */); 2650 } 2651 computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig)2652 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, 2653 @NonNull Configuration parentConfig) { 2654 computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */, 2655 null /* compatInsets */); 2656 } 2657 computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)2658 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, 2659 @NonNull Configuration parentConfig, 2660 @Nullable ActivityRecord.CompatDisplayInsets compatInsets) { 2661 if (compatInsets != null) { 2662 // Make sure the app bounds can be computed by the compat insets. 2663 invalidateAppBoundsConfig(inOutConfig); 2664 } 2665 computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */, 2666 compatInsets); 2667 } 2668 2669 /** 2670 * Calculates configuration values used by the client to get resources. This should be run 2671 * using app-facing bounds (bounds unmodified by animations or transient interactions). 2672 * 2673 * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely 2674 * configuring an "inherit-bounds" window which means that all configuration settings would 2675 * just be inherited from the parent configuration. 2676 **/ computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)2677 void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, 2678 @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo, 2679 @Nullable ActivityRecord.CompatDisplayInsets compatInsets) { 2680 int windowingMode = inOutConfig.windowConfiguration.getWindowingMode(); 2681 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 2682 windowingMode = parentConfig.windowConfiguration.getWindowingMode(); 2683 } 2684 2685 float density = inOutConfig.densityDpi; 2686 if (density == Configuration.DENSITY_DPI_UNDEFINED) { 2687 density = parentConfig.densityDpi; 2688 } 2689 density *= DisplayMetrics.DENSITY_DEFAULT_SCALE; 2690 2691 // The bounds may have been overridden at this level. If the parent cannot cover these 2692 // bounds, the configuration is still computed according to the override bounds. 2693 final boolean insideParentBounds; 2694 2695 final Rect parentBounds = parentConfig.windowConfiguration.getBounds(); 2696 final Rect resolvedBounds = inOutConfig.windowConfiguration.getBounds(); 2697 if (resolvedBounds == null || resolvedBounds.isEmpty()) { 2698 mTmpFullBounds.set(parentBounds); 2699 insideParentBounds = true; 2700 } else { 2701 mTmpFullBounds.set(resolvedBounds); 2702 insideParentBounds = parentBounds.contains(resolvedBounds); 2703 } 2704 2705 // Non-null compatibility insets means the activity prefers to keep its original size, so 2706 // out bounds doesn't need to be restricted by the parent or current display 2707 final boolean customContainerPolicy = compatInsets != null; 2708 2709 Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); 2710 if (outAppBounds == null || outAppBounds.isEmpty()) { 2711 // App-bounds hasn't been overridden, so calculate a value for it. 2712 inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds); 2713 outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); 2714 2715 if (!customContainerPolicy && windowingMode != WINDOWING_MODE_FREEFORM) { 2716 final Rect containingAppBounds; 2717 if (insideParentBounds) { 2718 containingAppBounds = parentConfig.windowConfiguration.getAppBounds(); 2719 } else { 2720 // Restrict appBounds to display non-decor rather than parent because the 2721 // override bounds are beyond the parent. Otherwise, it won't match the 2722 // overridden bounds. 2723 final TaskDisplayArea displayArea = getDisplayArea(); 2724 containingAppBounds = displayArea != null 2725 ? displayArea.getWindowConfiguration().getAppBounds() : null; 2726 } 2727 if (containingAppBounds != null && !containingAppBounds.isEmpty()) { 2728 outAppBounds.intersect(containingAppBounds); 2729 } 2730 } 2731 } 2732 2733 if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED 2734 || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { 2735 if (!customContainerPolicy && WindowConfiguration.isFloating(windowingMode)) { 2736 mTmpNonDecorBounds.set(mTmpFullBounds); 2737 mTmpStableBounds.set(mTmpFullBounds); 2738 } else if (!customContainerPolicy 2739 && (overrideDisplayInfo != null || getDisplayContent() != null)) { 2740 final DisplayInfo di = overrideDisplayInfo != null 2741 ? overrideDisplayInfo 2742 : getDisplayContent().getDisplayInfo(); 2743 2744 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen 2745 // area, i.e. the screen area without the system bars. 2746 // The non decor inset are areas that could never be removed in Honeycomb. See 2747 // {@link WindowManagerPolicy#getNonDecorInsetsLw}. 2748 calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di); 2749 } else { 2750 // Apply the given non-decor and stable insets to calculate the corresponding bounds 2751 // for screen size of configuration. 2752 int rotation = inOutConfig.windowConfiguration.getRotation(); 2753 if (rotation == ROTATION_UNDEFINED) { 2754 rotation = parentConfig.windowConfiguration.getRotation(); 2755 } 2756 if (rotation != ROTATION_UNDEFINED && customContainerPolicy) { 2757 mTmpNonDecorBounds.set(mTmpFullBounds); 2758 mTmpStableBounds.set(mTmpFullBounds); 2759 compatInsets.getBoundsByRotation(mTmpBounds, rotation); 2760 intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds, 2761 compatInsets.mNonDecorInsets[rotation]); 2762 intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds, 2763 compatInsets.mStableInsets[rotation]); 2764 outAppBounds.set(mTmpNonDecorBounds); 2765 } else { 2766 // Set to app bounds because it excludes decor insets. 2767 mTmpNonDecorBounds.set(outAppBounds); 2768 mTmpStableBounds.set(outAppBounds); 2769 } 2770 } 2771 2772 if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) { 2773 final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density); 2774 inOutConfig.screenWidthDp = (insideParentBounds && !customContainerPolicy) 2775 ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp) 2776 : overrideScreenWidthDp; 2777 } 2778 if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { 2779 final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density); 2780 inOutConfig.screenHeightDp = (insideParentBounds && !customContainerPolicy) 2781 ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp) 2782 : overrideScreenHeightDp; 2783 } 2784 2785 if (inOutConfig.smallestScreenWidthDp 2786 == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { 2787 if (WindowConfiguration.isFloating(windowingMode)) { 2788 // For floating tasks, calculate the smallest width from the bounds of the task 2789 inOutConfig.smallestScreenWidthDp = (int) ( 2790 Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density); 2791 } 2792 // otherwise, it will just inherit 2793 } 2794 } 2795 2796 if (inOutConfig.orientation == ORIENTATION_UNDEFINED) { 2797 inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp) 2798 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; 2799 } 2800 if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) { 2801 // For calculating screen layout, we need to use the non-decor inset screen area for the 2802 // calculation for compatibility reasons, i.e. screen area without system bars that 2803 // could never go away in Honeycomb. 2804 int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density); 2805 int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density); 2806 // Use overrides if provided. If both overrides are provided, mTmpNonDecorBounds is 2807 // undefined so it can't be used. 2808 if (inOutConfig.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) { 2809 compatScreenWidthDp = inOutConfig.screenWidthDp; 2810 } 2811 if (inOutConfig.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { 2812 compatScreenHeightDp = inOutConfig.screenHeightDp; 2813 } 2814 // Reducing the screen layout starting from its parent config. 2815 inOutConfig.screenLayout = computeScreenLayoutOverride(parentConfig.screenLayout, 2816 compatScreenWidthDp, compatScreenHeightDp); 2817 } 2818 } 2819 2820 /** Computes LONG, SIZE and COMPAT parts of {@link Configuration#screenLayout}. */ computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp, int screenHeightDp)2821 static int computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp, 2822 int screenHeightDp) { 2823 sourceScreenLayout = sourceScreenLayout 2824 & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK); 2825 final int longSize = Math.max(screenWidthDp, screenHeightDp); 2826 final int shortSize = Math.min(screenWidthDp, screenHeightDp); 2827 return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize); 2828 } 2829 2830 @Override resolveOverrideConfiguration(Configuration newParentConfig)2831 void resolveOverrideConfiguration(Configuration newParentConfig) { 2832 mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds()); 2833 super.resolveOverrideConfiguration(newParentConfig); 2834 2835 int windowingMode = 2836 getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode(); 2837 final int parentWindowingMode = newParentConfig.windowConfiguration.getWindowingMode(); 2838 2839 // Resolve override windowing mode to fullscreen for home task (even on freeform 2840 // display), or split-screen if in split-screen mode. 2841 if (getActivityType() == ACTIVITY_TYPE_HOME && windowingMode == WINDOWING_MODE_UNDEFINED) { 2842 windowingMode = WindowConfiguration.isSplitScreenWindowingMode(parentWindowingMode) 2843 ? parentWindowingMode : WINDOWING_MODE_FULLSCREEN; 2844 getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode); 2845 } 2846 2847 // Do not allow tasks not support multi window to be in a multi-window mode, unless it is in 2848 // pinned windowing mode. 2849 if (!supportsMultiWindow()) { 2850 final int candidateWindowingMode = 2851 windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : parentWindowingMode; 2852 if (WindowConfiguration.inMultiWindowMode(candidateWindowingMode) 2853 && candidateWindowingMode != WINDOWING_MODE_PINNED) { 2854 getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode( 2855 WINDOWING_MODE_FULLSCREEN); 2856 } 2857 } 2858 2859 if (isLeafTask()) { 2860 resolveLeafOnlyOverrideConfigs(newParentConfig, mTmpBounds /* previousBounds */); 2861 } 2862 computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig); 2863 } 2864 resolveLeafOnlyOverrideConfigs(Configuration newParentConfig, Rect previousBounds)2865 private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig, 2866 Rect previousBounds) { 2867 2868 int windowingMode = 2869 getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode(); 2870 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 2871 windowingMode = newParentConfig.windowConfiguration.getWindowingMode(); 2872 } 2873 // Commit the resolved windowing mode so the canSpecifyOrientation won't get the old 2874 // mode that may cause the bounds to be miscalculated, e.g. letterboxed. 2875 getConfiguration().windowConfiguration.setWindowingMode(windowingMode); 2876 Rect outOverrideBounds = 2877 getResolvedOverrideConfiguration().windowConfiguration.getBounds(); 2878 2879 if (windowingMode == WINDOWING_MODE_FULLSCREEN) { 2880 // Use empty bounds to indicate "fill parent". 2881 outOverrideBounds.setEmpty(); 2882 // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if 2883 // the parent or display is smaller than the size, the content may be cropped. 2884 return; 2885 } 2886 2887 adjustForMinimalTaskDimensions(outOverrideBounds, previousBounds, newParentConfig); 2888 if (windowingMode == WINDOWING_MODE_FREEFORM) { 2889 computeFreeformBounds(outOverrideBounds, newParentConfig); 2890 return; 2891 } 2892 } 2893 2894 /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FREEFORM}. */ computeFreeformBounds(@onNull Rect outBounds, @NonNull Configuration newParentConfig)2895 private void computeFreeformBounds(@NonNull Rect outBounds, 2896 @NonNull Configuration newParentConfig) { 2897 // by policy, make sure the window remains within parent somewhere 2898 final float density = 2899 ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT; 2900 final Rect parentBounds = 2901 new Rect(newParentConfig.windowConfiguration.getBounds()); 2902 final DisplayContent display = getDisplayContent(); 2903 if (display != null) { 2904 // If a freeform window moves below system bar, there is no way to move it again 2905 // by touch. Because its caption is covered by system bar. So we exclude them 2906 // from root task bounds. and then caption will be shown inside stable area. 2907 final Rect stableBounds = new Rect(); 2908 display.getStableRect(stableBounds); 2909 parentBounds.intersect(stableBounds); 2910 } 2911 2912 fitWithinBounds(outBounds, parentBounds, 2913 (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP), 2914 (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP)); 2915 2916 // Prevent to overlap caption with stable insets. 2917 final int offsetTop = parentBounds.top - outBounds.top; 2918 if (offsetTop > 0) { 2919 outBounds.offset(0, offsetTop); 2920 } 2921 } 2922 updateOverrideConfigurationFromLaunchBounds()2923 Rect updateOverrideConfigurationFromLaunchBounds() { 2924 // If the task is controlled by another organized task, do not set override 2925 // configurations and let its parent (organized task) to control it; 2926 final Task rootTask = getRootTask(); 2927 final Rect bounds = rootTask != this && rootTask.isOrganized() ? null : getLaunchBounds(); 2928 setBounds(bounds); 2929 if (bounds != null && !bounds.isEmpty()) { 2930 // TODO: Review if we actually want to do this - we are setting the launch bounds 2931 // directly here. 2932 bounds.set(getRequestedOverrideBounds()); 2933 } 2934 return bounds; 2935 } 2936 2937 /** Returns the bounds that should be used to launch this task. */ getLaunchBounds()2938 Rect getLaunchBounds() { 2939 final Task rootTask = getRootTask(); 2940 if (rootTask == null) { 2941 return null; 2942 } 2943 2944 final int windowingMode = getWindowingMode(); 2945 if (!isActivityTypeStandardOrUndefined() 2946 || windowingMode == WINDOWING_MODE_FULLSCREEN 2947 || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) { 2948 return isResizeable() ? rootTask.getRequestedOverrideBounds() : null; 2949 } else if (!getWindowConfiguration().persistTaskBounds()) { 2950 return rootTask.getRequestedOverrideBounds(); 2951 } 2952 return mLastNonFullscreenBounds; 2953 } 2954 setRootProcess(WindowProcessController proc)2955 void setRootProcess(WindowProcessController proc) { 2956 clearRootProcess(); 2957 if (intent != null 2958 && (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) { 2959 mRootProcess = proc; 2960 mRootProcess.addRecentTask(this); 2961 } 2962 } 2963 clearRootProcess()2964 void clearRootProcess() { 2965 if (mRootProcess != null) { 2966 mRootProcess.removeRecentTask(this); 2967 mRootProcess = null; 2968 } 2969 } 2970 getDisplayId()2971 int getDisplayId() { 2972 final DisplayContent dc = getDisplayContent(); 2973 return dc != null ? dc.mDisplayId : INVALID_DISPLAY; 2974 } 2975 2976 /** @return Id of root task. */ getRootTaskId()2977 int getRootTaskId() { 2978 return getRootTask().mTaskId; 2979 } 2980 getRootTask()2981 Task getRootTask() { 2982 final WindowContainer parent = getParent(); 2983 if (parent == null) return this; 2984 2985 final Task parentTask = parent.asTask(); 2986 return parentTask == null ? this : parentTask.getRootTask(); 2987 } 2988 2989 /** @return the first organized task. */ 2990 @Nullable getOrganizedTask()2991 Task getOrganizedTask() { 2992 if (isOrganized()) { 2993 return this; 2994 } 2995 final WindowContainer parent = getParent(); 2996 if (parent == null) { 2997 return null; 2998 } 2999 final Task parentTask = parent.asTask(); 3000 return parentTask == null ? null : parentTask.getOrganizedTask(); 3001 } 3002 3003 // TODO(task-merge): Figure out what's the right thing to do for places that used it. isRootTask()3004 boolean isRootTask() { 3005 return getRootTask() == this; 3006 } 3007 isLeafTask()3008 boolean isLeafTask() { 3009 for (int i = mChildren.size() - 1; i >= 0; --i) { 3010 if (mChildren.get(i).asTask() != null) { 3011 return false; 3012 } 3013 } 3014 return true; 3015 } 3016 getDescendantTaskCount()3017 int getDescendantTaskCount() { 3018 final int[] currentCount = {0}; 3019 final PooledConsumer c = PooledLambda.obtainConsumer((t, count) -> { count[0]++; }, 3020 PooledLambda.__(Task.class), currentCount); 3021 forAllLeafTasks(c, false /* traverseTopToBottom */); 3022 c.recycle(); 3023 return currentCount[0]; 3024 } 3025 3026 /** 3027 * Find next proper focusable root task and make it focused. 3028 * @return The root task that now got the focus, {@code null} if none found. 3029 */ adjustFocusToNextFocusableTask(String reason)3030 Task adjustFocusToNextFocusableTask(String reason) { 3031 return adjustFocusToNextFocusableTask(reason, false /* allowFocusSelf */, 3032 true /* moveDisplayToTop */); 3033 } 3034 3035 /** Return the next focusable task by looking from the siblings and parent tasks */ getNextFocusableTask(boolean allowFocusSelf)3036 private Task getNextFocusableTask(boolean allowFocusSelf) { 3037 final WindowContainer parent = getParent(); 3038 if (parent == null) { 3039 return null; 3040 } 3041 3042 final Task focusableTask = parent.getTask((task) -> (allowFocusSelf || task != this) 3043 && ((Task) task).isFocusableAndVisible()); 3044 if (focusableTask == null && parent.asTask() != null) { 3045 return parent.asTask().getNextFocusableTask(allowFocusSelf); 3046 } else { 3047 return focusableTask; 3048 } 3049 } 3050 3051 /** 3052 * Find next proper focusable task and make it focused. 3053 * @param reason The reason of making the adjustment. 3054 * @param allowFocusSelf Is the focus allowed to remain on the same task. 3055 * @param moveDisplayToTop Whether to move display to top while making the task focused. 3056 * @return The root task that now got the focus, {@code null} if none found. 3057 */ adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf, boolean moveDisplayToTop)3058 Task adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf, 3059 boolean moveDisplayToTop) { 3060 Task focusableTask = getNextFocusableTask(allowFocusSelf); 3061 if (focusableTask == null) { 3062 focusableTask = mRootWindowContainer.getNextFocusableRootTask(this, !allowFocusSelf); 3063 } 3064 if (focusableTask == null) { 3065 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 3066 if (taskDisplayArea != null) { 3067 // Clear the recorded task since there is no next focusable task. 3068 taskDisplayArea.clearPreferredTopFocusableRootTask(); 3069 } 3070 return null; 3071 } 3072 3073 final Task rootTask = focusableTask.getRootTask(); 3074 if (!moveDisplayToTop) { 3075 // There may be multiple task layers above this task, so when relocating the task to the 3076 // top, we should move this task and each of its parent task that below display area to 3077 // the top of each layer. 3078 WindowContainer parent = focusableTask.getParent(); 3079 WindowContainer next = focusableTask; 3080 do { 3081 parent.positionChildAt(POSITION_TOP, next, false /* includingParents */); 3082 next = parent; 3083 parent = next.getParent(); 3084 } while (next.asTask() != null && parent != null); 3085 return rootTask; 3086 } 3087 3088 final String myReason = reason + " adjustFocusToNextFocusableTask"; 3089 final ActivityRecord top = focusableTask.topRunningActivity(); 3090 if (focusableTask.isActivityTypeHome() && (top == null || !top.mVisibleRequested)) { 3091 // If we will be focusing on the root home task next and its current top activity isn't 3092 // visible, then use the move the root home task to top to make the activity visible. 3093 focusableTask.getDisplayArea().moveHomeActivityToTop(myReason); 3094 return rootTask; 3095 } 3096 3097 // Move the entire hierarchy to top with updating global top resumed activity 3098 // and focused application if needed. 3099 focusableTask.moveToFront(myReason); 3100 // Top display focused root task is changed, update top resumed activity if needed. 3101 if (rootTask.getResumedActivity() != null) { 3102 mTaskSupervisor.updateTopResumedActivityIfNeeded(); 3103 // Set focused app directly because if the next focused activity is already resumed 3104 // (e.g. the next top activity is on a different display), there won't have activity 3105 // state change to update it. 3106 mAtmService.setResumedActivityUncheckLocked(rootTask.getResumedActivity(), reason); 3107 } 3108 return rootTask; 3109 } 3110 3111 /** Calculate the minimum possible position for a task that can be shown to the user. 3112 * The minimum position will be above all other tasks that can't be shown. 3113 * @param minPosition The minimum position the caller is suggesting. 3114 * We will start adjusting up from here. 3115 * @param size The size of the current task list. 3116 */ 3117 // TODO: Move user to their own window container. computeMinUserPosition(int minPosition, int size)3118 private int computeMinUserPosition(int minPosition, int size) { 3119 while (minPosition < size) { 3120 final WindowContainer child = mChildren.get(minPosition); 3121 final boolean canShow = child.showToCurrentUser(); 3122 if (canShow) { 3123 break; 3124 } 3125 minPosition++; 3126 } 3127 return minPosition; 3128 } 3129 3130 /** Calculate the maximum possible position for a task that can't be shown to the user. 3131 * The maximum position will be below all other tasks that can be shown. 3132 * @param maxPosition The maximum position the caller is suggesting. 3133 * We will start adjusting down from here. 3134 */ 3135 // TODO: Move user to their own window container. computeMaxUserPosition(int maxPosition)3136 private int computeMaxUserPosition(int maxPosition) { 3137 while (maxPosition > 0) { 3138 final WindowContainer child = mChildren.get(maxPosition); 3139 final boolean canShow = child.showToCurrentUser(); 3140 if (!canShow) { 3141 break; 3142 } 3143 maxPosition--; 3144 } 3145 return maxPosition; 3146 } 3147 getAdjustedChildPosition(WindowContainer wc, int suggestedPosition)3148 private int getAdjustedChildPosition(WindowContainer wc, int suggestedPosition) { 3149 final boolean canShowChild = wc.showToCurrentUser(); 3150 3151 final int size = mChildren.size(); 3152 3153 // Figure-out min/max possible position depending on if child can show for current user. 3154 int minPosition = (canShowChild) ? computeMinUserPosition(0, size) : 0; 3155 int maxPosition = (canShowChild) ? size - 1 : computeMaxUserPosition(size - 1); 3156 if (!hasChild(wc)) { 3157 // Increase the maxPosition because children size will grow once wc is added. 3158 ++maxPosition; 3159 } 3160 3161 // Factor in always-on-top children in max possible position. 3162 if (!wc.isAlwaysOnTop()) { 3163 // We want to place all non-always-on-top containers below always-on-top ones. 3164 while (maxPosition > minPosition) { 3165 if (!mChildren.get(maxPosition - 1).isAlwaysOnTop()) break; 3166 --maxPosition; 3167 } 3168 } 3169 3170 // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid. 3171 if (suggestedPosition == POSITION_BOTTOM && minPosition == 0) { 3172 return POSITION_BOTTOM; 3173 } else if (suggestedPosition == POSITION_TOP && maxPosition >= (size - 1)) { 3174 return POSITION_TOP; 3175 } 3176 // Reset position based on minimum/maximum possible positions. 3177 return Math.min(Math.max(suggestedPosition, minPosition), maxPosition); 3178 } 3179 3180 @Override positionChildAt(int position, WindowContainer child, boolean includingParents)3181 void positionChildAt(int position, WindowContainer child, boolean includingParents) { 3182 final boolean toTop = position >= (mChildren.size() - 1); 3183 position = getAdjustedChildPosition(child, position); 3184 super.positionChildAt(position, child, includingParents); 3185 3186 // Log positioning. 3187 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "positionChildAt: child=" + child 3188 + " position=" + position + " parent=" + this); 3189 3190 final Task task = child.asTask(); 3191 if (task != null) { 3192 task.updateTaskMovement(toTop, position); 3193 } 3194 } 3195 3196 @VisibleForTesting hasWindowsAlive()3197 boolean hasWindowsAlive() { 3198 return getActivity(ActivityRecord::hasWindowsAlive) != null; 3199 } 3200 3201 @VisibleForTesting shouldDeferRemoval()3202 boolean shouldDeferRemoval() { 3203 if (mChildren.isEmpty()) { 3204 // No reason to defer removal of a Task that doesn't have any child. 3205 return false; 3206 } 3207 return hasWindowsAlive() && getRootTask().isAnimating(TRANSITION | CHILDREN); 3208 } 3209 3210 @Override removeImmediately()3211 void removeImmediately() { 3212 removeImmediately("removeTask"); 3213 } 3214 removeImmediately(String reason)3215 void removeImmediately(String reason) { 3216 if (DEBUG_ROOT_TASK) Slog.i(TAG, "removeTask:" + reason + " removing taskId=" + mTaskId); 3217 if (mRemoving) { 3218 return; 3219 } 3220 mRemoving = true; 3221 3222 EventLogTags.writeWmTaskRemoved(mTaskId, reason); 3223 clearPinnedTaskIfNeed(); 3224 // If applicable let the TaskOrganizer know the Task is vanishing. 3225 setTaskOrganizer(null); 3226 3227 super.removeImmediately(); 3228 mRemoving = false; 3229 } 3230 3231 // TODO: Consolidate this with Task.reparent() reparent(Task rootTask, int position, boolean moveParents, String reason)3232 void reparent(Task rootTask, int position, boolean moveParents, String reason) { 3233 if (DEBUG_ROOT_TASK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId 3234 + " from rootTask=" + getRootTask()); 3235 EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask:" + reason); 3236 3237 reparent(rootTask, position); 3238 3239 rootTask.positionChildAt(position, this, moveParents); 3240 3241 // If we are moving from the fullscreen root task to the root pinned task then we want to 3242 // preserve our insets so that there will not be a jump in the area covered by system 3243 // decorations. We rely on the pinned animation to later unset this value. 3244 mPreserveNonFloatingState = rootTask.inPinnedWindowingMode(); 3245 } 3246 setBounds(Rect bounds, boolean forceResize)3247 public int setBounds(Rect bounds, boolean forceResize) { 3248 final int boundsChanged = setBounds(bounds); 3249 3250 if (forceResize && (boundsChanged & BOUNDS_CHANGE_SIZE) != BOUNDS_CHANGE_SIZE) { 3251 onResize(); 3252 return BOUNDS_CHANGE_SIZE | boundsChanged; 3253 } 3254 3255 return boundsChanged; 3256 } 3257 3258 /** Set the task bounds. Passing in null sets the bounds to fullscreen. */ 3259 @Override setBounds(Rect bounds)3260 public int setBounds(Rect bounds) { 3261 if (isRootTask()) { 3262 return setBounds(getRequestedOverrideBounds(), bounds); 3263 } 3264 3265 int rotation = Surface.ROTATION_0; 3266 final DisplayContent displayContent = getRootTask() != null 3267 ? getRootTask().getDisplayContent() : null; 3268 if (displayContent != null) { 3269 rotation = displayContent.getDisplayInfo().rotation; 3270 } 3271 3272 final int boundsChange = super.setBounds(bounds); 3273 mRotation = rotation; 3274 updateSurfacePositionNonOrganized(); 3275 return boundsChange; 3276 } 3277 3278 @Override isCompatible(int windowingMode, int activityType)3279 public boolean isCompatible(int windowingMode, int activityType) { 3280 // TODO: Should we just move this to ConfigurationContainer? 3281 if (activityType == ACTIVITY_TYPE_UNDEFINED) { 3282 // Undefined activity types end up in a standard root task once the root task is 3283 // created on a display, so they should be considered compatible. 3284 activityType = ACTIVITY_TYPE_STANDARD; 3285 } 3286 return super.isCompatible(windowingMode, activityType); 3287 } 3288 3289 @Override onDescendantOrientationChanged(WindowContainer requestingContainer)3290 public boolean onDescendantOrientationChanged(WindowContainer requestingContainer) { 3291 if (super.onDescendantOrientationChanged(requestingContainer)) { 3292 return true; 3293 } 3294 3295 // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill 3296 // it if possible. 3297 if (getParent() != null) { 3298 onConfigurationChanged(getParent().getConfiguration()); 3299 return true; 3300 } 3301 return false; 3302 } 3303 3304 @Override handlesOrientationChangeFromDescendant()3305 boolean handlesOrientationChangeFromDescendant() { 3306 if (!super.handlesOrientationChangeFromDescendant()) { 3307 return false; 3308 } 3309 3310 // At task level, we want to check canSpecifyOrientation() based on the top activity type. 3311 // Do this only on leaf Task, so that the result is not affecting by the sibling leaf Task. 3312 // Otherwise, root Task will use the result from the top leaf Task, and all its child 3313 // leaf Tasks will rely on that from super.handlesOrientationChangeFromDescendant(). 3314 if (!isLeafTask()) { 3315 return true; 3316 } 3317 3318 // Check for leaf Task. 3319 // Display won't rotate for the orientation request if the Task/TaskDisplayArea 3320 // can't specify orientation. 3321 return canSpecifyOrientation() && getDisplayArea().canSpecifyOrientation(); 3322 } 3323 resize(boolean relayout, boolean forced)3324 void resize(boolean relayout, boolean forced) { 3325 if (setBounds(getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE && relayout) { 3326 getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); 3327 } 3328 } 3329 3330 @Override onDisplayChanged(DisplayContent dc)3331 void onDisplayChanged(DisplayContent dc) { 3332 final boolean isRootTask = isRootTask(); 3333 if (!isRootTask) { 3334 adjustBoundsForDisplayChangeIfNeeded(dc); 3335 } 3336 super.onDisplayChanged(dc); 3337 if (isLeafTask()) { 3338 final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY; 3339 mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged( 3340 mTaskId, displayId); 3341 } 3342 if (isRootTask()) { 3343 updateSurfaceBounds(); 3344 } 3345 } 3346 isResizeable()3347 boolean isResizeable() { 3348 final boolean forceResizable = mAtmService.mForceResizableActivities 3349 && getActivityType() == ACTIVITY_TYPE_STANDARD; 3350 return forceResizable || ActivityInfo.isResizeableMode(mResizeMode) 3351 || mSupportsPictureInPicture; 3352 } 3353 3354 /** 3355 * Tests if the orientation should be preserved upon user interactive resizig operations. 3356 3357 * @return true if orientation should not get changed upon resizing operation. 3358 */ preserveOrientationOnResize()3359 boolean preserveOrientationOnResize() { 3360 return mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY 3361 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY 3362 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; 3363 } 3364 cropWindowsToRootTaskBounds()3365 boolean cropWindowsToRootTaskBounds() { 3366 // Don't crop HOME/RECENTS windows to root task bounds. This is because in split-screen 3367 // they extend past their root task and sysui uses the root task surface to control 3368 // cropping. 3369 // TODO(b/158242495): get rid of this when drag/drop can use surface bounds. 3370 if (isActivityTypeHome() || isActivityTypeRecents()) { 3371 // Make sure this is the top-most non-organizer root task (if not top-most, it means 3372 // another translucent task could be above this, so this needs to stay cropped. 3373 final Task rootTask = getRootTask(); 3374 final Task topNonOrgTask = 3375 rootTask.mCreatedByOrganizer ? rootTask.getTopMostTask() : rootTask; 3376 if (this == topNonOrgTask || isDescendantOf(topNonOrgTask)) { 3377 return false; 3378 } 3379 } 3380 return isResizeable(); 3381 } 3382 3383 @Override getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, Rect outSurfaceInsets)3384 void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, 3385 Rect outSurfaceInsets) { 3386 final WindowState windowState = getTopVisibleAppMainWindow(); 3387 if (windowState != null) { 3388 windowState.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); 3389 } else { 3390 super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); 3391 } 3392 } 3393 3394 /** 3395 * Calculate the maximum visible area of this task. If the task has only one app, 3396 * the result will be visible frame of that app. If the task has more than one apps, 3397 * we search from top down if the next app got different visible area. 3398 * 3399 * This effort is to handle the case where some task (eg. GMail composer) might pop up 3400 * a dialog that's different in size from the activity below, in which case we should 3401 * be dimming the entire task area behind the dialog. 3402 * 3403 * @param out the union of visible bounds. 3404 */ getMaxVisibleBounds(ActivityRecord token, Rect out, boolean[] foundTop)3405 private static void getMaxVisibleBounds(ActivityRecord token, Rect out, boolean[] foundTop) { 3406 // skip hidden (or about to hide) apps 3407 if (token.mIsExiting || !token.isClientVisible() || !token.mVisibleRequested) { 3408 return; 3409 } 3410 final WindowState win = token.findMainWindow(); 3411 if (win == null) { 3412 return; 3413 } 3414 if (!foundTop[0]) { 3415 foundTop[0] = true; 3416 out.setEmpty(); 3417 } 3418 3419 final Rect visibleFrame = sTmpBounds; 3420 visibleFrame.set(win.getFrame()); 3421 visibleFrame.inset(win.getInsetsStateWithVisibilityOverride().calculateVisibleInsets( 3422 visibleFrame, win.mAttrs.softInputMode)); 3423 out.union(visibleFrame); 3424 } 3425 3426 /** Bounds of the task to be used for dimming, as well as touch related tests. */ getDimBounds(Rect out)3427 void getDimBounds(Rect out) { 3428 if (isRootTask()) { 3429 getBounds(out); 3430 return; 3431 } 3432 3433 final Task rootTask = getRootTask(); 3434 final DisplayContent displayContent = rootTask.getDisplayContent(); 3435 // It doesn't matter if we in particular are part of the resize, since we couldn't have 3436 // a DimLayer anyway if we weren't visible. 3437 final boolean dockedResizing = displayContent != null 3438 && displayContent.mDividerControllerLocked.isResizing(); 3439 if (inFreeformWindowingMode()) { 3440 boolean[] foundTop = { false }; 3441 final PooledConsumer c = PooledLambda.obtainConsumer(Task::getMaxVisibleBounds, 3442 PooledLambda.__(ActivityRecord.class), out, foundTop); 3443 forAllActivities(c); 3444 c.recycle(); 3445 if (foundTop[0]) { 3446 return; 3447 } 3448 } 3449 3450 if (!matchParentBounds()) { 3451 // When minimizing the root docked task when going home, we don't adjust the task bounds 3452 // so we need to intersect the task bounds with the root task bounds here. 3453 // 3454 // If we are Docked Resizing with snap points, the task bounds could be smaller than the 3455 // root task bounds and so we don't even want to use them. Even if the app should not be 3456 // resized the Dim should keep up with the divider. 3457 if (dockedResizing) { 3458 rootTask.getBounds(out); 3459 } else { 3460 rootTask.getBounds(mTmpRect); 3461 mTmpRect.intersect(getBounds()); 3462 out.set(mTmpRect); 3463 } 3464 } else { 3465 out.set(getBounds()); 3466 } 3467 return; 3468 } 3469 setDragResizing(boolean dragResizing, int dragResizeMode)3470 void setDragResizing(boolean dragResizing, int dragResizeMode) { 3471 if (mDragResizing != dragResizing) { 3472 // No need to check if the mode is allowed if it's leaving dragResize 3473 if (dragResizing 3474 && !DragResizeMode.isModeAllowedForRootTask(getRootTask(), dragResizeMode)) { 3475 throw new IllegalArgumentException("Drag resize mode not allow for root task id=" 3476 + getRootTaskId() + " dragResizeMode=" + dragResizeMode); 3477 } 3478 mDragResizing = dragResizing; 3479 mDragResizeMode = dragResizeMode; 3480 resetDragResizingChangeReported(); 3481 } 3482 } 3483 isDragResizing()3484 boolean isDragResizing() { 3485 return mDragResizing; 3486 } 3487 getDragResizeMode()3488 int getDragResizeMode() { 3489 return mDragResizeMode; 3490 } 3491 adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent)3492 void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) { 3493 if (displayContent == null) { 3494 return; 3495 } 3496 if (getRequestedOverrideBounds().isEmpty()) { 3497 return; 3498 } 3499 final int displayId = displayContent.getDisplayId(); 3500 final int newRotation = displayContent.getDisplayInfo().rotation; 3501 if (displayId != mLastRotationDisplayId) { 3502 // This task is on a display that it wasn't on. There is no point to keep the relative 3503 // position if display rotations for old and new displays are different. Just keep these 3504 // values. 3505 mLastRotationDisplayId = displayId; 3506 mRotation = newRotation; 3507 return; 3508 } 3509 3510 if (mRotation == newRotation) { 3511 // Rotation didn't change. We don't need to adjust the bounds to keep the relative 3512 // position. 3513 return; 3514 } 3515 3516 // Device rotation changed. 3517 // - We don't want the task to move around on the screen when this happens, so update the 3518 // task bounds so it stays in the same place. 3519 // - Rotate the bounds and notify activity manager if the task can be resized independently 3520 // from its root task. The root task will take care of task rotation for the other case. 3521 mTmpRect2.set(getBounds()); 3522 3523 if (!getWindowConfiguration().canResizeTask()) { 3524 setBounds(mTmpRect2); 3525 return; 3526 } 3527 3528 displayContent.rotateBounds(mRotation, newRotation, mTmpRect2); 3529 if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) { 3530 mAtmService.resizeTask(mTaskId, getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION); 3531 } 3532 } 3533 3534 /** Cancels any running app transitions associated with the task. */ cancelTaskWindowTransition()3535 void cancelTaskWindowTransition() { 3536 for (int i = mChildren.size() - 1; i >= 0; --i) { 3537 mChildren.get(i).cancelAnimation(); 3538 } 3539 } 3540 showForAllUsers()3541 boolean showForAllUsers() { 3542 if (mChildren.isEmpty()) return false; 3543 final ActivityRecord r = getTopNonFinishingActivity(); 3544 return r != null && r.mShowForAllUsers; 3545 } 3546 3547 @Override showToCurrentUser()3548 boolean showToCurrentUser() { 3549 return mForceShowForAllUsers || showForAllUsers() 3550 || mWmService.isCurrentProfile(getTopMostTask().mUserId); 3551 } 3552 setForceShowForAllUsers(boolean forceShowForAllUsers)3553 void setForceShowForAllUsers(boolean forceShowForAllUsers) { 3554 mForceShowForAllUsers = forceShowForAllUsers; 3555 } 3556 3557 @Override isAttached()3558 public boolean isAttached() { 3559 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 3560 return taskDisplayArea != null && !taskDisplayArea.isRemoved(); 3561 } 3562 3563 @Override 3564 @Nullable getDisplayArea()3565 TaskDisplayArea getDisplayArea() { 3566 return (TaskDisplayArea) super.getDisplayArea(); 3567 } 3568 3569 /** 3570 * When we are in a floating root task (Freeform, Pinned, ...) we calculate 3571 * insets differently. However if we are animating to the fullscreen root task 3572 * we need to begin calculating insets as if we were fullscreen, otherwise 3573 * we will have a jump at the end. 3574 */ isFloating()3575 boolean isFloating() { 3576 return getWindowConfiguration().tasksAreFloating() && !mPreserveNonFloatingState; 3577 } 3578 3579 /** 3580 * Returns true if the root task is translucent and can have other contents visible behind it if 3581 * needed. A root task is considered translucent if it don't contain a visible or 3582 * starting (about to be visible) activity that is fullscreen (opaque). 3583 * @param starting The currently starting activity or null if there is none. 3584 */ 3585 @VisibleForTesting isTranslucent(ActivityRecord starting)3586 boolean isTranslucent(ActivityRecord starting) { 3587 if (!isAttached() || isForceHidden()) { 3588 return true; 3589 } 3590 final PooledPredicate p = PooledLambda.obtainPredicate(Task::isOpaqueActivity, 3591 PooledLambda.__(ActivityRecord.class), starting); 3592 final ActivityRecord opaque = getActivity(p); 3593 p.recycle(); 3594 return opaque == null; 3595 } 3596 isOpaqueActivity(ActivityRecord r, ActivityRecord starting)3597 private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) { 3598 if (r.finishing) { 3599 // We don't factor in finishing activities when determining translucency since 3600 // they will be gone soon. 3601 return false; 3602 } 3603 3604 if (!r.visibleIgnoringKeyguard && r != starting) { 3605 // Also ignore invisible activities that are not the currently starting 3606 // activity (about to be visible). 3607 return false; 3608 } 3609 3610 if (r.occludesParent()) { 3611 // Root task isn't translucent if it has at least one fullscreen activity 3612 // that is visible. 3613 return true; 3614 } 3615 return false; 3616 } 3617 3618 /** Returns the top-most activity that occludes the given one, or {@code null} if none. */ 3619 @Nullable getOccludingActivityAbove(ActivityRecord activity)3620 ActivityRecord getOccludingActivityAbove(ActivityRecord activity) { 3621 final ActivityRecord top = getActivity(ActivityRecord::occludesParent, 3622 true /* traverseTopToBottom */, activity); 3623 return top != activity ? top : null; 3624 } 3625 3626 /** Iterates through all occluded activities. */ forAllOccludedActivities(Consumer<ActivityRecord> handleOccludedActivity)3627 void forAllOccludedActivities(Consumer<ActivityRecord> handleOccludedActivity) { 3628 if (!shouldBeVisible(null /* starting */)) { 3629 // The root task is invisible so all activities are occluded. 3630 forAllActivities(handleOccludedActivity); 3631 return; 3632 } 3633 final ActivityRecord topOccluding = getOccludingActivityAbove(null); 3634 if (topOccluding == null) { 3635 // No activities are occluded. 3636 return; 3637 } 3638 // Invoke the callback on the activities behind the top occluding activity. 3639 forAllActivities(r -> { 3640 handleOccludedActivity.accept(r); 3641 return false; 3642 }, topOccluding, false /* includeBoundary */, true /* traverseTopToBottom */); 3643 } 3644 3645 @Override makeAnimationLeash()3646 public SurfaceControl.Builder makeAnimationLeash() { 3647 return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId); 3648 } 3649 3650 @Override resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t)3651 void resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t) { 3652 super.resetSurfacePositionForAnimationLeash(t); 3653 } 3654 3655 @Override getAnimationBounds(int appRootTaskClipMode)3656 Rect getAnimationBounds(int appRootTaskClipMode) { 3657 // TODO(b/131661052): we should remove appRootTaskClipMode with hierarchical animations. 3658 if (appRootTaskClipMode == ROOT_TASK_CLIP_BEFORE_ANIM && getRootTask() != null) { 3659 // Using the root task bounds here effectively applies the clipping before animation. 3660 return getRootTask().getBounds(); 3661 } 3662 return super.getAnimationBounds(appRootTaskClipMode); 3663 } 3664 shouldAnimate()3665 boolean shouldAnimate() { 3666 /** 3667 * Animations are handled by the TaskOrganizer implementation. 3668 */ 3669 if (isOrganized()) { 3670 return false; 3671 } 3672 // Don't animate while the task runs recents animation but only if we are in the mode 3673 // where we cancel with deferred screenshot, which means that the controller has 3674 // transformed the task. 3675 final RecentsAnimationController controller = mWmService.getRecentsAnimationController(); 3676 if (controller != null && controller.isAnimatingTask(this) 3677 && controller.shouldDeferCancelUntilNextTransition()) { 3678 return false; 3679 } 3680 return true; 3681 } 3682 3683 @Override setInitialSurfaceControlProperties(SurfaceControl.Builder b)3684 void setInitialSurfaceControlProperties(SurfaceControl.Builder b) { 3685 b.setEffectLayer().setMetadata(METADATA_TASK_ID, mTaskId); 3686 super.setInitialSurfaceControlProperties(b); 3687 } 3688 3689 /** Checking if self or its child tasks are animated by recents animation. */ isAnimatingByRecents()3690 boolean isAnimatingByRecents() { 3691 return isAnimating(CHILDREN, ANIMATION_TYPE_RECENTS); 3692 } 3693 3694 @Override createRemoteAnimationTarget( RemoteAnimationController.RemoteAnimationRecord record)3695 RemoteAnimationTarget createRemoteAnimationTarget( 3696 RemoteAnimationController.RemoteAnimationRecord record) { 3697 final ActivityRecord activity = getTopMostActivity(); 3698 return activity != null ? activity.createRemoteAnimationTarget(record) : null; 3699 } 3700 3701 @Override canCreateRemoteAnimationTarget()3702 boolean canCreateRemoteAnimationTarget() { 3703 return true; 3704 } 3705 getTopVisibleAppMainWindow()3706 WindowState getTopVisibleAppMainWindow() { 3707 final ActivityRecord activity = getTopVisibleActivity(); 3708 return activity != null ? activity.findMainWindow() : null; 3709 } 3710 topRunningActivity()3711 ActivityRecord topRunningActivity() { 3712 return topRunningActivity(false /* focusableOnly */); 3713 } 3714 topRunningActivity(boolean focusableOnly)3715 ActivityRecord topRunningActivity(boolean focusableOnly) { 3716 // Split into 2 to avoid object creation due to variable capture. 3717 if (focusableOnly) { 3718 return getActivity((r) -> r.canBeTopRunning() && r.isFocusable()); 3719 } else { 3720 return getActivity(ActivityRecord::canBeTopRunning); 3721 } 3722 } 3723 topRunningNonDelayedActivityLocked(ActivityRecord notTop)3724 ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) { 3725 final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunningNonDelayed 3726 , PooledLambda.__(ActivityRecord.class), notTop); 3727 final ActivityRecord r = getActivity(p); 3728 p.recycle(); 3729 return r; 3730 } 3731 isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop)3732 private static boolean isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop) { 3733 return !r.delayedResume && r != notTop && r.canBeTopRunning(); 3734 } 3735 3736 /** 3737 * This is a simplified version of topRunningActivity that provides a number of 3738 * optional skip-over modes. It is intended for use with the ActivityController hook only. 3739 * 3740 * @param token If non-null, any history records matching this token will be skipped. 3741 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID. 3742 * 3743 * @return Returns the HistoryRecord of the next activity on the root task. 3744 */ topRunningActivity(IBinder token, int taskId)3745 ActivityRecord topRunningActivity(IBinder token, int taskId) { 3746 final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunning, 3747 PooledLambda.__(ActivityRecord.class), taskId, token); 3748 final ActivityRecord r = getActivity(p); 3749 p.recycle(); 3750 return r; 3751 } 3752 isTopRunning(ActivityRecord r, int taskId, IBinder notTop)3753 private static boolean isTopRunning(ActivityRecord r, int taskId, IBinder notTop) { 3754 return r.getTask().mTaskId != taskId && r.appToken != notTop && r.canBeTopRunning(); 3755 } 3756 getTopFullscreenActivity()3757 ActivityRecord getTopFullscreenActivity() { 3758 return getActivity((r) -> { 3759 final WindowState win = r.findMainWindow(); 3760 return (win != null && win.mAttrs.isFullscreen()); 3761 }); 3762 } 3763 getTopVisibleActivity()3764 ActivityRecord getTopVisibleActivity() { 3765 return getActivity((r) -> { 3766 // skip hidden (or about to hide) apps 3767 return !r.mIsExiting && r.isClientVisible() && r.mVisibleRequested; 3768 }); 3769 } 3770 3771 ActivityRecord getTopWaitSplashScreenActivity() { 3772 return getActivity((r) -> { 3773 return r.mHandleExitSplashScreen 3774 && r.mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_COPYING; 3775 }); 3776 } 3777 3778 boolean isTopActivityFocusable() { 3779 final ActivityRecord r = topRunningActivity(); 3780 return r != null ? r.isFocusable() 3781 : (isFocusable() && getWindowConfiguration().canReceiveKeys()); 3782 } 3783 3784 boolean isFocusableAndVisible() { 3785 return isTopActivityFocusable() && shouldBeVisible(null /* starting */); 3786 } 3787 3788 void positionChildAtTop(ActivityRecord child) { 3789 positionChildAt(child, POSITION_TOP); 3790 } 3791 3792 void positionChildAt(ActivityRecord child, int position) { 3793 if (child == null) { 3794 Slog.w(TAG_WM, 3795 "Attempted to position of non-existing app"); 3796 return; 3797 } 3798 3799 positionChildAt(position, child, false /* includeParents */); 3800 } 3801 3802 void setTaskDescription(TaskDescription taskDescription) { 3803 mTaskDescription = taskDescription; 3804 } 3805 3806 void onSnapshotChanged(TaskSnapshot snapshot) { 3807 mLastTaskSnapshotData.set(snapshot); 3808 mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged( 3809 mTaskId, snapshot); 3810 } 3811 3812 TaskDescription getTaskDescription() { 3813 return mTaskDescription; 3814 } 3815 3816 @Override 3817 int getOrientation(int candidate) { 3818 return canSpecifyOrientation() ? super.getOrientation(candidate) : SCREEN_ORIENTATION_UNSET; 3819 } 3820 3821 private boolean canSpecifyOrientation() { 3822 final int windowingMode = getWindowingMode(); 3823 final int activityType = getActivityType(); 3824 return windowingMode == WINDOWING_MODE_FULLSCREEN 3825 || activityType == ACTIVITY_TYPE_HOME 3826 || activityType == ACTIVITY_TYPE_RECENTS 3827 || activityType == ACTIVITY_TYPE_ASSISTANT; 3828 } 3829 3830 @Override 3831 boolean fillsParent() { 3832 // From the perspective of policy, we still want to report that this task fills parent 3833 // in fullscreen windowing mode even it doesn't match parent bounds because there will be 3834 // letterbox around its real content. 3835 return getWindowingMode() == WINDOWING_MODE_FULLSCREEN || matchParentBounds(); 3836 } 3837 3838 @Override 3839 void forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom) { 3840 final int count = mChildren.size(); 3841 boolean isLeafTask = true; 3842 if (traverseTopToBottom) { 3843 for (int i = count - 1; i >= 0; --i) { 3844 final Task child = mChildren.get(i).asTask(); 3845 if (child != null) { 3846 isLeafTask = false; 3847 child.forAllLeafTasks(callback, traverseTopToBottom); 3848 } 3849 } 3850 } else { 3851 for (int i = 0; i < count; i++) { 3852 final Task child = mChildren.get(i).asTask(); 3853 if (child != null) { 3854 isLeafTask = false; 3855 child.forAllLeafTasks(callback, traverseTopToBottom); 3856 } 3857 } 3858 } 3859 if (isLeafTask) callback.accept(this); 3860 } 3861 3862 @Override 3863 void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom) { 3864 super.forAllTasks(callback, traverseTopToBottom); 3865 callback.accept(this); 3866 } 3867 3868 @Override 3869 void forAllRootTasks(Consumer<Task> callback, boolean traverseTopToBottom) { 3870 if (isRootTask()) { 3871 callback.accept(this); 3872 } 3873 } 3874 3875 @Override 3876 boolean forAllTasks(Function<Task, Boolean> callback) { 3877 if (super.forAllTasks(callback)) return true; 3878 return callback.apply(this); 3879 } 3880 3881 @Override 3882 boolean forAllLeafTasks(Function<Task, Boolean> callback) { 3883 boolean isLeafTask = true; 3884 for (int i = mChildren.size() - 1; i >= 0; --i) { 3885 final Task child = mChildren.get(i).asTask(); 3886 if (child != null) { 3887 isLeafTask = false; 3888 if (child.forAllLeafTasks(callback)) { 3889 return true; 3890 } 3891 } 3892 } 3893 if (isLeafTask) { 3894 return callback.apply(this); 3895 } 3896 return false; 3897 } 3898 3899 @Override 3900 boolean forAllRootTasks(Function<Task, Boolean> callback, boolean traverseTopToBottom) { 3901 return isRootTask() ? callback.apply(this) : false; 3902 } 3903 3904 @Override 3905 Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) { 3906 final Task t = super.getTask(callback, traverseTopToBottom); 3907 if (t != null) return t; 3908 return callback.test(this) ? this : null; 3909 } 3910 3911 @Nullable 3912 @Override 3913 Task getRootTask(Predicate<Task> callback, boolean traverseTopToBottom) { 3914 return isRootTask() && callback.test(this) ? this : null; 3915 } 3916 3917 @Nullable 3918 @Override 3919 <R> R getItemFromRootTasks(Function<Task, R> callback, boolean traverseTopToBottom) { 3920 return isRootTask() ? callback.apply(this) : null; 3921 } 3922 3923 /** 3924 * @param canAffectSystemUiFlags If false, all windows in this task can not affect SystemUI 3925 * flags. See {@link WindowState#canAffectSystemUiFlags()}. 3926 */ 3927 void setCanAffectSystemUiFlags(boolean canAffectSystemUiFlags) { 3928 mCanAffectSystemUiFlags = canAffectSystemUiFlags; 3929 } 3930 3931 /** 3932 * @see #setCanAffectSystemUiFlags 3933 */ 3934 boolean canAffectSystemUiFlags() { 3935 return mCanAffectSystemUiFlags; 3936 } 3937 3938 void dontAnimateDimExit() { 3939 mDimmer.dontAnimateExit(); 3940 } 3941 3942 String getName() { 3943 return "Task=" + mTaskId; 3944 } 3945 3946 void clearPreserveNonFloatingState() { 3947 mPreserveNonFloatingState = false; 3948 } 3949 3950 @Override 3951 Dimmer getDimmer() { 3952 // If the window is in multi-window mode, we want to dim at the Task level to ensure the dim 3953 // bounds match the area the app lives in 3954 if (inMultiWindowMode()) { 3955 return mDimmer; 3956 } 3957 3958 // If we're not at the root task level, we want to keep traversing through the parents to 3959 // find the root. 3960 // Once at the root task level, we want to check {@link #isTranslucent(ActivityRecord)}. 3961 // If true, we want to get the Dimmer from the level above since we don't want to animate 3962 // the dim with the Task. 3963 if (!isRootTask() || isTranslucent(null)) { 3964 return super.getDimmer(); 3965 } 3966 3967 return mDimmer; 3968 } 3969 3970 @Override 3971 void prepareSurfaces() { 3972 mDimmer.resetDimStates(); 3973 super.prepareSurfaces(); 3974 getDimBounds(mTmpDimBoundsRect); 3975 3976 // Bounds need to be relative, as the dim layer is a child. 3977 if (inFreeformWindowingMode()) { 3978 getBounds(mTmpRect); 3979 mTmpDimBoundsRect.offsetTo(mTmpDimBoundsRect.left - mTmpRect.left, 3980 mTmpDimBoundsRect.top - mTmpRect.top); 3981 } else { 3982 mTmpDimBoundsRect.offsetTo(0, 0); 3983 } 3984 3985 updateShadowsRadius(isFocused(), getSyncTransaction()); 3986 3987 if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) { 3988 scheduleAnimation(); 3989 } 3990 } 3991 3992 @Override 3993 protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter, 3994 @TransitionOldType int transit, boolean isVoiceInteraction, 3995 @Nullable ArrayList<WindowContainer> sources) { 3996 final RecentsAnimationController control = mWmService.getRecentsAnimationController(); 3997 if (control != null) { 3998 // We let the transition to be controlled by RecentsAnimation, and callback task's 3999 // RemoteAnimationTarget for remote runner to animate. 4000 if (enter && !isHomeOrRecentsRootTask()) { 4001 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, 4002 "applyAnimationUnchecked, control: %s, task: %s, transit: %s", 4003 control, asTask(), AppTransition.appTransitionOldToString(transit)); 4004 control.addTaskToTargets(this, (type, anim) -> { 4005 for (int i = 0; i < sources.size(); ++i) { 4006 sources.get(i).onAnimationFinished(type, anim); 4007 } 4008 }); 4009 } 4010 } else { 4011 super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources); 4012 } 4013 } 4014 4015 @Override 4016 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 4017 super.dump(pw, prefix, dumpAll); 4018 pw.println(prefix + "bounds=" + getBounds().toShortString()); 4019 final String doublePrefix = prefix + " "; 4020 for (int i = mChildren.size() - 1; i >= 0; i--) { 4021 final WindowContainer<?> child = mChildren.get(i); 4022 pw.println(prefix + "* " + child); 4023 // Only dump non-activity because full activity info is already printed by 4024 // RootWindowContainer#dumpActivities. 4025 if (child.asActivityRecord() == null) { 4026 child.dump(pw, doublePrefix, dumpAll); 4027 } 4028 } 4029 4030 if (!mExitingActivities.isEmpty()) { 4031 pw.println(); 4032 pw.println(prefix + "Exiting application tokens:"); 4033 for (int i = mExitingActivities.size() - 1; i >= 0; i--) { 4034 WindowToken token = mExitingActivities.get(i); 4035 pw.print(doublePrefix + "Exiting App #" + i); 4036 pw.print(' '); pw.print(token); 4037 pw.println(':'); 4038 token.dump(pw, doublePrefix, dumpAll); 4039 } 4040 pw.println(); 4041 } 4042 mAnimatingActivityRegistry.dump(pw, "AnimatingApps:", prefix); 4043 } 4044 4045 4046 /** 4047 * Fills in a {@link TaskInfo} with information from this task. Note that the base intent in the 4048 * task info will not include any extras or clip data. 4049 */ 4050 void fillTaskInfo(TaskInfo info) { 4051 fillTaskInfo(info, true /* stripExtras */); 4052 } 4053 4054 void fillTaskInfo(TaskInfo info, boolean stripExtras) { 4055 fillTaskInfo(info, stripExtras, getDisplayArea()); 4056 } 4057 4058 /** 4059 * Fills in a {@link TaskInfo} with information from this task. 4060 * 4061 * @param tda consider whether this Task can be put in multi window as it will be attached to 4062 * the give {@link TaskDisplayArea}. 4063 */ 4064 void fillTaskInfo(TaskInfo info, boolean stripExtras, @Nullable TaskDisplayArea tda) { 4065 getNumRunningActivities(mReuseActivitiesReport); 4066 info.userId = isLeafTask() ? mUserId : mCurrentUser; 4067 info.taskId = mTaskId; 4068 info.displayId = getDisplayId(); 4069 info.isRunning = getTopNonFinishingActivity() != null; 4070 final Intent baseIntent = getBaseIntent(); 4071 // Make a copy of base intent because this is like a snapshot info. 4072 // Besides, {@link RecentTasks#getRecentTasksImpl} may modify it. 4073 final int baseIntentFlags = baseIntent == null ? 0 : baseIntent.getFlags(); 4074 info.baseIntent = baseIntent == null 4075 ? new Intent() 4076 : stripExtras ? baseIntent.cloneFilter() : new Intent(baseIntent); 4077 info.baseIntent.setFlags(baseIntentFlags); 4078 info.baseActivity = mReuseActivitiesReport.base != null 4079 ? mReuseActivitiesReport.base.intent.getComponent() 4080 : null; 4081 info.topActivity = mReuseActivitiesReport.top != null 4082 ? mReuseActivitiesReport.top.mActivityComponent 4083 : null; 4084 info.origActivity = origActivity; 4085 info.realActivity = realActivity; 4086 info.numActivities = mReuseActivitiesReport.numActivities; 4087 info.lastActiveTime = lastActiveTime; 4088 info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription()); 4089 info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingModeInDisplayArea(tda); 4090 info.supportsMultiWindow = supportsMultiWindowInDisplayArea(tda); 4091 info.configuration.setTo(getConfiguration()); 4092 // Update to the task's current activity type and windowing mode which may differ from the 4093 // window configuration 4094 info.configuration.windowConfiguration.setActivityType(getActivityType()); 4095 info.configuration.windowConfiguration.setWindowingMode(getWindowingMode()); 4096 info.token = mRemoteToken.toWindowContainerToken(); 4097 4098 //TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child 4099 // order changes. 4100 final Task top = getTopMostTask(); 4101 info.resizeMode = top != null ? top.mResizeMode : mResizeMode; 4102 info.topActivityType = top.getActivityType(); 4103 info.isResizeable = isResizeable(); 4104 4105 info.positionInParent = getRelativePosition(); 4106 4107 info.pictureInPictureParams = getPictureInPictureParams(top); 4108 info.displayCutoutInsets = top != null ? top.getDisplayCutoutInsets() : null; 4109 info.topActivityInfo = mReuseActivitiesReport.top != null 4110 ? mReuseActivitiesReport.top.info 4111 : null; 4112 // Whether the direct top activity is in size compat mode on foreground. 4113 info.topActivityInSizeCompat = mReuseActivitiesReport.top != null 4114 && mReuseActivitiesReport.top.getOrganizedTask() == this 4115 && mReuseActivitiesReport.top.inSizeCompatMode() 4116 && mReuseActivitiesReport.top.isState(RESUMED); 4117 info.launchCookies.clear(); 4118 info.addLaunchCookie(mLaunchCookie); 4119 forAllActivities(r -> { 4120 info.addLaunchCookie(r.mLaunchCookie); 4121 }); 4122 final Task rootTask = getRootTask(); 4123 info.parentTaskId = rootTask == getParent() && rootTask.mCreatedByOrganizer 4124 ? rootTask.mTaskId 4125 : INVALID_TASK_ID; 4126 info.isFocused = isFocused(); 4127 info.isVisible = hasVisibleChildren(); 4128 ActivityRecord topRecord = getTopNonFinishingActivity(); 4129 info.mTopActivityLocusId = topRecord != null ? topRecord.getLocusId() : null; 4130 } 4131 4132 @Nullable PictureInPictureParams getPictureInPictureParams() { 4133 return getPictureInPictureParams(getTopMostTask()); 4134 } 4135 4136 private @Nullable PictureInPictureParams getPictureInPictureParams(Task top) { 4137 if (top == null) return null; 4138 final ActivityRecord topVisibleActivity = top.getTopVisibleActivity(); 4139 return (topVisibleActivity == null || topVisibleActivity.pictureInPictureArgs.empty()) 4140 ? null : new PictureInPictureParams(topVisibleActivity.pictureInPictureArgs); 4141 } 4142 4143 Rect getDisplayCutoutInsets() { 4144 if (mDisplayContent == null || getDisplayInfo().displayCutout == null) return null; 4145 final WindowState w = getTopVisibleAppMainWindow(); 4146 final int displayCutoutMode = w == null 4147 ? WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 4148 : w.getAttrs().layoutInDisplayCutoutMode; 4149 return (displayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS 4150 || displayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) 4151 ? null : getDisplayInfo().displayCutout.getSafeInsets(); 4152 } 4153 4154 /** 4155 * Returns a {@link TaskInfo} with information from this task. 4156 */ 4157 ActivityManager.RunningTaskInfo getTaskInfo() { 4158 ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo(); 4159 fillTaskInfo(info); 4160 return info; 4161 } 4162 4163 /** 4164 * Returns a {@link StartingWindowInfo} with information from this task and the target activity. 4165 * @param activity Target activity which to show the starting window. 4166 */ 4167 StartingWindowInfo getStartingWindowInfo(ActivityRecord activity) { 4168 final StartingWindowInfo info = new StartingWindowInfo(); 4169 info.taskInfo = getTaskInfo(); 4170 info.targetActivityInfo = info.taskInfo.topActivityInfo != null 4171 && activity.info != info.taskInfo.topActivityInfo 4172 ? activity.info : null; 4173 info.isKeyguardOccluded = 4174 mAtmService.mKeyguardController.isDisplayOccluded(DEFAULT_DISPLAY); 4175 4176 info.startingWindowTypeParameter = activity.mStartingData.mTypeParams; 4177 final WindowState mainWindow = activity.findMainWindow(); 4178 if (mainWindow != null) { 4179 info.mainWindowLayoutParams = mainWindow.getAttrs(); 4180 } 4181 // If the developer has persist a different configuration, we need to override it to the 4182 // starting window because persisted configuration does not effect to Task. 4183 info.taskInfo.configuration.setTo(activity.getConfiguration()); 4184 final ActivityRecord topFullscreenActivity = getTopFullscreenActivity(); 4185 if (topFullscreenActivity != null) { 4186 final WindowState topFullscreenOpaqueWindow = 4187 topFullscreenActivity.getTopFullscreenOpaqueWindow(); 4188 if (topFullscreenOpaqueWindow != null) { 4189 info.topOpaqueWindowInsetsState = 4190 topFullscreenOpaqueWindow.getInsetsStateWithVisibilityOverride(); 4191 info.topOpaqueWindowLayoutParams = topFullscreenOpaqueWindow.getAttrs(); 4192 } 4193 } 4194 return info; 4195 } 4196 4197 boolean isTaskId(int taskId) { 4198 return mTaskId == taskId; 4199 } 4200 4201 @Override 4202 Task asTask() { 4203 // I'm a task! 4204 return this; 4205 } 4206 4207 /** 4208 * Returns true if the task should be visible. 4209 * 4210 * @param starting The currently starting activity or null if there is none. 4211 */ 4212 boolean shouldBeVisible(ActivityRecord starting) { 4213 return getVisibility(starting) != TASK_VISIBILITY_INVISIBLE; 4214 } 4215 4216 /** 4217 * Returns true if the task should be visible. 4218 * 4219 * @param starting The currently starting activity or null if there is none. 4220 */ 4221 @TaskVisibility 4222 int getVisibility(ActivityRecord starting) { 4223 if (!isAttached() || isForceHidden()) { 4224 return TASK_VISIBILITY_INVISIBLE; 4225 } 4226 4227 if (isTopActivityLaunchedBehind()) { 4228 return TASK_VISIBILITY_VISIBLE; 4229 } 4230 4231 boolean gotRootSplitScreenTask = false; 4232 boolean gotOpaqueSplitScreenPrimary = false; 4233 boolean gotOpaqueSplitScreenSecondary = false; 4234 boolean gotTranslucentFullscreen = false; 4235 boolean gotTranslucentSplitScreenPrimary = false; 4236 boolean gotTranslucentSplitScreenSecondary = false; 4237 boolean shouldBeVisible = true; 4238 4239 // This root task is only considered visible if all its parent root tasks are considered 4240 // visible, so check the visibility of all ancestor root task first. 4241 final WindowContainer parent = getParent(); 4242 if (parent.asTask() != null) { 4243 final int parentVisibility = parent.asTask().getVisibility(starting); 4244 if (parentVisibility == TASK_VISIBILITY_INVISIBLE) { 4245 // Can't be visible if parent isn't visible 4246 return TASK_VISIBILITY_INVISIBLE; 4247 } else if (parentVisibility == TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) { 4248 // Parent is behind a translucent container so the highest visibility this container 4249 // can get is that. 4250 gotTranslucentFullscreen = true; 4251 } 4252 } 4253 4254 final List<Task> adjacentTasks = new ArrayList<>(); 4255 final int windowingMode = getWindowingMode(); 4256 final boolean isAssistantType = isActivityTypeAssistant(); 4257 for (int i = parent.getChildCount() - 1; i >= 0; --i) { 4258 final WindowContainer wc = parent.getChildAt(i); 4259 final Task other = wc.asTask(); 4260 if (other == null) continue; 4261 4262 final boolean hasRunningActivities = other.topRunningActivity() != null; 4263 if (other == this) { 4264 // Should be visible if there is no other stack occluding it, unless it doesn't 4265 // have any running activities, not starting one and not home stack. 4266 shouldBeVisible = hasRunningActivities || isInTask(starting) != null 4267 || isActivityTypeHome(); 4268 break; 4269 } 4270 4271 if (!hasRunningActivities) { 4272 continue; 4273 } 4274 4275 final int otherWindowingMode = other.getWindowingMode(); 4276 4277 if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) { 4278 if (other.isTranslucent(starting)) { 4279 // Can be visible behind a translucent fullscreen stack. 4280 gotTranslucentFullscreen = true; 4281 continue; 4282 } 4283 return TASK_VISIBILITY_INVISIBLE; 4284 } else if (otherWindowingMode == WINDOWING_MODE_MULTI_WINDOW 4285 && other.matchParentBounds()) { 4286 if (other.isTranslucent(starting)) { 4287 // Can be visible behind a translucent task. 4288 gotTranslucentFullscreen = true; 4289 continue; 4290 } 4291 // Multi-window task that matches parent bounds would occlude other children. 4292 return TASK_VISIBILITY_INVISIBLE; 4293 } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY 4294 && !gotOpaqueSplitScreenPrimary) { 4295 gotRootSplitScreenTask = true; 4296 gotTranslucentSplitScreenPrimary = other.isTranslucent(starting); 4297 gotOpaqueSplitScreenPrimary = !gotTranslucentSplitScreenPrimary; 4298 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY 4299 && gotOpaqueSplitScreenPrimary) { 4300 // Can not be visible behind another opaque stack in split-screen-primary mode. 4301 return TASK_VISIBILITY_INVISIBLE; 4302 } 4303 } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY 4304 && !gotOpaqueSplitScreenSecondary) { 4305 gotRootSplitScreenTask = true; 4306 gotTranslucentSplitScreenSecondary = other.isTranslucent(starting); 4307 gotOpaqueSplitScreenSecondary = !gotTranslucentSplitScreenSecondary; 4308 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY 4309 && gotOpaqueSplitScreenSecondary) { 4310 // Can not be visible behind another opaque stack in split-screen-secondary mode. 4311 return TASK_VISIBILITY_INVISIBLE; 4312 } 4313 } 4314 if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) { 4315 // Can not be visible if we are in split-screen windowing mode and both halves of 4316 // the screen are opaque. 4317 return TASK_VISIBILITY_INVISIBLE; 4318 } 4319 if (isAssistantType && gotRootSplitScreenTask) { 4320 // Assistant stack can't be visible behind split-screen. In addition to this not 4321 // making sense, it also works around an issue here we boost the z-order of the 4322 // assistant window surfaces in window manager whenever it is visible. 4323 return TASK_VISIBILITY_INVISIBLE; 4324 } 4325 if (other.mAdjacentTask != null) { 4326 if (adjacentTasks.contains(other.mAdjacentTask)) { 4327 if (other.isTranslucent(starting) 4328 || other.mAdjacentTask.isTranslucent(starting)) { 4329 // Can be visible behind a translucent adjacent tasks. 4330 gotTranslucentFullscreen = true; 4331 continue; 4332 } 4333 // Can not be visible behind adjacent tasks. 4334 return TASK_VISIBILITY_INVISIBLE; 4335 } else { 4336 adjacentTasks.add(other); 4337 } 4338 } 4339 } 4340 4341 if (!shouldBeVisible) { 4342 return TASK_VISIBILITY_INVISIBLE; 4343 } 4344 4345 // Handle cases when there can be a translucent split-screen stack on top. 4346 switch (windowingMode) { 4347 case WINDOWING_MODE_FULLSCREEN: 4348 if (gotTranslucentSplitScreenPrimary || gotTranslucentSplitScreenSecondary) { 4349 // At least one of the split-screen stacks that covers this one is translucent. 4350 // When in split mode, home task will be reparented to the secondary split while 4351 // leaving tasks not supporting split below. Due to 4352 // TaskDisplayArea#assignRootTaskOrdering always adjusts home surface layer to 4353 // the bottom, this makes sure tasks not in split roots won't occlude home task 4354 // unexpectedly. 4355 return TASK_VISIBILITY_INVISIBLE; 4356 } 4357 break; 4358 case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: 4359 if (gotTranslucentSplitScreenPrimary) { 4360 // Covered by translucent primary split-screen on top. 4361 return TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; 4362 } 4363 break; 4364 case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: 4365 if (gotTranslucentSplitScreenSecondary) { 4366 // Covered by translucent secondary split-screen on top. 4367 return TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; 4368 } 4369 break; 4370 } 4371 4372 // Lastly - check if there is a translucent fullscreen stack on top. 4373 return gotTranslucentFullscreen ? TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT 4374 : TASK_VISIBILITY_VISIBLE; 4375 } 4376 4377 private boolean isTopActivityLaunchedBehind() { 4378 final ActivityRecord top = topRunningActivity(); 4379 if (top != null && top.mLaunchTaskBehind) { 4380 return true; 4381 } 4382 return false; 4383 } 4384 4385 ActivityRecord isInTask(ActivityRecord r) { 4386 if (r == null) { 4387 return null; 4388 } 4389 if (r.isDescendantOf(this)) { 4390 return r; 4391 } 4392 return null; 4393 } 4394 4395 void dump(PrintWriter pw, String prefix) { 4396 pw.print(prefix); pw.print("userId="); pw.print(mUserId); 4397 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid); 4398 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid); 4399 pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete); 4400 pw.print(" mCallingPackage="); pw.print(mCallingPackage); 4401 pw.print(" mCallingFeatureId="); pw.println(mCallingFeatureId); 4402 if (affinity != null || rootAffinity != null) { 4403 pw.print(prefix); pw.print("affinity="); pw.print(affinity); 4404 if (affinity == null || !affinity.equals(rootAffinity)) { 4405 pw.print(" root="); pw.println(rootAffinity); 4406 } else { 4407 pw.println(); 4408 } 4409 } 4410 if (mWindowLayoutAffinity != null) { 4411 pw.print(prefix); pw.print("windowLayoutAffinity="); pw.println(mWindowLayoutAffinity); 4412 } 4413 if (voiceSession != null || voiceInteractor != null) { 4414 pw.print(prefix); pw.print("VOICE: session=0x"); 4415 pw.print(Integer.toHexString(System.identityHashCode(voiceSession))); 4416 pw.print(" interactor=0x"); 4417 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor))); 4418 } 4419 if (intent != null) { 4420 StringBuilder sb = new StringBuilder(128); 4421 sb.append(prefix); sb.append("intent={"); 4422 intent.toShortString(sb, false, true, false, false); 4423 sb.append('}'); 4424 pw.println(sb.toString()); 4425 } 4426 if (affinityIntent != null) { 4427 StringBuilder sb = new StringBuilder(128); 4428 sb.append(prefix); sb.append("affinityIntent={"); 4429 affinityIntent.toShortString(sb, false, true, false, false); 4430 sb.append('}'); 4431 pw.println(sb.toString()); 4432 } 4433 if (origActivity != null) { 4434 pw.print(prefix); pw.print("origActivity="); 4435 pw.println(origActivity.flattenToShortString()); 4436 } 4437 if (realActivity != null) { 4438 pw.print(prefix); pw.print("mActivityComponent="); 4439 pw.println(realActivity.flattenToShortString()); 4440 } 4441 if (autoRemoveRecents || isPersistable || !isActivityTypeStandard()) { 4442 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents); 4443 pw.print(" isPersistable="); pw.print(isPersistable); 4444 pw.print(" activityType="); pw.println(getActivityType()); 4445 } 4446 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask 4447 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) { 4448 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset); 4449 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity); 4450 pw.print(" mReuseTask="); pw.print(mReuseTask); 4451 pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString()); 4452 } 4453 if (mAffiliatedTaskId != mTaskId || mPrevAffiliateTaskId != INVALID_TASK_ID 4454 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID 4455 || mNextAffiliate != null) { 4456 pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId); 4457 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId); 4458 pw.print(" ("); 4459 if (mPrevAffiliate == null) { 4460 pw.print("null"); 4461 } else { 4462 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate))); 4463 } 4464 pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId); 4465 pw.print(" ("); 4466 if (mNextAffiliate == null) { 4467 pw.print("null"); 4468 } else { 4469 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate))); 4470 } 4471 pw.println(")"); 4472 } 4473 pw.print(prefix); pw.print("Activities="); pw.println(mChildren); 4474 if (!askedCompatMode || !inRecents || !isAvailable) { 4475 pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode); 4476 pw.print(" inRecents="); pw.print(inRecents); 4477 pw.print(" isAvailable="); pw.println(isAvailable); 4478 } 4479 if (lastDescription != null) { 4480 pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription); 4481 } 4482 if (mRootProcess != null) { 4483 pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess); 4484 } 4485 pw.print(prefix); pw.print("taskId=" + mTaskId); 4486 pw.println(" rootTaskId=" + getRootTaskId()); 4487 pw.print(prefix); pw.println("hasChildPipActivity=" + (mChildPipActivity != null)); 4488 pw.print(prefix); pw.print("mHasBeenVisible="); pw.println(getHasBeenVisible()); 4489 pw.print(prefix); pw.print("mResizeMode="); 4490 pw.print(ActivityInfo.resizeModeToString(mResizeMode)); 4491 pw.print(" mSupportsPictureInPicture="); pw.print(mSupportsPictureInPicture); 4492 pw.print(" isResizeable="); pw.println(isResizeable()); 4493 pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime); 4494 pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)"); 4495 if (mForceNotOrganized) { 4496 pw.print(prefix); pw.println("mForceNotOrganized=true"); 4497 } 4498 } 4499 4500 @Override 4501 public String toString() { 4502 StringBuilder sb = new StringBuilder(128); 4503 if (stringName != null) { 4504 sb.append(stringName); 4505 sb.append(" U="); 4506 sb.append(mUserId); 4507 final Task rootTask = getRootTask(); 4508 if (rootTask != this) { 4509 sb.append(" rootTaskId="); 4510 sb.append(rootTask.mTaskId); 4511 } 4512 sb.append(" visible="); 4513 sb.append(shouldBeVisible(null /* starting */)); 4514 sb.append(" mode="); 4515 sb.append(windowingModeToString(getWindowingMode())); 4516 sb.append(" translucent="); 4517 sb.append(isTranslucent(null /* starting */)); 4518 sb.append(" sz="); 4519 sb.append(getChildCount()); 4520 sb.append('}'); 4521 return sb.toString(); 4522 } 4523 sb.append("Task{"); 4524 sb.append(Integer.toHexString(System.identityHashCode(this))); 4525 sb.append(" #"); 4526 sb.append(mTaskId); 4527 sb.append(" type=" + activityTypeToString(getActivityType())); 4528 if (affinity != null) { 4529 sb.append(" A="); 4530 sb.append(affinity); 4531 } else if (intent != null && intent.getComponent() != null) { 4532 sb.append(" I="); 4533 sb.append(intent.getComponent().flattenToShortString()); 4534 } else if (affinityIntent != null && affinityIntent.getComponent() != null) { 4535 sb.append(" aI="); 4536 sb.append(affinityIntent.getComponent().flattenToShortString()); 4537 } else { 4538 sb.append(" ??"); 4539 } 4540 stringName = sb.toString(); 4541 return toString(); 4542 } 4543 4544 /** @see #getNumRunningActivities(TaskActivitiesReport) */ 4545 static class TaskActivitiesReport implements Consumer<ActivityRecord> { 4546 int numRunning; 4547 int numActivities; 4548 ActivityRecord top; 4549 ActivityRecord base; 4550 4551 void reset() { 4552 numRunning = numActivities = 0; 4553 top = base = null; 4554 } 4555 4556 @Override 4557 public void accept(ActivityRecord r) { 4558 if (r.finishing) { 4559 return; 4560 } 4561 4562 base = r; 4563 4564 // Increment the total number of non-finishing activities 4565 numActivities++; 4566 4567 if (top == null || (top.isState(ActivityState.INITIALIZING))) { 4568 top = r; 4569 // Reset the number of running activities until we hit the first non-initializing 4570 // activity 4571 numRunning = 0; 4572 } 4573 if (r.attachedToProcess()) { 4574 // Increment the number of actually running activities 4575 numRunning++; 4576 } 4577 } 4578 } 4579 4580 /** 4581 * Saves this {@link Task} to XML using given serializer. 4582 */ 4583 void saveToXml(TypedXmlSerializer out) throws Exception { 4584 if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this); 4585 4586 out.attributeInt(null, ATTR_TASKID, mTaskId); 4587 if (realActivity != null) { 4588 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString()); 4589 } 4590 out.attributeBoolean(null, ATTR_REALACTIVITY_SUSPENDED, realActivitySuspended); 4591 if (origActivity != null) { 4592 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString()); 4593 } 4594 // Write affinity, and root affinity if it is different from affinity. 4595 // We use the special string "@" for a null root affinity, so we can identify 4596 // later whether we were given a root affinity or should just make it the 4597 // same as the affinity. 4598 if (affinity != null) { 4599 out.attribute(null, ATTR_AFFINITY, affinity); 4600 if (!affinity.equals(rootAffinity)) { 4601 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 4602 } 4603 } else if (rootAffinity != null) { 4604 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 4605 } 4606 if (mWindowLayoutAffinity != null) { 4607 out.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity); 4608 } 4609 out.attributeBoolean(null, ATTR_ROOTHASRESET, rootWasReset); 4610 out.attributeBoolean(null, ATTR_AUTOREMOVERECENTS, autoRemoveRecents); 4611 out.attributeBoolean(null, ATTR_ASKEDCOMPATMODE, askedCompatMode); 4612 out.attributeInt(null, ATTR_USERID, mUserId); 4613 out.attributeBoolean(null, ATTR_USER_SETUP_COMPLETE, mUserSetupComplete); 4614 out.attributeInt(null, ATTR_EFFECTIVE_UID, effectiveUid); 4615 out.attributeLong(null, ATTR_LASTTIMEMOVED, mLastTimeMoved); 4616 out.attributeBoolean(null, ATTR_NEVERRELINQUISH, mNeverRelinquishIdentity); 4617 if (lastDescription != null) { 4618 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); 4619 } 4620 if (getTaskDescription() != null) { 4621 getTaskDescription().saveToXml(out); 4622 } 4623 out.attributeInt(null, ATTR_TASK_AFFILIATION, mAffiliatedTaskId); 4624 out.attributeInt(null, ATTR_PREV_AFFILIATION, mPrevAffiliateTaskId); 4625 out.attributeInt(null, ATTR_NEXT_AFFILIATION, mNextAffiliateTaskId); 4626 out.attributeInt(null, ATTR_CALLING_UID, mCallingUid); 4627 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage); 4628 out.attribute(null, ATTR_CALLING_FEATURE_ID, 4629 mCallingFeatureId == null ? "" : mCallingFeatureId); 4630 out.attributeInt(null, ATTR_RESIZE_MODE, mResizeMode); 4631 out.attributeBoolean(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE, mSupportsPictureInPicture); 4632 if (mLastNonFullscreenBounds != null) { 4633 out.attribute( 4634 null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString()); 4635 } 4636 out.attributeInt(null, ATTR_MIN_WIDTH, mMinWidth); 4637 out.attributeInt(null, ATTR_MIN_HEIGHT, mMinHeight); 4638 out.attributeInt(null, ATTR_PERSIST_TASK_VERSION, PERSIST_TASK_VERSION); 4639 4640 if (mLastTaskSnapshotData.taskSize != null) { 4641 out.attribute(null, ATTR_LAST_SNAPSHOT_TASK_SIZE, 4642 mLastTaskSnapshotData.taskSize.flattenToString()); 4643 } 4644 if (mLastTaskSnapshotData.contentInsets != null) { 4645 out.attribute(null, ATTR_LAST_SNAPSHOT_CONTENT_INSETS, 4646 mLastTaskSnapshotData.contentInsets.flattenToString()); 4647 } 4648 if (mLastTaskSnapshotData.bufferSize != null) { 4649 out.attribute(null, ATTR_LAST_SNAPSHOT_BUFFER_SIZE, 4650 mLastTaskSnapshotData.bufferSize.flattenToString()); 4651 } 4652 4653 if (affinityIntent != null) { 4654 out.startTag(null, TAG_AFFINITYINTENT); 4655 affinityIntent.saveToXml(out); 4656 out.endTag(null, TAG_AFFINITYINTENT); 4657 } 4658 4659 if (intent != null) { 4660 out.startTag(null, TAG_INTENT); 4661 intent.saveToXml(out); 4662 out.endTag(null, TAG_INTENT); 4663 } 4664 4665 sTmpException = null; 4666 final PooledFunction f = PooledLambda.obtainFunction(Task::saveActivityToXml, 4667 PooledLambda.__(ActivityRecord.class), getBottomMostActivity(), out); 4668 forAllActivities(f); 4669 f.recycle(); 4670 if (sTmpException != null) { 4671 throw sTmpException; 4672 } 4673 } 4674 4675 private static boolean saveActivityToXml( 4676 ActivityRecord r, ActivityRecord first, TypedXmlSerializer out) { 4677 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() 4678 || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT 4679 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) 4680 && r != first) { 4681 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET). 4682 return true; 4683 } 4684 try { 4685 out.startTag(null, TAG_ACTIVITY); 4686 r.saveToXml(out); 4687 out.endTag(null, TAG_ACTIVITY); 4688 return false; 4689 } catch (Exception e) { 4690 sTmpException = e; 4691 return true; 4692 } 4693 } 4694 4695 static Task restoreFromXml(TypedXmlPullParser in, ActivityTaskSupervisor taskSupervisor) 4696 throws IOException, XmlPullParserException { 4697 Intent intent = null; 4698 Intent affinityIntent = null; 4699 ArrayList<ActivityRecord> activities = new ArrayList<>(); 4700 ComponentName realActivity = null; 4701 boolean realActivitySuspended = false; 4702 ComponentName origActivity = null; 4703 String affinity = null; 4704 String rootAffinity = null; 4705 boolean hasRootAffinity = false; 4706 String windowLayoutAffinity = null; 4707 boolean rootHasReset = false; 4708 boolean autoRemoveRecents = false; 4709 boolean askedCompatMode = false; 4710 int taskType = 0; 4711 int userId = 0; 4712 boolean userSetupComplete = true; 4713 int effectiveUid = -1; 4714 String lastDescription = null; 4715 long lastTimeOnTop = 0; 4716 boolean neverRelinquishIdentity = true; 4717 int taskId = INVALID_TASK_ID; 4718 final int outerDepth = in.getDepth(); 4719 TaskDescription taskDescription = new TaskDescription(); 4720 PersistedTaskSnapshotData lastSnapshotData = new PersistedTaskSnapshotData(); 4721 int taskAffiliation = INVALID_TASK_ID; 4722 int prevTaskId = INVALID_TASK_ID; 4723 int nextTaskId = INVALID_TASK_ID; 4724 int callingUid = -1; 4725 String callingPackage = ""; 4726 String callingFeatureId = null; 4727 int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; 4728 boolean supportsPictureInPicture = false; 4729 Rect lastNonFullscreenBounds = null; 4730 int minWidth = INVALID_MIN_SIZE; 4731 int minHeight = INVALID_MIN_SIZE; 4732 int persistTaskVersion = 0; 4733 4734 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { 4735 final String attrName = in.getAttributeName(attrNdx); 4736 final String attrValue = in.getAttributeValue(attrNdx); 4737 if (TaskPersister.DEBUG) { 4738 Slog.d(TaskPersister.TAG, "Task: attribute name=" + attrName + " value=" 4739 + attrValue); 4740 } 4741 switch (attrName) { 4742 case ATTR_TASKID: 4743 if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue); 4744 break; 4745 case ATTR_REALACTIVITY: 4746 realActivity = ComponentName.unflattenFromString(attrValue); 4747 break; 4748 case ATTR_REALACTIVITY_SUSPENDED: 4749 realActivitySuspended = Boolean.valueOf(attrValue); 4750 break; 4751 case ATTR_ORIGACTIVITY: 4752 origActivity = ComponentName.unflattenFromString(attrValue); 4753 break; 4754 case ATTR_AFFINITY: 4755 affinity = attrValue; 4756 break; 4757 case ATTR_ROOT_AFFINITY: 4758 rootAffinity = attrValue; 4759 hasRootAffinity = true; 4760 break; 4761 case ATTR_WINDOW_LAYOUT_AFFINITY: 4762 windowLayoutAffinity = attrValue; 4763 break; 4764 case ATTR_ROOTHASRESET: 4765 rootHasReset = Boolean.parseBoolean(attrValue); 4766 break; 4767 case ATTR_AUTOREMOVERECENTS: 4768 autoRemoveRecents = Boolean.parseBoolean(attrValue); 4769 break; 4770 case ATTR_ASKEDCOMPATMODE: 4771 askedCompatMode = Boolean.parseBoolean(attrValue); 4772 break; 4773 case ATTR_USERID: 4774 userId = Integer.parseInt(attrValue); 4775 break; 4776 case ATTR_USER_SETUP_COMPLETE: 4777 userSetupComplete = Boolean.parseBoolean(attrValue); 4778 break; 4779 case ATTR_EFFECTIVE_UID: 4780 effectiveUid = Integer.parseInt(attrValue); 4781 break; 4782 case ATTR_TASKTYPE: 4783 taskType = Integer.parseInt(attrValue); 4784 break; 4785 case ATTR_LASTDESCRIPTION: 4786 lastDescription = attrValue; 4787 break; 4788 case ATTR_LASTTIMEMOVED: 4789 lastTimeOnTop = Long.parseLong(attrValue); 4790 break; 4791 case ATTR_NEVERRELINQUISH: 4792 neverRelinquishIdentity = Boolean.parseBoolean(attrValue); 4793 break; 4794 case ATTR_TASK_AFFILIATION: 4795 taskAffiliation = Integer.parseInt(attrValue); 4796 break; 4797 case ATTR_PREV_AFFILIATION: 4798 prevTaskId = Integer.parseInt(attrValue); 4799 break; 4800 case ATTR_NEXT_AFFILIATION: 4801 nextTaskId = Integer.parseInt(attrValue); 4802 break; 4803 case ATTR_CALLING_UID: 4804 callingUid = Integer.parseInt(attrValue); 4805 break; 4806 case ATTR_CALLING_PACKAGE: 4807 callingPackage = attrValue; 4808 break; 4809 case ATTR_CALLING_FEATURE_ID: 4810 callingFeatureId = attrValue; 4811 break; 4812 case ATTR_RESIZE_MODE: 4813 resizeMode = Integer.parseInt(attrValue); 4814 break; 4815 case ATTR_SUPPORTS_PICTURE_IN_PICTURE: 4816 supportsPictureInPicture = Boolean.parseBoolean(attrValue); 4817 break; 4818 case ATTR_NON_FULLSCREEN_BOUNDS: 4819 lastNonFullscreenBounds = Rect.unflattenFromString(attrValue); 4820 break; 4821 case ATTR_MIN_WIDTH: 4822 minWidth = Integer.parseInt(attrValue); 4823 break; 4824 case ATTR_MIN_HEIGHT: 4825 minHeight = Integer.parseInt(attrValue); 4826 break; 4827 case ATTR_PERSIST_TASK_VERSION: 4828 persistTaskVersion = Integer.parseInt(attrValue); 4829 break; 4830 case ATTR_LAST_SNAPSHOT_TASK_SIZE: 4831 lastSnapshotData.taskSize = Point.unflattenFromString(attrValue); 4832 break; 4833 case ATTR_LAST_SNAPSHOT_CONTENT_INSETS: 4834 lastSnapshotData.contentInsets = Rect.unflattenFromString(attrValue); 4835 break; 4836 case ATTR_LAST_SNAPSHOT_BUFFER_SIZE: 4837 lastSnapshotData.bufferSize = Point.unflattenFromString(attrValue); 4838 break; 4839 default: 4840 if (!attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) { 4841 Slog.w(TAG, "Task: Unknown attribute=" + attrName); 4842 } 4843 } 4844 } 4845 taskDescription.restoreFromXml(in); 4846 4847 int event; 4848 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) 4849 && (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) { 4850 if (event == XmlPullParser.START_TAG) { 4851 final String name = in.getName(); 4852 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: START_TAG name=" + name); 4853 if (TAG_AFFINITYINTENT.equals(name)) { 4854 affinityIntent = Intent.restoreFromXml(in); 4855 } else if (TAG_INTENT.equals(name)) { 4856 intent = Intent.restoreFromXml(in); 4857 } else if (TAG_ACTIVITY.equals(name)) { 4858 ActivityRecord activity = 4859 ActivityRecord.restoreFromXml(in, taskSupervisor); 4860 if (TaskPersister.DEBUG) { 4861 Slog.d(TaskPersister.TAG, "Task: activity=" + activity); 4862 } 4863 if (activity != null) { 4864 activities.add(activity); 4865 } 4866 } else { 4867 Slog.e(TAG, "restoreTask: Unexpected name=" + name); 4868 XmlUtils.skipCurrentTag(in); 4869 } 4870 } 4871 } 4872 if (!hasRootAffinity) { 4873 rootAffinity = affinity; 4874 } else if ("@".equals(rootAffinity)) { 4875 rootAffinity = null; 4876 } 4877 if (effectiveUid <= 0) { 4878 Intent checkIntent = intent != null ? intent : affinityIntent; 4879 effectiveUid = 0; 4880 if (checkIntent != null) { 4881 IPackageManager pm = AppGlobals.getPackageManager(); 4882 try { 4883 ApplicationInfo ai = pm.getApplicationInfo( 4884 checkIntent.getComponent().getPackageName(), 4885 PackageManager.MATCH_UNINSTALLED_PACKAGES 4886 | PackageManager.MATCH_DISABLED_COMPONENTS, userId); 4887 if (ai != null) { 4888 effectiveUid = ai.uid; 4889 } 4890 } catch (RemoteException e) { 4891 } 4892 } 4893 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent 4894 + ": effectiveUid=" + effectiveUid); 4895 } 4896 4897 if (persistTaskVersion < 1) { 4898 // We need to convert the resize mode of home activities saved before version one if 4899 // they are marked as RESIZE_MODE_RESIZEABLE to 4900 // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation 4901 // before version 1 and the system didn't resize home activities before then. 4902 if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) { 4903 resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 4904 } 4905 } else { 4906 // This activity has previously marked itself explicitly as both resizeable and 4907 // supporting picture-in-picture. Since there is no longer a requirement for 4908 // picture-in-picture activities to be resizeable, we can mark this simply as 4909 // resizeable and supporting picture-in-picture separately. 4910 if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) { 4911 resizeMode = RESIZE_MODE_RESIZEABLE; 4912 supportsPictureInPicture = true; 4913 } 4914 } 4915 4916 final Task task = new Task.Builder(taskSupervisor.mService) 4917 .setTaskId(taskId) 4918 .setIntent(intent) 4919 .setAffinityIntent(affinityIntent) 4920 .setAffinity(affinity) 4921 .setRootAffinity(rootAffinity) 4922 .setRealActivity(realActivity) 4923 .setOrigActivity(origActivity) 4924 .setRootWasReset(rootHasReset) 4925 .setAutoRemoveRecents(autoRemoveRecents) 4926 .setAskedCompatMode(askedCompatMode) 4927 .setUserId(userId) 4928 .setEffectiveUid(effectiveUid) 4929 .setLastDescription(lastDescription) 4930 .setLastTimeMoved(lastTimeOnTop) 4931 .setNeverRelinquishIdentity(neverRelinquishIdentity) 4932 .setLastTaskDescription(taskDescription) 4933 .setLastSnapshotData(lastSnapshotData) 4934 .setTaskAffiliation(taskAffiliation) 4935 .setPrevAffiliateTaskId(prevTaskId) 4936 .setNextAffiliateTaskId(nextTaskId) 4937 .setCallingUid(callingUid) 4938 .setCallingPackage(callingPackage) 4939 .setCallingFeatureId(callingFeatureId) 4940 .setResizeMode(resizeMode) 4941 .setSupportsPictureInPicture(supportsPictureInPicture) 4942 .setRealActivitySuspended(realActivitySuspended) 4943 .setUserSetupComplete(userSetupComplete) 4944 .setMinWidth(minWidth) 4945 .setMinHeight(minHeight) 4946 .buildInner(); 4947 task.mLastNonFullscreenBounds = lastNonFullscreenBounds; 4948 task.setBounds(lastNonFullscreenBounds); 4949 task.mWindowLayoutAffinity = windowLayoutAffinity; 4950 if (activities.size() > 0) { 4951 // We need to add the task into hierarchy before adding child to it. 4952 final DisplayContent dc = 4953 taskSupervisor.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY); 4954 dc.getDefaultTaskDisplayArea().addChild(task, POSITION_BOTTOM); 4955 4956 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { 4957 task.addChild(activities.get(activityNdx)); 4958 } 4959 } 4960 4961 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task); 4962 return task; 4963 } 4964 4965 @Override 4966 boolean isOrganized() { 4967 return mTaskOrganizer != null; 4968 } 4969 4970 private boolean canBeOrganized() { 4971 if (mForceNotOrganized || !mAtmService.mTaskOrganizerController 4972 .isSupportedWindowingMode(getWindowingMode())) { 4973 return false; 4974 } 4975 // All root tasks can be organized 4976 if (isRootTask()) { 4977 return true; 4978 } 4979 4980 // Task could be organized if it's the direct child of the root created by organizer. 4981 final Task rootTask = getRootTask(); 4982 return rootTask == getParent() && rootTask.mCreatedByOrganizer; 4983 } 4984 4985 @Override 4986 boolean showSurfaceOnCreation() { 4987 if (mCreatedByOrganizer) { 4988 // Tasks created by the organizer are default visible because they can synchronously 4989 // update the leash before new children are added to the task. 4990 return true; 4991 } 4992 // Organized tasks handle their own surface visibility 4993 return !canBeOrganized(); 4994 } 4995 4996 @Override 4997 protected void reparentSurfaceControl(SurfaceControl.Transaction t, SurfaceControl newParent) { 4998 /** 4999 * Avoid reparenting SurfaceControl of the organized tasks that are always on top, since 5000 * the surfaces should be controlled by the organizer itself, like bubbles. 5001 */ 5002 if (isOrganized() && isAlwaysOnTop()) { 5003 return; 5004 } 5005 super.reparentSurfaceControl(t, newParent); 5006 } 5007 5008 void setHasBeenVisible(boolean hasBeenVisible) { 5009 mHasBeenVisible = hasBeenVisible; 5010 if (hasBeenVisible) { 5011 if (!mDeferTaskAppear) sendTaskAppeared(); 5012 if (!isRootTask()) { 5013 getRootTask().setHasBeenVisible(true); 5014 } 5015 } 5016 } 5017 5018 boolean getHasBeenVisible() { 5019 return mHasBeenVisible; 5020 } 5021 5022 void setDeferTaskAppear(boolean deferTaskAppear) { 5023 mDeferTaskAppear = deferTaskAppear; 5024 if (!mDeferTaskAppear) { 5025 sendTaskAppeared(); 5026 } 5027 } 5028 5029 /** In the case that these conditions are true, we want to send the Task to the organizer: 5030 * 1. An organizer has been set 5031 * 2. The Task was created by the organizer 5032 * or 5033 * 2a. We have a SurfaceControl 5034 * 2b. We have finished drawing 5035 * Any time any of these conditions are updated, the updating code should call 5036 * sendTaskAppeared. 5037 */ 5038 boolean taskAppearedReady() { 5039 if (mTaskOrganizer == null) { 5040 return false; 5041 } 5042 5043 if (mDeferTaskAppear) { 5044 return false; 5045 } 5046 5047 if (mCreatedByOrganizer) { 5048 return true; 5049 } 5050 5051 return mSurfaceControl != null && getHasBeenVisible(); 5052 } 5053 5054 private void sendTaskAppeared() { 5055 if (mTaskOrganizer != null) { 5056 mAtmService.mTaskOrganizerController.onTaskAppeared(mTaskOrganizer, this); 5057 } 5058 } 5059 5060 private void sendTaskVanished(ITaskOrganizer organizer) { 5061 if (organizer != null) { 5062 mAtmService.mTaskOrganizerController.onTaskVanished(organizer, this); 5063 } 5064 } 5065 5066 @VisibleForTesting 5067 boolean setTaskOrganizer(ITaskOrganizer organizer) { 5068 return setTaskOrganizer(organizer, false /* skipTaskAppeared */); 5069 } 5070 5071 @VisibleForTesting 5072 boolean setTaskOrganizer(ITaskOrganizer organizer, boolean skipTaskAppeared) { 5073 if (mTaskOrganizer == organizer) { 5074 return false; 5075 } 5076 5077 ITaskOrganizer prevOrganizer = mTaskOrganizer; 5078 // Update the new task organizer before calling sendTaskVanished since it could result in 5079 // a new SurfaceControl getting created that would notify the old organizer about it. 5080 mTaskOrganizer = organizer; 5081 // Let the old organizer know it has lost control. 5082 sendTaskVanished(prevOrganizer); 5083 5084 if (mTaskOrganizer != null) { 5085 if (!skipTaskAppeared) { 5086 sendTaskAppeared(); 5087 } 5088 } else { 5089 // No longer managed by any organizer. 5090 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 5091 if (taskDisplayArea != null) { 5092 taskDisplayArea.removeLaunchRootTask(this); 5093 } 5094 setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */); 5095 if (mCreatedByOrganizer) { 5096 removeImmediately("setTaskOrganizer"); 5097 } 5098 } 5099 5100 return true; 5101 } 5102 5103 boolean updateTaskOrganizerState(boolean forceUpdate) { 5104 return updateTaskOrganizerState(forceUpdate, false /* skipTaskAppeared */); 5105 } 5106 5107 /** 5108 * Called when the task state changes (ie. from windowing mode change) an the task organizer 5109 * state should also be updated. 5110 * 5111 * @param forceUpdate Updates the task organizer to the one currently specified in the task 5112 * org controller for the task's windowing mode, ignoring the cached 5113 * windowing mode checks. 5114 * @param skipTaskAppeared Skips calling taskAppeared for the new organizer if it has changed 5115 * @return {@code true} if task organizer changed. 5116 */ 5117 boolean updateTaskOrganizerState(boolean forceUpdate, boolean skipTaskAppeared) { 5118 if (getSurfaceControl() == null) { 5119 // Can't call onTaskAppeared without a surfacecontrol, so defer this until next one 5120 // is created. 5121 return false; 5122 } 5123 if (!canBeOrganized()) { 5124 return setTaskOrganizer(null); 5125 } 5126 5127 final int windowingMode = getWindowingMode(); 5128 final TaskOrganizerController controller = mWmService.mAtmService.mTaskOrganizerController; 5129 final ITaskOrganizer organizer = controller.getTaskOrganizer(windowingMode); 5130 if (!forceUpdate && mTaskOrganizer == organizer) { 5131 return false; 5132 } 5133 return setTaskOrganizer(organizer, skipTaskAppeared); 5134 } 5135 5136 @Override 5137 void setSurfaceControl(SurfaceControl sc) { 5138 super.setSurfaceControl(sc); 5139 // If the TaskOrganizer was set before we created the SurfaceControl, we need to 5140 // emit the callbacks now. 5141 sendTaskAppeared(); 5142 } 5143 5144 /** 5145 * @return true if the task is currently focused. 5146 */ 5147 private boolean isFocused() { 5148 if (mDisplayContent == null || mDisplayContent.mCurrentFocus == null) { 5149 return false; 5150 } 5151 return mDisplayContent.mCurrentFocus.getTask() == this; 5152 } 5153 5154 /** 5155 * @return true if the task is visible and has at least one visible child. 5156 */ 5157 private boolean hasVisibleChildren() { 5158 if (!isAttached() || isForceHidden()) { 5159 return false; 5160 } 5161 5162 return getActivity(ActivityRecord::isVisible) != null; 5163 } 5164 5165 /** 5166 * @return the desired shadow radius in pixels for the current task. 5167 */ 5168 private float getShadowRadius(boolean taskIsFocused) { 5169 int elevation = 0; 5170 5171 // Get elevation for a specific windowing mode. 5172 if (inPinnedWindowingMode()) { 5173 elevation = PINNED_WINDOWING_MODE_ELEVATION_IN_DIP; 5174 } else if (inFreeformWindowingMode()) { 5175 elevation = taskIsFocused 5176 ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; 5177 } else { 5178 // For all other windowing modes, do not draw a shadow. 5179 return 0; 5180 } 5181 5182 // If the task has no visible children, do not draw a shadow. 5183 if (!hasVisibleChildren()) { 5184 return 0; 5185 } 5186 5187 return dipToPixel(elevation, getDisplayContent().getDisplayMetrics()); 5188 } 5189 5190 /** 5191 * Update the length of the shadow if needed based on windowing mode and task focus state. 5192 */ 5193 private void updateShadowsRadius(boolean taskIsFocused, 5194 SurfaceControl.Transaction pendingTransaction) { 5195 if (!mWmService.mRenderShadowsInCompositor || !isRootTask()) return; 5196 5197 final float newShadowRadius = getShadowRadius(taskIsFocused); 5198 if (mShadowRadius != newShadowRadius) { 5199 mShadowRadius = newShadowRadius; 5200 pendingTransaction.setShadowRadius(getSurfaceControl(), mShadowRadius); 5201 } 5202 } 5203 5204 /** 5205 * Called on the task of a window which gained or lost focus. 5206 * @param hasFocus 5207 */ 5208 void onWindowFocusChanged(boolean hasFocus) { 5209 updateShadowsRadius(hasFocus, getSyncTransaction()); 5210 // TODO(b/180525887): Un-comment once there is resolution on the bug. 5211 // dispatchTaskInfoChangedIfNeeded(false /* force */); 5212 } 5213 5214 void onPictureInPictureParamsChanged() { 5215 if (inPinnedWindowingMode()) { 5216 dispatchTaskInfoChangedIfNeeded(true /* force */); 5217 } 5218 } 5219 5220 /** Called when the top activity in the Root Task enters or exits size compat mode. */ 5221 void onSizeCompatActivityChanged() { 5222 // Trigger TaskInfoChanged to update the size compat restart button. 5223 dispatchTaskInfoChangedIfNeeded(true /* force */); 5224 } 5225 5226 /** 5227 * See {@link WindowContainerTransaction#setBoundsChangeTransaction}. In short this 5228 * transaction will be consumed by the next BASE_APPLICATION window within our hierarchy 5229 * to resize, and it will defer the transaction until that resize frame completes. 5230 */ 5231 void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t) { 5232 setMainWindowSizeChangeTransaction(t, this); 5233 forAllWindows(WindowState::requestRedrawForSync, true); 5234 } 5235 5236 private void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t, Task origin) { 5237 // This is only meaningful on an activity's task, so put it on the top one. 5238 ActivityRecord topActivity = getTopNonFinishingActivity(); 5239 Task leaf = topActivity != null ? topActivity.getTask() : null; 5240 if (leaf == null) { 5241 return; 5242 } 5243 if (leaf != this) { 5244 leaf.setMainWindowSizeChangeTransaction(t, origin); 5245 return; 5246 } 5247 mMainWindowSizeChangeTransaction = t; 5248 mMainWindowSizeChangeTask = t == null ? null : origin; 5249 } 5250 5251 SurfaceControl.Transaction getMainWindowSizeChangeTransaction() { 5252 return mMainWindowSizeChangeTransaction; 5253 } 5254 5255 Task getMainWindowSizeChangeTask() { 5256 return mMainWindowSizeChangeTask; 5257 } 5258 5259 void setActivityWindowingMode(int windowingMode) { 5260 PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setWindowingMode, 5261 PooledLambda.__(ActivityRecord.class), windowingMode); 5262 forAllActivities(c); 5263 c.recycle(); 5264 } 5265 5266 /** 5267 * Sets/unsets the forced-hidden state flag for this task depending on {@param set}. 5268 * @return Whether the force hidden state changed 5269 */ 5270 boolean setForceHidden(int flags, boolean set) { 5271 int newFlags = mForceHiddenFlags; 5272 if (set) { 5273 newFlags |= flags; 5274 } else { 5275 newFlags &= ~flags; 5276 } 5277 if (mForceHiddenFlags == newFlags) { 5278 return false; 5279 } 5280 5281 final boolean wasHidden = isForceHidden(); 5282 final boolean wasVisible = isVisible(); 5283 mForceHiddenFlags = newFlags; 5284 final boolean nowHidden = isForceHidden(); 5285 if (wasHidden != nowHidden) { 5286 final String reason = "setForceHidden"; 5287 if (wasVisible && nowHidden) { 5288 // Move this visible task to back when the task is forced hidden 5289 moveToBack(reason, null); 5290 } else if (isAlwaysOnTop()) { 5291 // Move this always-on-top task to front when no longer hidden 5292 moveToFront(reason); 5293 } 5294 } 5295 return true; 5296 } 5297 5298 @Override 5299 public boolean isAlwaysOnTop() { 5300 return !isForceHidden() && super.isAlwaysOnTop(); 5301 } 5302 5303 /** 5304 * @return whether this task is always on top without taking visibility into account. 5305 */ 5306 public boolean isAlwaysOnTopWhenVisible() { 5307 return super.isAlwaysOnTop(); 5308 } 5309 5310 /** 5311 * Returns whether this task is currently forced to be hidden for any reason. 5312 */ 5313 protected boolean isForceHidden() { 5314 return mForceHiddenFlags != 0; 5315 } 5316 5317 @Override 5318 long getProtoFieldId() { 5319 return TASK; 5320 } 5321 5322 @Override 5323 public void setWindowingMode(int windowingMode) { 5324 // Calling Task#setWindowingMode() for leaf task since this is the a specialization of 5325 // {@link #setWindowingMode(int)} for root task. 5326 if (!isRootTask()) { 5327 super.setWindowingMode(windowingMode); 5328 return; 5329 } 5330 5331 setWindowingMode(windowingMode, false /* creating */); 5332 } 5333 5334 /** 5335 * Specialization of {@link #setWindowingMode(int)} for this subclass. 5336 * 5337 * @param preferredWindowingMode the preferred windowing mode. This may not be honored depending 5338 * on the state of things. For example, WINDOWING_MODE_UNDEFINED will resolve to the 5339 * previous non-transient mode if this root task is currently in a transient mode. 5340 * @param creating {@code true} if this is being run during task construction. 5341 */ 5342 void setWindowingMode(int preferredWindowingMode, boolean creating) { 5343 mWmService.inSurfaceTransaction(() -> setWindowingModeInSurfaceTransaction( 5344 preferredWindowingMode, creating)); 5345 } 5346 5347 private void setWindowingModeInSurfaceTransaction(int preferredWindowingMode, 5348 boolean creating) { 5349 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 5350 if (taskDisplayArea == null) { 5351 Slog.d(TAG, "taskDisplayArea is null, bail early"); 5352 return; 5353 } 5354 final int currentMode = getWindowingMode(); 5355 final Task topTask = getTopMostTask(); 5356 int windowingMode = preferredWindowingMode; 5357 5358 // Need to make sure windowing mode is supported. If we in the process of creating the 5359 // root task no need to resolve the windowing mode again as it is already resolved to the 5360 // right mode. 5361 if (!creating) { 5362 if (!taskDisplayArea.isValidWindowingMode(windowingMode, null /* ActivityRecord */, 5363 topTask, getActivityType())) { 5364 windowingMode = WINDOWING_MODE_UNDEFINED; 5365 } 5366 } 5367 5368 final boolean alreadyInSplitScreenMode = taskDisplayArea.isSplitScreenModeActivated(); 5369 5370 if (creating && alreadyInSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN 5371 && isActivityTypeStandardOrUndefined()) { 5372 // If the root task is being created explicitly in fullscreen mode, dismiss split-screen 5373 // and display a warning toast about it. 5374 mAtmService.getTaskChangeNotificationController() 5375 .notifyActivityDismissingDockedRootTask(); 5376 taskDisplayArea.onSplitScreenModeDismissed(this); 5377 } 5378 5379 if (currentMode == windowingMode) { 5380 // You are already in the window mode, so we can skip most of the work below. However, 5381 // it's possible that we have inherited the current windowing mode from a parent. So, 5382 // fulfill this method's contract by setting the override mode directly. 5383 getRequestedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode); 5384 return; 5385 } 5386 5387 final ActivityRecord topActivity = getTopNonFinishingActivity(); 5388 5389 // For now, assume that the root task's windowing mode is what will actually be used 5390 // by it's activities. In the future, there may be situations where this doesn't 5391 // happen; so at that point, this message will need to handle that. 5392 int likelyResolvedMode = windowingMode; 5393 if (windowingMode == WINDOWING_MODE_UNDEFINED) { 5394 final ConfigurationContainer parent = getParent(); 5395 likelyResolvedMode = parent != null ? parent.getWindowingMode() 5396 : WINDOWING_MODE_FULLSCREEN; 5397 } 5398 if (currentMode == WINDOWING_MODE_PINNED) { 5399 mRootWindowContainer.notifyActivityPipModeChanged(this, null); 5400 } 5401 if (likelyResolvedMode == WINDOWING_MODE_PINNED) { 5402 // In the case that we've disabled affecting the SysUI flags as a part of seamlessly 5403 // transferring the transform on the leash to the task, reset this state once we've 5404 // actually entered pip 5405 setCanAffectSystemUiFlags(true); 5406 if (taskDisplayArea.getRootPinnedTask() != null) { 5407 // Can only have 1 pip at a time, so replace an existing pip 5408 taskDisplayArea.getRootPinnedTask().dismissPip(); 5409 } 5410 } 5411 if (likelyResolvedMode != WINDOWING_MODE_FULLSCREEN 5412 && topActivity != null && !topActivity.noDisplay 5413 && topActivity.canForceResizeNonResizable(likelyResolvedMode)) { 5414 // Inform the user that they are starting an app that may not work correctly in 5415 // multi-window mode. 5416 final String packageName = topActivity.info.applicationInfo.packageName; 5417 mAtmService.getTaskChangeNotificationController().notifyActivityForcedResizable( 5418 topTask.mTaskId, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN, packageName); 5419 } 5420 5421 mAtmService.deferWindowLayout(); 5422 try { 5423 if (topActivity != null) { 5424 mTaskSupervisor.mNoAnimActivities.add(topActivity); 5425 } 5426 super.setWindowingMode(windowingMode); 5427 5428 // Try reparent pinned activity back to its original task after onConfigurationChanged 5429 // cascade finishes. This is done on Task level instead of 5430 // {@link ActivityRecord#onConfigurationChanged(Configuration)} since when we exit PiP, 5431 // we set final windowing mode on the ActivityRecord first and then on its Task when 5432 // the exit PiP transition finishes. Meanwhile, the exit transition is always 5433 // performed on its original task, reparent immediately in ActivityRecord breaks it. 5434 if (currentMode == WINDOWING_MODE_PINNED) { 5435 if (topActivity != null && topActivity.getLastParentBeforePip() != null) { 5436 // Do not reparent if the pinned task is in removal, indicated by the 5437 // force hidden flag. 5438 if (!isForceHidden()) { 5439 final Task lastParentBeforePip = topActivity.getLastParentBeforePip(); 5440 if (lastParentBeforePip.isAttached()) { 5441 topActivity.reparent(lastParentBeforePip, 5442 lastParentBeforePip.getChildCount() /* top */, 5443 "movePinnedActivityToOriginalTask"); 5444 lastParentBeforePip.moveToFront("movePinnedActivityToOriginalTask"); 5445 } 5446 } 5447 } 5448 } 5449 5450 if (creating) { 5451 // Nothing else to do if we don't have a window container yet. E.g. call from ctor. 5452 return; 5453 } 5454 5455 // From fullscreen to PiP. 5456 if (topActivity != null && currentMode == WINDOWING_MODE_FULLSCREEN 5457 && windowingMode == WINDOWING_MODE_PINNED) { 5458 mDisplayContent.mPinnedTaskController 5459 .deferOrientationChangeForEnteringPipFromFullScreenIfNeeded(); 5460 } 5461 } finally { 5462 mAtmService.continueWindowLayout(); 5463 } 5464 5465 mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); 5466 mRootWindowContainer.resumeFocusedTasksTopActivities(); 5467 } 5468 5469 void resumeNextFocusAfterReparent() { 5470 adjustFocusToNextFocusableTask("reparent", true /* allowFocusSelf */, 5471 true /* moveDisplayToTop */); 5472 mRootWindowContainer.resumeFocusedTasksTopActivities(); 5473 // Update visibility of activities before notifying WM. This way it won't try to resize 5474 // windows that are no longer visible. 5475 mRootWindowContainer.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, 5476 !PRESERVE_WINDOWS); 5477 } 5478 5479 final boolean isHomeOrRecentsRootTask() { 5480 return isActivityTypeHome() || isActivityTypeRecents(); 5481 } 5482 5483 final boolean isOnHomeDisplay() { 5484 return getDisplayId() == DEFAULT_DISPLAY; 5485 } 5486 5487 void moveToFront(String reason) { 5488 moveToFront(reason, null); 5489 } 5490 5491 /** 5492 * @param reason The reason for moving the root task to the front. 5493 * @param task If non-null, the task will be moved to the top of the root task. 5494 */ 5495 void moveToFront(String reason, Task task) { 5496 if (!isAttached()) { 5497 return; 5498 } 5499 5500 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 5501 5502 if (inSplitScreenSecondaryWindowingMode()) { 5503 // If the root task is in split-screen secondary mode, we need to make sure we move the 5504 // primary split-screen root task forward in the case it is currently behind a 5505 // fullscreen root task so both halves of the split-screen appear on-top and the 5506 // fullscreen root task isn't cutting between them. 5507 // TODO(b/70677280): This is a workaround until we can fix as part of b/70677280. 5508 final Task topFullScreenRootTask = 5509 taskDisplayArea.getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN); 5510 if (topFullScreenRootTask != null) { 5511 final Task primarySplitScreenRootTask = 5512 taskDisplayArea.getRootSplitScreenPrimaryTask(); 5513 if (primarySplitScreenRootTask != null 5514 && topFullScreenRootTask.compareTo(primarySplitScreenRootTask) > 0) { 5515 primarySplitScreenRootTask.moveToFront(reason + " splitScreenToTop"); 5516 } 5517 } 5518 } 5519 5520 if (!isActivityTypeHome() && returnsToHomeRootTask()) { 5521 // Make sure the root home task is behind this root task since that is where we 5522 // should return to when this root task is no longer visible. 5523 taskDisplayArea.moveHomeRootTaskToFront(reason + " returnToHome"); 5524 } 5525 5526 final Task lastFocusedTask = isRootTask() ? taskDisplayArea.getFocusedRootTask() : null; 5527 if (task == null) { 5528 task = this; 5529 } 5530 task.getParent().positionChildAt(POSITION_TOP, task, true /* includingParents */); 5531 taskDisplayArea.updateLastFocusedRootTask(lastFocusedTask, reason); 5532 } 5533 5534 /** 5535 * This moves 'task' to the back of this task and also recursively moves this task to the back 5536 * of its parents (if applicable). 5537 * 5538 * @param reason The reason for moving the root task to the back. 5539 * @param task If non-null, the task will be moved to the bottom of the root task. 5540 **/ 5541 void moveToBack(String reason, Task task) { 5542 if (!isAttached()) { 5543 return; 5544 } 5545 final TaskDisplayArea displayArea = getDisplayArea(); 5546 if (!mCreatedByOrganizer) { 5547 // If this is just a normal task, so move to back of parent and then move 'task' to 5548 // back of this. 5549 final WindowContainer parent = getParent(); 5550 final Task parentTask = parent != null ? parent.asTask() : null; 5551 if (parentTask != null) { 5552 parentTask.moveToBack(reason, this); 5553 } else { 5554 final Task lastFocusedTask = displayArea.getFocusedRootTask(); 5555 displayArea.positionChildAt(POSITION_BOTTOM, this, false /*includingParents*/); 5556 displayArea.updateLastFocusedRootTask(lastFocusedTask, reason); 5557 mAtmService.getTaskChangeNotificationController().notifyTaskMovedToBack( 5558 getTaskInfo()); 5559 } 5560 if (task != null && task != this) { 5561 positionChildAtBottom(task); 5562 mAtmService.getTaskChangeNotificationController().notifyTaskMovedToBack( 5563 task.getTaskInfo()); 5564 } 5565 return; 5566 } 5567 if (task == null || task == this) { 5568 return; 5569 } 5570 // This is a created-by-organizer task. In this case, let the organizer deal with this 5571 // task's ordering. However, we still need to move 'task' to back. The intention is that 5572 // this ends up behind the home-task so that it is made invisible; so, if the home task 5573 // is not a child of this, reparent 'task' to the back of the home task's actual parent. 5574 displayArea.positionTaskBehindHome(task); 5575 } 5576 5577 // TODO: Should each user have there own root tasks? 5578 @Override 5579 void switchUser(int userId) { 5580 if (mCurrentUser == userId) { 5581 return; 5582 } 5583 mCurrentUser = userId; 5584 5585 super.switchUser(userId); 5586 if (!isRootTask() && showToCurrentUser()) { 5587 getParent().positionChildAt(POSITION_TOP, this, false /*includeParents*/); 5588 } 5589 } 5590 5591 void minimalResumeActivityLocked(ActivityRecord r) { 5592 ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (starting new instance) " 5593 + "callers=%s", r, Debug.getCallers(5)); 5594 r.setState(RESUMED, "minimalResumeActivityLocked"); 5595 r.completeResumeLocked(); 5596 } 5597 5598 void awakeFromSleepingLocked() { 5599 if (!isLeafTask()) { 5600 forAllLeafTasks((task) -> task.awakeFromSleepingLocked(), 5601 true /* traverseTopToBottom */); 5602 return; 5603 } 5604 5605 if (mPausingActivity != null) { 5606 Slog.d(TAG, "awakeFromSleepingLocked: previously pausing activity didn't pause"); 5607 mPausingActivity.activityPaused(true); 5608 } 5609 } 5610 5611 void checkReadyForSleep() { 5612 if (shouldSleepActivities() && goToSleepIfPossible(false /* shuttingDown */)) { 5613 mTaskSupervisor.checkReadyForSleepLocked(true /* allowDelay */); 5614 } 5615 } 5616 5617 /** 5618 * Tries to put the activities in the root task to sleep. 5619 * 5620 * If the root task is not in a state where its activities can be put to sleep, this function 5621 * will start any necessary actions to move the root task into such a state. It is expected 5622 * that this function get called again when those actions complete. 5623 * 5624 * @param shuttingDown true when the called because the device is shutting down. 5625 * @return true if the root task finished going to sleep, false if the root task only started 5626 * the process of going to sleep (checkReadyForSleep will be called when that process finishes). 5627 */ 5628 boolean goToSleepIfPossible(boolean shuttingDown) { 5629 if (!isLeafTask()) { 5630 final int[] sleepInProgress = {0}; 5631 forAllLeafTasks((t) -> { 5632 if (!t.goToSleepIfPossible(shuttingDown)) { 5633 sleepInProgress[0]++; 5634 } 5635 }, true); 5636 return sleepInProgress[0] == 0; 5637 } 5638 5639 boolean shouldSleep = true; 5640 if (mResumedActivity != null) { 5641 // Still have something resumed; can't sleep until it is paused. 5642 ProtoLog.v(WM_DEBUG_STATES, "Sleep needs to pause %s", mResumedActivity); 5643 if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING, 5644 "Sleep => pause with userLeaving=false"); 5645 5646 startPausingLocked(false /* userLeaving */, true /* uiSleeping */, null /* resuming */, 5647 "sleep"); 5648 shouldSleep = false ; 5649 } else if (mPausingActivity != null) { 5650 // Still waiting for something to pause; can't sleep yet. 5651 ProtoLog.v(WM_DEBUG_STATES, "Sleep still waiting to pause %s", mPausingActivity); 5652 shouldSleep = false; 5653 } 5654 5655 if (!shuttingDown) { 5656 if (containsActivityFromRootTask(mTaskSupervisor.mStoppingActivities)) { 5657 // Still need to tell some activities to stop; can't sleep yet. 5658 ProtoLog.v(WM_DEBUG_STATES, "Sleep still need to stop %d activities", 5659 mTaskSupervisor.mStoppingActivities.size()); 5660 5661 mTaskSupervisor.scheduleIdle(); 5662 shouldSleep = false; 5663 } 5664 } 5665 5666 if (shouldSleep) { 5667 ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, 5668 !PRESERVE_WINDOWS); 5669 } 5670 5671 return shouldSleep; 5672 } 5673 5674 private boolean containsActivityFromRootTask(List<ActivityRecord> rs) { 5675 for (ActivityRecord r : rs) { 5676 if (r.getRootTask() == this) { 5677 return true; 5678 } 5679 } 5680 return false; 5681 } 5682 5683 final boolean startPausingLocked(boolean uiSleeping, ActivityRecord resuming, String reason) { 5684 return startPausingLocked(mTaskSupervisor.mUserLeaving, uiSleeping, resuming, reason); 5685 } 5686 5687 /** 5688 * Start pausing the currently resumed activity. It is an error to call this if there 5689 * is already an activity being paused or there is no resumed activity. 5690 * 5691 * @param userLeaving True if this should result in an onUserLeaving to the current activity. 5692 * @param uiSleeping True if this is happening with the user interface going to sleep (the 5693 * screen turning off). 5694 * @param resuming The activity we are currently trying to resume or null if this is not being 5695 * called as part of resuming the top activity, so we shouldn't try to instigate 5696 * a resume here if not null. 5697 * @param reason The reason of pausing the activity. 5698 * @return Returns true if an activity now is in the PAUSING state, and we are waiting for 5699 * it to tell us when it is done. 5700 */ 5701 final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, 5702 ActivityRecord resuming, String reason) { 5703 if (!isLeafTask()) { 5704 final int[] pausing = {0}; 5705 forAllLeafTasks((t) -> { 5706 if (t.startPausingLocked(userLeaving, uiSleeping, resuming, reason)) { 5707 pausing[0]++; 5708 } 5709 }, true /* traverseTopToBottom */); 5710 return pausing[0] > 0; 5711 } 5712 5713 if (mPausingActivity != null) { 5714 Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity 5715 + " state=" + mPausingActivity.getState()); 5716 if (!shouldSleepActivities()) { 5717 // Avoid recursion among check for sleep and complete pause during sleeping. 5718 // Because activity will be paused immediately after resume, just let pause 5719 // be completed by the order of activity paused from clients. 5720 completePauseLocked(false, resuming); 5721 } 5722 } 5723 ActivityRecord prev = mResumedActivity; 5724 5725 if (prev == null) { 5726 if (resuming == null) { 5727 Slog.wtf(TAG, "Trying to pause when nothing is resumed"); 5728 mRootWindowContainer.resumeFocusedTasksTopActivities(); 5729 } 5730 return false; 5731 } 5732 5733 if (prev == resuming) { 5734 Slog.wtf(TAG, "Trying to pause activity that is in process of being resumed"); 5735 return false; 5736 } 5737 5738 ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSING: %s", prev); 5739 mPausingActivity = prev; 5740 mLastPausedActivity = prev; 5741 if (prev.isNoHistory() && !mTaskSupervisor.mNoHistoryActivities.contains(prev)) { 5742 mTaskSupervisor.mNoHistoryActivities.add(prev); 5743 } 5744 prev.setState(PAUSING, "startPausingLocked"); 5745 prev.getTask().touchActiveTime(); 5746 5747 mAtmService.updateCpuStats(); 5748 5749 boolean pauseImmediately = false; 5750 boolean shouldAutoPip = false; 5751 if (resuming != null && (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0) { 5752 // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous 5753 // activity to be paused, while at the same time resuming the new resume activity 5754 // only if the previous activity can't go into Pip since we want to give Pip 5755 // activities a chance to enter Pip before resuming the next activity. 5756 final boolean lastResumedCanPip = prev != null && prev.checkEnterPictureInPictureState( 5757 "shouldResumeWhilePausing", userLeaving); 5758 if (lastResumedCanPip && prev.pictureInPictureArgs.isAutoEnterEnabled()) { 5759 shouldAutoPip = true; 5760 } else if (!lastResumedCanPip) { 5761 pauseImmediately = true; 5762 } else { 5763 // The previous activity may still enter PIP even though it did not allow auto-PIP. 5764 } 5765 } 5766 5767 boolean didAutoPip = false; 5768 if (prev.attachedToProcess()) { 5769 if (shouldAutoPip) { 5770 ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode " 5771 + "directly: %s", prev); 5772 5773 didAutoPip = mAtmService.enterPictureInPictureMode(prev, prev.pictureInPictureArgs); 5774 mPausingActivity = null; 5775 } else { 5776 ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev); 5777 try { 5778 EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev), 5779 prev.shortComponentName, "userLeaving=" + userLeaving, reason); 5780 5781 mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), 5782 prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, 5783 prev.configChangeFlags, pauseImmediately)); 5784 } catch (Exception e) { 5785 // Ignore exception, if process died other code will cleanup. 5786 Slog.w(TAG, "Exception thrown during pause", e); 5787 mPausingActivity = null; 5788 mLastPausedActivity = null; 5789 mTaskSupervisor.mNoHistoryActivities.remove(prev); 5790 } 5791 } 5792 } else { 5793 mPausingActivity = null; 5794 mLastPausedActivity = null; 5795 mTaskSupervisor.mNoHistoryActivities.remove(prev); 5796 } 5797 5798 // If we are not going to sleep, we want to ensure the device is 5799 // awake until the next activity is started. 5800 if (!uiSleeping && !mAtmService.isSleepingOrShuttingDownLocked()) { 5801 mTaskSupervisor.acquireLaunchWakelock(); 5802 } 5803 5804 // If already entered PIP mode, no need to keep pausing. 5805 if (mPausingActivity != null && !didAutoPip) { 5806 // Have the window manager pause its key dispatching until the new 5807 // activity has started. If we're pausing the activity just because 5808 // the screen is being turned off and the UI is sleeping, don't interrupt 5809 // key dispatch; the same activity will pick it up again on wakeup. 5810 if (!uiSleeping) { 5811 prev.pauseKeyDispatchingLocked(); 5812 } else { 5813 ProtoLog.v(WM_DEBUG_STATES, "Key dispatch not paused for screen off"); 5814 } 5815 5816 if (pauseImmediately) { 5817 // If the caller said they don't want to wait for the pause, then complete 5818 // the pause now. 5819 completePauseLocked(false, resuming); 5820 return false; 5821 5822 } else { 5823 prev.schedulePauseTimeout(); 5824 return true; 5825 } 5826 5827 } else { 5828 // This activity either failed to schedule the pause or it entered PIP mode, 5829 // so just treat it as being paused now. 5830 ProtoLog.v(WM_DEBUG_STATES, "Activity not running or entered PiP, resuming next."); 5831 if (resuming == null) { 5832 mRootWindowContainer.resumeFocusedTasksTopActivities(); 5833 } 5834 return false; 5835 } 5836 } 5837 5838 @VisibleForTesting 5839 void completePauseLocked(boolean resumeNext, ActivityRecord resuming) { 5840 // Complete the pausing process of a pausing activity, so it doesn't make sense to 5841 // operate on non-leaf tasks. 5842 warnForNonLeafTask("completePauseLocked"); 5843 5844 ActivityRecord prev = mPausingActivity; 5845 ProtoLog.v(WM_DEBUG_STATES, "Complete pause: %s", prev); 5846 5847 if (prev != null) { 5848 prev.setWillCloseOrEnterPip(false); 5849 final boolean wasStopping = prev.isState(STOPPING); 5850 prev.setState(PAUSED, "completePausedLocked"); 5851 if (prev.finishing) { 5852 // We will update the activity visibility later, no need to do in 5853 // completeFinishing(). Updating visibility here might also making the next 5854 // activities to be resumed, and could result in wrong app transition due to 5855 // lack of previous activity information. 5856 ProtoLog.v(WM_DEBUG_STATES, "Executing finish of activity: %s", prev); 5857 prev = prev.completeFinishing(false /* updateVisibility */, 5858 "completePausedLocked"); 5859 } else if (prev.hasProcess()) { 5860 ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s " 5861 + "wasStopping=%b visibleRequested=%b", prev, wasStopping, 5862 prev.mVisibleRequested); 5863 if (prev.deferRelaunchUntilPaused) { 5864 // Complete the deferred relaunch that was waiting for pause to complete. 5865 ProtoLog.v(WM_DEBUG_STATES, "Re-launching after pause: %s", prev); 5866 prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch); 5867 } else if (wasStopping) { 5868 // We are also stopping, the stop request must have gone soon after the pause. 5869 // We can't clobber it, because the stop confirmation will not be handled. 5870 // We don't need to schedule another stop, we only need to let it happen. 5871 prev.setState(STOPPING, "completePausedLocked"); 5872 } else if (!prev.mVisibleRequested || shouldSleepOrShutDownActivities()) { 5873 // Clear out any deferred client hide we might currently have. 5874 prev.setDeferHidingClient(false); 5875 // If we were visible then resumeTopActivities will release resources before 5876 // stopping. 5877 prev.addToStopping(true /* scheduleIdle */, false /* idleDelayed */, 5878 "completePauseLocked"); 5879 } 5880 } else { 5881 ProtoLog.v(WM_DEBUG_STATES, "App died during pause, not stopping: %s", prev); 5882 prev = null; 5883 } 5884 // It is possible the activity was freezing the screen before it was paused. 5885 // In that case go ahead and remove the freeze this activity has on the screen 5886 // since it is no longer visible. 5887 if (prev != null) { 5888 prev.stopFreezingScreenLocked(true /*force*/); 5889 } 5890 mPausingActivity = null; 5891 } 5892 5893 if (resumeNext) { 5894 final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask(); 5895 if (topRootTask != null && !topRootTask.shouldSleepOrShutDownActivities()) { 5896 mRootWindowContainer.resumeFocusedTasksTopActivities(topRootTask, prev, null); 5897 } else { 5898 checkReadyForSleep(); 5899 final ActivityRecord top = 5900 topRootTask != null ? topRootTask.topRunningActivity() : null; 5901 if (top == null || (prev != null && top != prev)) { 5902 // If there are no more activities available to run, do resume anyway to start 5903 // something. Also if the top activity on the root task is not the just paused 5904 // activity, we need to go ahead and resume it to ensure we complete an 5905 // in-flight app switch. 5906 mRootWindowContainer.resumeFocusedTasksTopActivities(); 5907 } 5908 } 5909 } 5910 5911 if (prev != null) { 5912 prev.resumeKeyDispatchingLocked(); 5913 } 5914 5915 mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS); 5916 5917 // Notify when the task stack has changed, but only if visibilities changed (not just 5918 // focus). Also if there is an active root pinned task - we always want to notify it about 5919 // task stack changes, because its positioning may depend on it. 5920 if (mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause 5921 || (getDisplayArea() != null && getDisplayArea().hasPinnedTask())) { 5922 mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged(); 5923 mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = false; 5924 } 5925 } 5926 5927 boolean isTopRootTaskInDisplayArea() { 5928 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 5929 return taskDisplayArea != null && taskDisplayArea.isTopRootTask(this); 5930 } 5931 5932 /** 5933 * @return {@code true} if this is the focused root task on its current display, {@code false} 5934 * otherwise. 5935 */ 5936 boolean isFocusedRootTaskOnDisplay() { 5937 return mDisplayContent != null && this == mDisplayContent.getFocusedRootTask(); 5938 } 5939 5940 /** 5941 * Make sure that all activities that need to be visible in the root task (that is, they 5942 * currently can be seen by the user) actually are and update their configuration. 5943 * @param starting The top most activity in the task. 5944 * The activity is either starting or resuming. 5945 * Caller should ensure starting activity is visible. 5946 * @param preserveWindows Flag indicating whether windows should be preserved when updating 5947 * configuration in {@link mEnsureActivitiesVisibleHelper}. 5948 * @param configChanges Parts of the configuration that changed for this activity for evaluating 5949 * if the screen should be frozen as part of 5950 * {@link mEnsureActivitiesVisibleHelper}. 5951 * 5952 */ 5953 void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges, 5954 boolean preserveWindows) { 5955 ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */); 5956 } 5957 5958 /** 5959 * Ensure visibility with an option to also update the configuration of visible activities. 5960 * @see #ensureActivitiesVisible(ActivityRecord, int, boolean) 5961 * @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean) 5962 * @param starting The top most activity in the task. 5963 * The activity is either starting or resuming. 5964 * Caller should ensure starting activity is visible. 5965 * @param notifyClients Flag indicating whether the visibility updates should be sent to the 5966 * clients in {@link mEnsureActivitiesVisibleHelper}. 5967 * @param preserveWindows Flag indicating whether windows should be preserved when updating 5968 * configuration in {@link mEnsureActivitiesVisibleHelper}. 5969 * @param configChanges Parts of the configuration that changed for this activity for evaluating 5970 * if the screen should be frozen as part of 5971 * {@link mEnsureActivitiesVisibleHelper}. 5972 */ 5973 // TODO: Should be re-worked based on the fact that each task as a root task in most cases. 5974 void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges, 5975 boolean preserveWindows, boolean notifyClients) { 5976 mTaskSupervisor.beginActivityVisibilityUpdate(); 5977 try { 5978 forAllLeafTasks(task -> task.mEnsureActivitiesVisibleHelper.process( 5979 starting, configChanges, preserveWindows, notifyClients), 5980 true /* traverseTopToBottom */); 5981 5982 // Notify WM shell that task visibilities may have changed 5983 forAllTasks(task -> task.dispatchTaskInfoChangedIfNeeded(/* force */ false), 5984 true /* traverseTopToBottom */); 5985 5986 if (mTranslucentActivityWaiting != null && 5987 mUndrawnActivitiesBelowTopTranslucent.isEmpty()) { 5988 // Nothing is getting drawn or everything was already visible, don't wait for 5989 // timeout. 5990 notifyActivityDrawnLocked(null); 5991 } 5992 } finally { 5993 mTaskSupervisor.endActivityVisibilityUpdate(); 5994 } 5995 } 5996 5997 /** 5998 * Returns true if this root task should be resized to match the bounds specified by 5999 * {@link ActivityOptions#setLaunchBounds} when launching an activity into the root task. 6000 */ 6001 boolean shouldResizeRootTaskWithLaunchBounds() { 6002 return inPinnedWindowingMode(); 6003 } 6004 6005 void checkTranslucentActivityWaiting(ActivityRecord top) { 6006 if (mTranslucentActivityWaiting != top) { 6007 mUndrawnActivitiesBelowTopTranslucent.clear(); 6008 if (mTranslucentActivityWaiting != null) { 6009 // Call the callback with a timeout indication. 6010 notifyActivityDrawnLocked(null); 6011 mTranslucentActivityWaiting = null; 6012 } 6013 mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG); 6014 } 6015 } 6016 6017 void convertActivityToTranslucent(ActivityRecord r) { 6018 mTranslucentActivityWaiting = r; 6019 mUndrawnActivitiesBelowTopTranslucent.clear(); 6020 mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT); 6021 } 6022 6023 /** 6024 * Called as activities below the top translucent activity are redrawn. When the last one is 6025 * redrawn notify the top activity by calling 6026 * {@link Activity#onTranslucentConversionComplete}. 6027 * 6028 * @param r The most recent background activity to be drawn. Or, if r is null then a timeout 6029 * occurred and the activity will be notified immediately. 6030 */ 6031 void notifyActivityDrawnLocked(ActivityRecord r) { 6032 if ((r == null) 6033 || (mUndrawnActivitiesBelowTopTranslucent.remove(r) && 6034 mUndrawnActivitiesBelowTopTranslucent.isEmpty())) { 6035 // The last undrawn activity below the top has just been drawn. If there is an 6036 // opaque activity at the top, notify it that it can become translucent safely now. 6037 final ActivityRecord waitingActivity = mTranslucentActivityWaiting; 6038 mTranslucentActivityWaiting = null; 6039 mUndrawnActivitiesBelowTopTranslucent.clear(); 6040 mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG); 6041 6042 if (waitingActivity != null) { 6043 mWmService.setWindowOpaqueLocked(waitingActivity.appToken, false); 6044 if (waitingActivity.attachedToProcess()) { 6045 try { 6046 waitingActivity.app.getThread().scheduleTranslucentConversionComplete( 6047 waitingActivity.appToken, r != null); 6048 } catch (RemoteException e) { 6049 } 6050 } 6051 } 6052 } 6053 } 6054 6055 /** @see ActivityRecord#cancelInitializing() */ 6056 void cancelInitializingActivities() { 6057 // We don't want to clear starting window for activities that aren't behind fullscreen 6058 // activities as we need to display their starting window until they are done initializing. 6059 checkBehindFullscreenActivity(null /* toCheck */, ActivityRecord::cancelInitializing); 6060 } 6061 6062 /** 6063 * If an activity {@param toCheck} is given, this method returns {@code true} if the activity 6064 * is occluded by any fullscreen activity. If there is no {@param toCheck} and the handling 6065 * function {@param handleBehindFullscreenActivity} is given, this method will pass all occluded 6066 * activities to the function. 6067 */ 6068 boolean checkBehindFullscreenActivity(ActivityRecord toCheck, 6069 Consumer<ActivityRecord> handleBehindFullscreenActivity) { 6070 return mCheckBehindFullscreenActivityHelper.process( 6071 toCheck, handleBehindFullscreenActivity); 6072 } 6073 6074 /** 6075 * Ensure that the top activity in the root task is resumed. 6076 * 6077 * @param prev The previously resumed activity, for when in the process 6078 * of pausing; can be null to call from elsewhere. 6079 * @param options Activity options. 6080 * @param deferPause When {@code true}, this will not pause back tasks. 6081 * 6082 * @return Returns true if something is being resumed, or false if 6083 * nothing happened. 6084 * 6085 * NOTE: It is not safe to call this method directly as it can cause an activity in a 6086 * non-focused root task to be resumed. 6087 * Use {@link RootWindowContainer#resumeFocusedTasksTopActivities} to resume the 6088 * right activity for the current system state. 6089 */ 6090 @GuardedBy("mService") 6091 boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options, 6092 boolean deferPause) { 6093 if (mInResumeTopActivity) { 6094 // Don't even start recursing. 6095 return false; 6096 } 6097 6098 boolean someActivityResumed = false; 6099 try { 6100 // Protect against recursion. 6101 mInResumeTopActivity = true; 6102 6103 if (isLeafTask()) { 6104 if (isFocusableAndVisible()) { 6105 someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause); 6106 } 6107 } else { 6108 int idx = mChildren.size() - 1; 6109 while (idx >= 0) { 6110 final Task child = (Task) getChildAt(idx--); 6111 if (!child.isTopActivityFocusable()) { 6112 continue; 6113 } 6114 if (child.getVisibility(null /* starting */) != TASK_VISIBILITY_VISIBLE) { 6115 break; 6116 } 6117 6118 someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options, 6119 deferPause); 6120 // Doing so in order to prevent IndexOOB since hierarchy might changes while 6121 // resuming activities, for example dismissing split-screen while starting 6122 // non-resizeable activity. 6123 if (idx >= mChildren.size()) { 6124 idx = mChildren.size() - 1; 6125 } 6126 } 6127 } 6128 6129 // When resuming the top activity, it may be necessary to pause the top activity (for 6130 // example, returning to the lock screen. We suppress the normal pause logic in 6131 // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the 6132 // end. We call the {@link ActivityTaskSupervisor#checkReadyForSleepLocked} again here 6133 // to ensure any necessary pause logic occurs. In the case where the Activity will be 6134 // shown regardless of the lock screen, the call to 6135 // {@link ActivityTaskSupervisor#checkReadyForSleepLocked} is skipped. 6136 final ActivityRecord next = topRunningActivity(true /* focusableOnly */); 6137 if (next == null || !next.canTurnScreenOn()) { 6138 checkReadyForSleep(); 6139 } 6140 } finally { 6141 mInResumeTopActivity = false; 6142 } 6143 6144 return someActivityResumed; 6145 } 6146 6147 /** @see #resumeTopActivityUncheckedLocked(ActivityRecord, ActivityOptions, boolean) */ 6148 @GuardedBy("mService") 6149 boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) { 6150 return resumeTopActivityUncheckedLocked(prev, options, false /* skipPause */); 6151 } 6152 6153 @GuardedBy("mService") 6154 private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options, 6155 boolean deferPause) { 6156 if (!mAtmService.isBooting() && !mAtmService.isBooted()) { 6157 // Not ready yet! 6158 return false; 6159 } 6160 6161 // Find the next top-most activity to resume in this root task that is not finishing and is 6162 // focusable. If it is not focusable, we will fall into the case below to resume the 6163 // top activity in the next focusable task. 6164 ActivityRecord next = topRunningActivity(true /* focusableOnly */); 6165 6166 final boolean hasRunningActivity = next != null; 6167 6168 // TODO: Maybe this entire condition can get removed? 6169 if (hasRunningActivity && !isAttached()) { 6170 return false; 6171 } 6172 6173 mRootWindowContainer.cancelInitializingActivities(); 6174 6175 if (!hasRunningActivity) { 6176 // There are no activities left in the root task, let's look somewhere else. 6177 return resumeNextFocusableActivityWhenRootTaskIsEmpty(prev, options); 6178 } 6179 6180 next.delayedResume = false; 6181 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 6182 6183 // If the top activity is the resumed one, nothing to do. 6184 if (mResumedActivity == next && next.isState(RESUMED) 6185 && taskDisplayArea.allResumedActivitiesComplete()) { 6186 // Make sure we have executed any pending transitions, since there 6187 // should be nothing left to do at this point. 6188 executeAppTransition(options); 6189 // For devices that are not in fullscreen mode (e.g. freeform windows), it's possible 6190 // we still want to check if the visibility of other windows have changed (e.g. bringing 6191 // a fullscreen window forward to cover another freeform activity.) 6192 if (taskDisplayArea.inMultiWindowMode()) { 6193 taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, 6194 false /* preserveWindows */, true /* notifyClients */); 6195 } 6196 ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity " 6197 + "resumed %s", next); 6198 return false; 6199 } 6200 6201 if (!next.canResumeByCompat()) { 6202 return false; 6203 } 6204 6205 // If we are currently pausing an activity, then don't do anything until that is done. 6206 final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete(); 6207 if (!allPausedComplete) { 6208 ProtoLog.v(WM_DEBUG_STATES, 6209 "resumeTopActivityLocked: Skip resume: some activity pausing."); 6210 6211 return false; 6212 } 6213 6214 // If we are sleeping, and there is no resumed activity, and the top activity is paused, 6215 // well that is the state we want. 6216 if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) { 6217 // Make sure we have executed any pending transitions, since there 6218 // should be nothing left to do at this point. 6219 executeAppTransition(options); 6220 ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Going to sleep and" 6221 + " all paused"); 6222 return false; 6223 } 6224 6225 // Make sure that the user who owns this activity is started. If not, 6226 // we will just leave it as is because someone should be bringing 6227 // another user's activities to the top of the stack. 6228 if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) { 6229 Slog.w(TAG, "Skipping resume of top activity " + next 6230 + ": user " + next.mUserId + " is stopped"); 6231 return false; 6232 } 6233 6234 // The activity may be waiting for stop, but that is no longer 6235 // appropriate for it. 6236 mTaskSupervisor.mStoppingActivities.remove(next); 6237 6238 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next); 6239 6240 mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid); 6241 6242 ActivityRecord lastResumed = null; 6243 final Task lastFocusedRootTask = taskDisplayArea.getLastFocusedRootTask(); 6244 if (lastFocusedRootTask != null && lastFocusedRootTask != getRootTask()) { 6245 // So, why aren't we using prev here??? See the param comment on the method. prev 6246 // doesn't represent the last resumed activity. However, the last focus stack does if 6247 // it isn't null. 6248 lastResumed = lastFocusedRootTask.getResumedActivity(); 6249 } 6250 6251 boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next); 6252 if (mResumedActivity != null) { 6253 ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Pausing %s", mResumedActivity); 6254 pausing |= startPausingLocked(false /* uiSleeping */, next, 6255 "resumeTopActivityInnerLocked"); 6256 } 6257 if (pausing) { 6258 ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivityLocked: Skip resume: need to" 6259 + " start pausing"); 6260 // At this point we want to put the upcoming activity's process 6261 // at the top of the LRU list, since we know we will be needing it 6262 // very soon and it would be a waste to let it get killed if it 6263 // happens to be sitting towards the end. 6264 if (next.attachedToProcess()) { 6265 next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, 6266 true /* activityChange */, false /* updateOomAdj */, 6267 false /* addPendingTopUid */); 6268 } else if (!next.isProcessRunning()) { 6269 // Since the start-process is asynchronous, if we already know the process of next 6270 // activity isn't running, we can start the process earlier to save the time to wait 6271 // for the current activity to be paused. 6272 final boolean isTop = this == taskDisplayArea.getFocusedRootTask(); 6273 mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop, 6274 isTop ? "pre-top-activity" : "pre-activity"); 6275 } 6276 if (lastResumed != null) { 6277 lastResumed.setWillCloseOrEnterPip(true); 6278 } 6279 return true; 6280 } else if (mResumedActivity == next && next.isState(RESUMED) 6281 && taskDisplayArea.allResumedActivitiesComplete()) { 6282 // It is possible for the activity to be resumed when we paused back stacks above if the 6283 // next activity doesn't have to wait for pause to complete. 6284 // So, nothing else to-do except: 6285 // Make sure we have executed any pending transitions, since there 6286 // should be nothing left to do at this point. 6287 executeAppTransition(options); 6288 ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity resumed " 6289 + "(dontWaitForPause) %s", next); 6290 return true; 6291 } 6292 6293 // If the most recent activity was noHistory but was only stopped rather 6294 // than stopped+finished because the device went to sleep, we need to make 6295 // sure to finish it as we're making a new activity topmost. 6296 if (shouldSleepActivities()) { 6297 mTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next); 6298 } 6299 6300 if (prev != null && prev != next && next.nowVisible) { 6301 6302 // The next activity is already visible, so hide the previous 6303 // activity's windows right now so we can show the new one ASAP. 6304 // We only do this if the previous is finishing, which should mean 6305 // it is on top of the one being resumed so hiding it quickly 6306 // is good. Otherwise, we want to do the normal route of allowing 6307 // the resumed activity to be shown so we can decide if the 6308 // previous should actually be hidden depending on whether the 6309 // new one is found to be full-screen or not. 6310 if (prev.finishing) { 6311 prev.setVisibility(false); 6312 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, 6313 "Not waiting for visible to hide: " + prev 6314 + ", nowVisible=" + next.nowVisible); 6315 } else { 6316 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, 6317 "Previous already visible but still waiting to hide: " + prev 6318 + ", nowVisible=" + next.nowVisible); 6319 } 6320 6321 } 6322 6323 // Launching this app's activity, make sure the app is no longer 6324 // considered stopped. 6325 try { 6326 mTaskSupervisor.getActivityMetricsLogger() 6327 .notifyBeforePackageUnstopped(next.packageName); 6328 mAtmService.getPackageManager().setPackageStoppedState( 6329 next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */ 6330 } catch (RemoteException e1) { 6331 } catch (IllegalArgumentException e) { 6332 Slog.w(TAG, "Failed trying to unstop package " 6333 + next.packageName + ": " + e); 6334 } 6335 6336 // We are starting up the next activity, so tell the window manager 6337 // that the previous one will be hidden soon. This way it can know 6338 // to ignore it when computing the desired screen orientation. 6339 boolean anim = true; 6340 final DisplayContent dc = taskDisplayArea.mDisplayContent; 6341 if (prev != null) { 6342 if (prev.finishing) { 6343 if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, 6344 "Prepare close transition: prev=" + prev); 6345 if (mTaskSupervisor.mNoAnimActivities.contains(prev)) { 6346 anim = false; 6347 dc.prepareAppTransition(TRANSIT_NONE); 6348 } else { 6349 dc.prepareAppTransition(TRANSIT_CLOSE); 6350 } 6351 prev.setVisibility(false); 6352 } else { 6353 if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, 6354 "Prepare open transition: prev=" + prev); 6355 if (mTaskSupervisor.mNoAnimActivities.contains(next)) { 6356 anim = false; 6357 dc.prepareAppTransition(TRANSIT_NONE); 6358 } else { 6359 dc.prepareAppTransition(TRANSIT_OPEN, 6360 next.mLaunchTaskBehind ? TRANSIT_FLAG_OPEN_BEHIND : 0); 6361 } 6362 } 6363 } else { 6364 if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous"); 6365 if (mTaskSupervisor.mNoAnimActivities.contains(next)) { 6366 anim = false; 6367 dc.prepareAppTransition(TRANSIT_NONE); 6368 } else { 6369 dc.prepareAppTransition(TRANSIT_OPEN); 6370 } 6371 } 6372 6373 if (anim) { 6374 next.applyOptionsAnimation(); 6375 } else { 6376 next.abortAndClearOptionsAnimation(); 6377 } 6378 6379 mTaskSupervisor.mNoAnimActivities.clear(); 6380 6381 if (next.attachedToProcess()) { 6382 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next 6383 + " stopped=" + next.stopped 6384 + " visibleRequested=" + next.mVisibleRequested); 6385 6386 // If the previous activity is translucent, force a visibility update of 6387 // the next activity, so that it's added to WM's opening app list, and 6388 // transition animation can be set up properly. 6389 // For example, pressing Home button with a translucent activity in focus. 6390 // Launcher is already visible in this case. If we don't add it to opening 6391 // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a 6392 // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation. 6393 final boolean lastActivityTranslucent = lastFocusedRootTask != null 6394 && (lastFocusedRootTask.inMultiWindowMode() 6395 || (lastFocusedRootTask.mLastPausedActivity != null 6396 && !lastFocusedRootTask.mLastPausedActivity.occludesParent())); 6397 6398 // This activity is now becoming visible. 6399 if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) { 6400 next.setVisibility(true); 6401 } 6402 6403 // schedule launch ticks to collect information about slow apps. 6404 next.startLaunchTickingLocked(); 6405 6406 ActivityRecord lastResumedActivity = 6407 lastFocusedRootTask == null ? null : lastFocusedRootTask.getResumedActivity(); 6408 final ActivityState lastState = next.getState(); 6409 6410 mAtmService.updateCpuStats(); 6411 6412 ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (in existing)", next); 6413 6414 next.setState(RESUMED, "resumeTopActivityInnerLocked"); 6415 6416 // Have the window manager re-evaluate the orientation of 6417 // the screen based on the new activity order. 6418 boolean notUpdated = true; 6419 6420 // Activity should also be visible if set mLaunchTaskBehind to true (see 6421 // ActivityRecord#shouldBeVisibleIgnoringKeyguard()). 6422 if (shouldBeVisible(next)) { 6423 // We have special rotation behavior when here is some active activity that 6424 // requests specific orientation or Keyguard is locked. Make sure all activity 6425 // visibilities are set correctly as well as the transition is updated if needed 6426 // to get the correct rotation behavior. Otherwise the following call to update 6427 // the orientation may cause incorrect configurations delivered to client as a 6428 // result of invisible window resize. 6429 // TODO: Remove this once visibilities are set correctly immediately when 6430 // starting an activity. 6431 notUpdated = !mRootWindowContainer.ensureVisibilityAndConfig(next, getDisplayId(), 6432 true /* markFrozenIfConfigChanged */, false /* deferResume */); 6433 } 6434 6435 if (notUpdated) { 6436 // The configuration update wasn't able to keep the existing 6437 // instance of the activity, and instead started a new one. 6438 // We should be all done, but let's just make sure our activity 6439 // is still at the top and schedule another run if something 6440 // weird happened. 6441 ActivityRecord nextNext = topRunningActivity(); 6442 ProtoLog.i(WM_DEBUG_STATES, "Activity config changed during resume: " 6443 + "%s, new next: %s", next, nextNext); 6444 if (nextNext != next) { 6445 // Do over! 6446 mTaskSupervisor.scheduleResumeTopActivities(); 6447 } 6448 if (!next.mVisibleRequested || next.stopped) { 6449 next.setVisibility(true); 6450 } 6451 next.completeResumeLocked(); 6452 return true; 6453 } 6454 6455 try { 6456 final ClientTransaction transaction = 6457 ClientTransaction.obtain(next.app.getThread(), next.appToken); 6458 // Deliver all pending results. 6459 ArrayList<ResultInfo> a = next.results; 6460 if (a != null) { 6461 final int N = a.size(); 6462 if (!next.finishing && N > 0) { 6463 if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, 6464 "Delivering results to " + next + ": " + a); 6465 transaction.addCallback(ActivityResultItem.obtain(a)); 6466 } 6467 } 6468 6469 if (next.newIntents != null) { 6470 transaction.addCallback( 6471 NewIntentItem.obtain(next.newIntents, true /* resume */)); 6472 } 6473 6474 // Well the app will no longer be stopped. 6475 // Clear app token stopped state in window manager if needed. 6476 next.notifyAppResumed(next.stopped); 6477 6478 EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next), 6479 next.getTask().mTaskId, next.shortComponentName); 6480 6481 mAtmService.getAppWarningsLocked().onResumeActivity(next); 6482 next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState); 6483 next.abortAndClearOptionsAnimation(); 6484 transaction.setLifecycleStateRequest( 6485 ResumeActivityItem.obtain(next.app.getReportedProcState(), 6486 dc.isNextTransitionForward())); 6487 mAtmService.getLifecycleManager().scheduleTransaction(transaction); 6488 6489 ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Resumed %s", next); 6490 } catch (Exception e) { 6491 // Whoops, need to restart this activity! 6492 ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: " 6493 + "%s", lastState, next); 6494 next.setState(lastState, "resumeTopActivityInnerLocked"); 6495 6496 // lastResumedActivity being non-null implies there is a lastStack present. 6497 if (lastResumedActivity != null) { 6498 lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked"); 6499 } 6500 6501 Slog.i(TAG, "Restarting because process died: " + next); 6502 if (!next.hasBeenLaunched) { 6503 next.hasBeenLaunched = true; 6504 } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null 6505 && lastFocusedRootTask.isTopRootTaskInDisplayArea()) { 6506 next.showStartingWindow(false /* taskSwitch */); 6507 } 6508 mTaskSupervisor.startSpecificActivity(next, true, false); 6509 return true; 6510 } 6511 6512 // From this point on, if something goes wrong there is no way 6513 // to recover the activity. 6514 try { 6515 next.completeResumeLocked(); 6516 } catch (Exception e) { 6517 // If any exception gets thrown, toss away this 6518 // activity and try the next one. 6519 Slog.w(TAG, "Exception thrown during resume of " + next, e); 6520 next.finishIfPossible("resume-exception", true /* oomAdj */); 6521 return true; 6522 } 6523 } else { 6524 // Whoops, need to restart this activity! 6525 if (!next.hasBeenLaunched) { 6526 next.hasBeenLaunched = true; 6527 } else { 6528 if (SHOW_APP_STARTING_PREVIEW) { 6529 next.showStartingWindow(false /* taskSwich */); 6530 } 6531 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next); 6532 } 6533 ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Restarting %s", next); 6534 mTaskSupervisor.startSpecificActivity(next, true, true); 6535 } 6536 6537 return true; 6538 } 6539 6540 /** 6541 * Resume the next eligible activity in a focusable root task when this one does not have any 6542 * running activities left. The focus will be adjusted to the next focusable root task and 6543 * top running activities will be resumed in all focusable root tasks. However, if the 6544 * current root task is a root home task - we have to keep it focused, start and resume a 6545 * home activity on the current display instead to make sure that the display is not empty. 6546 */ 6547 private boolean resumeNextFocusableActivityWhenRootTaskIsEmpty(ActivityRecord prev, 6548 ActivityOptions options) { 6549 final String reason = "noMoreActivities"; 6550 6551 if (!isActivityTypeHome()) { 6552 final Task nextFocusedTask = adjustFocusToNextFocusableTask(reason); 6553 if (nextFocusedTask != null) { 6554 // Try to move focus to the next visible root task with a running activity if this 6555 // root task is not covering the entire screen or is on a secondary display with 6556 // no home root task. 6557 return mRootWindowContainer.resumeFocusedTasksTopActivities(nextFocusedTask, 6558 prev, null /* targetOptions */); 6559 } 6560 } 6561 6562 // If the current root task is a root home task, or if focus didn't switch to a different 6563 // root task - just start up the Launcher... 6564 ActivityOptions.abort(options); 6565 ProtoLog.d(WM_DEBUG_STATES, "resumeNextFocusableActivityWhenRootTaskIsEmpty: %s, " 6566 + "go home", reason); 6567 return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayArea()); 6568 } 6569 6570 void startActivityLocked(ActivityRecord r, @Nullable ActivityRecord focusedTopActivity, 6571 boolean newTask, boolean keepCurTransition, ActivityOptions options, 6572 @Nullable ActivityRecord sourceRecord) { 6573 Task rTask = r.getTask(); 6574 final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront(); 6575 final boolean isOrhasTask = rTask == this || hasChild(rTask); 6576 // mLaunchTaskBehind tasks get placed at the back of the task stack. 6577 if (!r.mLaunchTaskBehind && allowMoveToFront && (!isOrhasTask || newTask)) { 6578 // Last activity in task had been removed or ActivityManagerService is reusing task. 6579 // Insert or replace. 6580 // Might not even be in. 6581 positionChildAtTop(rTask); 6582 } 6583 Task task = null; 6584 if (!newTask && isOrhasTask) { 6585 // Starting activity cannot be occluding activity, otherwise starting window could be 6586 // remove immediately without transferring to starting activity. 6587 final ActivityRecord occludingActivity = getOccludingActivityAbove(r); 6588 if (occludingActivity != null) { 6589 // Here it is! Now, if this is not yet visible (occluded by another task) to the 6590 // user, then just add it without starting; it will get started when the user 6591 // navigates back to it. 6592 ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to task %s " 6593 + "callers: %s", r, task, 6594 new RuntimeException("here").fillInStackTrace()); 6595 rTask.positionChildAtTop(r); 6596 ActivityOptions.abort(options); 6597 return; 6598 } 6599 } 6600 6601 // Place a new activity at top of root task, so it is next to interact with the user. 6602 6603 // If we are not placing the new activity frontmost, we do not want to deliver the 6604 // onUserLeaving callback to the actual frontmost activity 6605 final Task activityTask = r.getTask(); 6606 if (task == activityTask && mChildren.indexOf(task) != (getChildCount() - 1)) { 6607 mTaskSupervisor.mUserLeaving = false; 6608 if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING, 6609 "startActivity() behind front, mUserLeaving=false"); 6610 } 6611 6612 task = activityTask; 6613 6614 // Slot the activity into the history root task and proceed 6615 ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to task %s " 6616 + "callers: %s", r, task, new RuntimeException("here").fillInStackTrace()); 6617 task.positionChildAtTop(r); 6618 6619 // The transition animation and starting window are not needed if {@code allowMoveToFront} 6620 // is false, because the activity won't be visible. 6621 if ((!isHomeOrRecentsRootTask() || hasActivity()) && allowMoveToFront) { 6622 final DisplayContent dc = mDisplayContent; 6623 if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, 6624 "Prepare open transition: starting " + r); 6625 // TODO(shell-transitions): record NO_ANIMATION flag somewhere. 6626 if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) { 6627 dc.prepareAppTransition(TRANSIT_NONE); 6628 mTaskSupervisor.mNoAnimActivities.add(r); 6629 } else { 6630 int transit = TRANSIT_OLD_ACTIVITY_OPEN; 6631 if (newTask) { 6632 if (r.mLaunchTaskBehind) { 6633 transit = TRANSIT_OLD_TASK_OPEN_BEHIND; 6634 } else { 6635 // If a new task is being launched, then mark the existing top activity as 6636 // supporting picture-in-picture while pausing only if the starting activity 6637 // would not be considered an overlay on top of the current activity 6638 // (eg. not fullscreen, or the assistant) 6639 if (canEnterPipOnTaskSwitch(focusedTopActivity, 6640 null /* toFrontTask */, r, options)) { 6641 focusedTopActivity.supportsEnterPipOnTaskSwitch = true; 6642 } 6643 transit = TRANSIT_OLD_TASK_OPEN; 6644 } 6645 } 6646 dc.prepareAppTransition(TRANSIT_OPEN); 6647 mTaskSupervisor.mNoAnimActivities.remove(r); 6648 } 6649 boolean doShow = true; 6650 if (newTask) { 6651 // Even though this activity is starting fresh, we still need 6652 // to reset it to make sure we apply affinities to move any 6653 // existing activities from other tasks in to it. 6654 // If the caller has requested that the target task be 6655 // reset, then do so. 6656 if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { 6657 resetTaskIfNeeded(r, r); 6658 doShow = topRunningNonDelayedActivityLocked(null) == r; 6659 } 6660 } else if (options != null && options.getAnimationType() 6661 == ActivityOptions.ANIM_SCENE_TRANSITION) { 6662 doShow = false; 6663 } 6664 if (r.mLaunchTaskBehind) { 6665 // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we 6666 // tell WindowManager that r is visible even though it is at the back of the root 6667 // task. 6668 r.setVisibility(true); 6669 ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); 6670 // Go ahead to execute app transition for this activity since the app transition 6671 // will not be triggered through the resume channel. 6672 mDisplayContent.executeAppTransition(); 6673 } else if (SHOW_APP_STARTING_PREVIEW && doShow) { 6674 // Figure out if we are transitioning from another activity that is 6675 // "has the same starting icon" as the next one. This allows the 6676 // window manager to keep the previous window it had previously 6677 // created, if it still had one. 6678 Task prevTask = r.getTask(); 6679 ActivityRecord prev = prevTask.topActivityWithStartingWindow(); 6680 if (prev != null) { 6681 // We don't want to reuse the previous starting preview if: 6682 // (1) The current activity is in a different task. 6683 if (prev.getTask() != prevTask) { 6684 prev = null; 6685 } 6686 // (2) The current activity is already displayed. 6687 else if (prev.nowVisible) { 6688 prev = null; 6689 } 6690 } 6691 6692 r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity), 6693 true /* startActivity */, sourceRecord); 6694 } 6695 } else { 6696 // If this is the first activity, don't do any fancy animations, 6697 // because there is nothing for it to animate on top of. 6698 ActivityOptions.abort(options); 6699 } 6700 } 6701 6702 /** 6703 * @return Whether the switch to another task can trigger the currently running activity to 6704 * enter PiP while it is pausing (if supported). Only one of {@param toFrontTask} or 6705 * {@param toFrontActivity} should be set. 6706 */ 6707 private boolean canEnterPipOnTaskSwitch(ActivityRecord pipCandidate, 6708 Task toFrontTask, ActivityRecord toFrontActivity, ActivityOptions opts) { 6709 if (opts != null && opts.disallowEnterPictureInPictureWhileLaunching()) { 6710 // Ensure the caller has requested not to trigger auto-enter PiP 6711 return false; 6712 } 6713 if (pipCandidate == null || pipCandidate.inPinnedWindowingMode()) { 6714 // Ensure that we do not trigger entering PiP an activity on the root pinned task 6715 return false; 6716 } 6717 final Task targetRootTask = toFrontTask != null 6718 ? toFrontTask.getRootTask() : toFrontActivity.getRootTask(); 6719 if (targetRootTask != null && targetRootTask.isActivityTypeAssistant()) { 6720 // Ensure the task/activity being brought forward is not the assistant 6721 return false; 6722 } 6723 return true; 6724 } 6725 6726 private boolean isTaskSwitch(ActivityRecord r, ActivityRecord topFocusedActivity) { 6727 return topFocusedActivity != null && r.getTask() != topFocusedActivity.getTask(); 6728 } 6729 6730 /** 6731 * Reset the task by reparenting the activities that have same affinity to the task or 6732 * reparenting the activities that have different affinityies out of the task, while these 6733 * activities allow task reparenting. 6734 * 6735 * @param taskTop Top activity of the task might be reset. 6736 * @param newActivity The activity that going to be started. 6737 * @return The non-finishing top activity of the task after reset or the original task top 6738 * activity if all activities within the task are finishing. 6739 */ 6740 ActivityRecord resetTaskIfNeeded(ActivityRecord taskTop, ActivityRecord newActivity) { 6741 final boolean forceReset = 6742 (newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0; 6743 final Task task = taskTop.getTask(); 6744 6745 // If ActivityOptions are moved out and need to be aborted or moved to taskTop. 6746 final ActivityOptions topOptions = sResetTargetTaskHelper.process(task, forceReset); 6747 6748 if (mChildren.contains(task)) { 6749 final ActivityRecord newTop = task.getTopNonFinishingActivity(); 6750 if (newTop != null) { 6751 taskTop = newTop; 6752 } 6753 } 6754 6755 if (topOptions != null) { 6756 // If we got some ActivityOptions from an activity on top that 6757 // was removed from the task, propagate them to the new real top. 6758 taskTop.updateOptionsLocked(topOptions); 6759 } 6760 6761 return taskTop; 6762 } 6763 6764 /** 6765 * Finish the topmost activity that belongs to the crashed app. We may also finish the activity 6766 * that requested launch of the crashed one to prevent launch-crash loop. 6767 * @param app The app that crashed. 6768 * @param reason Reason to perform this action. 6769 * @return The task that was finished in this root task, {@code null} if top running activity 6770 * does not belong to the crashed app. 6771 */ 6772 final Task finishTopCrashedActivityLocked(WindowProcessController app, String reason) { 6773 final ActivityRecord r = topRunningActivity(); 6774 if (r == null || r.app != app) { 6775 return null; 6776 } 6777 if (r.isActivityTypeHome() && mAtmService.mHomeProcess == app) { 6778 // Home activities should not be force-finished as we have nothing else to go 6779 // back to. AppErrors will get to it after two crashes in MIN_CRASH_INTERVAL. 6780 Slog.w(TAG, " Not force finishing home activity " 6781 + r.intent.getComponent().flattenToShortString()); 6782 return null; 6783 } 6784 Slog.w(TAG, " Force finishing activity " 6785 + r.intent.getComponent().flattenToShortString()); 6786 Task finishedTask = r.getTask(); 6787 mDisplayContent.prepareAppTransition(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED); 6788 mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED); 6789 r.finishIfPossible(reason, false /* oomAdj */); 6790 6791 // Also terminate any activities below it that aren't yet stopped, to avoid a situation 6792 // where one will get re-start our crashing activity once it gets resumed again. 6793 final ActivityRecord activityBelow = getActivityBelow(r); 6794 if (activityBelow != null) { 6795 if (activityBelow.isState(STARTED, RESUMED, PAUSING, PAUSED)) { 6796 if (!activityBelow.isActivityTypeHome() 6797 || mAtmService.mHomeProcess != activityBelow.app) { 6798 Slog.w(TAG, " Force finishing activity " 6799 + activityBelow.intent.getComponent().flattenToShortString()); 6800 activityBelow.finishIfPossible(reason, false /* oomAdj */); 6801 } 6802 } 6803 } 6804 6805 return finishedTask; 6806 } 6807 6808 void finishVoiceTask(IVoiceInteractionSession session) { 6809 final PooledConsumer c = PooledLambda.obtainConsumer(Task::finishIfVoiceTask, 6810 PooledLambda.__(Task.class), session.asBinder()); 6811 forAllLeafTasks(c, true /* traverseTopToBottom */); 6812 c.recycle(); 6813 } 6814 6815 private static void finishIfVoiceTask(Task tr, IBinder binder) { 6816 if (tr.voiceSession != null && tr.voiceSession.asBinder() == binder) { 6817 tr.forAllActivities((r) -> { 6818 if (r.finishing) return; 6819 r.finishIfPossible("finish-voice", false /* oomAdj */); 6820 tr.mAtmService.updateOomAdj(); 6821 }); 6822 } else { 6823 // Check if any of the activities are using voice 6824 final PooledFunction f = PooledLambda.obtainFunction( 6825 Task::finishIfVoiceActivity, PooledLambda.__(ActivityRecord.class), 6826 binder); 6827 tr.forAllActivities(f); 6828 f.recycle(); 6829 } 6830 } 6831 6832 private static boolean finishIfVoiceActivity(ActivityRecord r, IBinder binder) { 6833 if (r.voiceSession == null || r.voiceSession.asBinder() != binder) return false; 6834 // Inform of cancellation 6835 r.clearVoiceSessionLocked(); 6836 try { 6837 r.app.getThread().scheduleLocalVoiceInteractionStarted(r.appToken, null); 6838 } catch (RemoteException re) { 6839 // Ok Boomer... 6840 } 6841 r.mAtmService.finishRunningVoiceLocked(); 6842 return true; 6843 } 6844 6845 /** Finish all activities in the root task without waiting. */ 6846 void finishAllActivitiesImmediately() { 6847 if (!hasChild()) { 6848 removeIfPossible("finishAllActivitiesImmediately"); 6849 return; 6850 } 6851 forAllActivities((r) -> { 6852 Slog.d(TAG, "finishAllActivitiesImmediatelyLocked: finishing " + r); 6853 r.destroyIfPossible("finishAllActivitiesImmediately"); 6854 }); 6855 } 6856 6857 /** @return true if the root task behind this one is a standard activity type. */ 6858 private boolean inFrontOfStandardRootTask() { 6859 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 6860 if (taskDisplayArea == null) { 6861 return false; 6862 } 6863 final boolean[] hasFound = new boolean[1]; 6864 final Task rootTaskBehind = taskDisplayArea.getRootTask( 6865 // From top to bottom, find the one behind this Task. 6866 task -> { 6867 if (hasFound[0]) { 6868 return true; 6869 } 6870 if (task == this) { 6871 // The next one is our target. 6872 hasFound[0] = true; 6873 } 6874 return false; 6875 }); 6876 return rootTaskBehind != null && rootTaskBehind.isActivityTypeStandard(); 6877 } 6878 6879 boolean shouldUpRecreateTaskLocked(ActivityRecord srec, String destAffinity) { 6880 // Basic case: for simple app-centric recents, we need to recreate 6881 // the task if the affinity has changed. 6882 6883 final String affinity = ActivityRecord.computeTaskAffinity(destAffinity, srec.getUid(), 6884 srec.launchMode); 6885 if (srec == null || srec.getTask().affinity == null 6886 || !srec.getTask().affinity.equals(affinity)) { 6887 return true; 6888 } 6889 // Document-centric case: an app may be split in to multiple documents; 6890 // they need to re-create their task if this current activity is the root 6891 // of a document, unless simply finishing it will return them to the 6892 // correct app behind. 6893 final Task task = srec.getTask(); 6894 if (srec.isRootOfTask() && task.getBaseIntent() != null 6895 && task.getBaseIntent().isDocument()) { 6896 // Okay, this activity is at the root of its task. What to do, what to do... 6897 if (!inFrontOfStandardRootTask()) { 6898 // Finishing won't return to an application, so we need to recreate. 6899 return true; 6900 } 6901 // We now need to get the task below it to determine what to do. 6902 final Task prevTask = getTaskBelow(task); 6903 if (prevTask == null) { 6904 Slog.w(TAG, "shouldUpRecreateTask: task not in history for " + srec); 6905 return false; 6906 } 6907 if (!task.affinity.equals(prevTask.affinity)) { 6908 // These are different apps, so need to recreate. 6909 return true; 6910 } 6911 } 6912 return false; 6913 } 6914 6915 boolean navigateUpTo(ActivityRecord srec, Intent destIntent, NeededUriGrants destGrants, 6916 int resultCode, Intent resultData, NeededUriGrants resultGrants) { 6917 if (!srec.attachedToProcess()) { 6918 // Nothing to do if the caller is not attached, because this method should be called 6919 // from an alive activity. 6920 return false; 6921 } 6922 final Task task = srec.getTask(); 6923 if (!srec.isDescendantOf(this)) { 6924 return false; 6925 } 6926 6927 ActivityRecord parent = task.getActivityBelow(srec); 6928 boolean foundParentInTask = false; 6929 final ComponentName dest = destIntent.getComponent(); 6930 if (task.getBottomMostActivity() != srec && dest != null) { 6931 final ActivityRecord candidate = task.getActivity( 6932 (ar) -> ar.info.packageName.equals(dest.getPackageName()) 6933 && ar.info.name.equals(dest.getClassName()), srec, 6934 false /*includeBoundary*/, true /*traverseTopToBottom*/); 6935 if (candidate != null) { 6936 parent = candidate; 6937 foundParentInTask = true; 6938 } 6939 } 6940 6941 // TODO: There is a dup. of this block of code in ActivityTaskManagerService.finishActivity 6942 // We should consolidate. 6943 IActivityController controller = mAtmService.mController; 6944 if (controller != null) { 6945 ActivityRecord next = topRunningActivity(srec.appToken, INVALID_TASK_ID); 6946 if (next != null) { 6947 // ask watcher if this is allowed 6948 boolean resumeOK = true; 6949 try { 6950 resumeOK = controller.activityResuming(next.packageName); 6951 } catch (RemoteException e) { 6952 mAtmService.mController = null; 6953 Watchdog.getInstance().setActivityController(null); 6954 } 6955 6956 if (!resumeOK) { 6957 return false; 6958 } 6959 } 6960 } 6961 final long origId = Binder.clearCallingIdentity(); 6962 6963 final int[] resultCodeHolder = new int[1]; 6964 resultCodeHolder[0] = resultCode; 6965 final Intent[] resultDataHolder = new Intent[1]; 6966 resultDataHolder[0] = resultData; 6967 final NeededUriGrants[] resultGrantsHolder = new NeededUriGrants[1]; 6968 resultGrantsHolder[0] = resultGrants; 6969 final ActivityRecord finalParent = parent; 6970 task.forAllActivities((ar) -> { 6971 if (ar == finalParent) return true; 6972 6973 ar.finishIfPossible(resultCodeHolder[0], resultDataHolder[0], resultGrantsHolder[0], 6974 "navigate-up", true /* oomAdj */); 6975 // Only return the supplied result for the first activity finished 6976 resultCodeHolder[0] = Activity.RESULT_CANCELED; 6977 resultDataHolder[0] = null; 6978 return false; 6979 }, srec, true, true); 6980 resultCode = resultCodeHolder[0]; 6981 resultData = resultDataHolder[0]; 6982 6983 if (parent != null && foundParentInTask) { 6984 final int callingUid = srec.info.applicationInfo.uid; 6985 final int parentLaunchMode = parent.info.launchMode; 6986 final int destIntentFlags = destIntent.getFlags(); 6987 if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || 6988 parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK || 6989 parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP || 6990 (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { 6991 parent.deliverNewIntentLocked(callingUid, destIntent, destGrants, srec.packageName); 6992 } else { 6993 try { 6994 ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( 6995 destIntent.getComponent(), ActivityManagerService.STOCK_PM_FLAGS, 6996 srec.mUserId); 6997 // TODO(b/64750076): Check if calling pid should really be -1. 6998 final int res = mAtmService.getActivityStartController() 6999 .obtainStarter(destIntent, "navigateUpTo") 7000 .setCaller(srec.app.getThread()) 7001 .setActivityInfo(aInfo) 7002 .setResultTo(parent.appToken) 7003 .setCallingPid(-1) 7004 .setCallingUid(callingUid) 7005 .setCallingPackage(srec.packageName) 7006 .setCallingFeatureId(parent.launchedFromFeatureId) 7007 .setRealCallingPid(-1) 7008 .setRealCallingUid(callingUid) 7009 .setComponentSpecified(true) 7010 .execute(); 7011 foundParentInTask = res == ActivityManager.START_SUCCESS; 7012 } catch (RemoteException e) { 7013 foundParentInTask = false; 7014 } 7015 parent.finishIfPossible(resultCode, resultData, resultGrants, 7016 "navigate-top", true /* oomAdj */); 7017 } 7018 } 7019 Binder.restoreCallingIdentity(origId); 7020 return foundParentInTask; 7021 } 7022 7023 void removeLaunchTickMessages() { 7024 forAllActivities(ActivityRecord::removeLaunchTickRunnable); 7025 } 7026 7027 private void updateTransitLocked(@WindowManager.TransitionType int transit, 7028 ActivityOptions options) { 7029 if (options != null) { 7030 ActivityRecord r = topRunningActivity(); 7031 if (r != null && !r.isState(RESUMED)) { 7032 r.updateOptionsLocked(options); 7033 } else { 7034 ActivityOptions.abort(options); 7035 } 7036 } 7037 mDisplayContent.prepareAppTransition(transit); 7038 } 7039 7040 final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options, 7041 AppTimeTracker timeTracker, String reason) { 7042 moveTaskToFront(tr, noAnimation, options, timeTracker, !DEFER_RESUME, reason); 7043 } 7044 7045 final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options, 7046 AppTimeTracker timeTracker, boolean deferResume, String reason) { 7047 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr); 7048 7049 final Task topRootTask = getDisplayArea().getTopRootTask(); 7050 final ActivityRecord topActivity = topRootTask != null 7051 ? topRootTask.getTopNonFinishingActivity() : null; 7052 7053 if (tr != this && !tr.isDescendantOf(this)) { 7054 // nothing to do! 7055 if (noAnimation) { 7056 ActivityOptions.abort(options); 7057 } else { 7058 updateTransitLocked(TRANSIT_TO_FRONT, options); 7059 } 7060 return; 7061 } 7062 7063 if (timeTracker != null) { 7064 // The caller wants a time tracker associated with this task. 7065 final PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setAppTimeTracker, 7066 PooledLambda.__(ActivityRecord.class), timeTracker); 7067 tr.forAllActivities(c); 7068 c.recycle(); 7069 } 7070 7071 try { 7072 // Defer updating the IME target since the new IME target will try to get computed 7073 // before updating all closing and opening apps, which can cause the ime target to 7074 // get calculated incorrectly. 7075 mDisplayContent.deferUpdateImeTarget(); 7076 7077 // Don't refocus if invisible to current user 7078 final ActivityRecord top = tr.getTopNonFinishingActivity(); 7079 if (top == null || !top.okToShowLocked()) { 7080 positionChildAtTop(tr); 7081 if (top != null) { 7082 mTaskSupervisor.mRecentTasks.add(top.getTask()); 7083 } 7084 ActivityOptions.abort(options); 7085 return; 7086 } 7087 7088 // Set focus to the top running activity of this task and move all its parents to top. 7089 top.moveFocusableActivityToTop(reason); 7090 7091 if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr); 7092 if (noAnimation) { 7093 mDisplayContent.prepareAppTransition(TRANSIT_NONE); 7094 mTaskSupervisor.mNoAnimActivities.add(top); 7095 ActivityOptions.abort(options); 7096 } else { 7097 updateTransitLocked(TRANSIT_TO_FRONT, options); 7098 } 7099 7100 // If a new task is moved to the front, then mark the existing top activity as 7101 // supporting 7102 7103 // picture-in-picture while paused only if the task would not be considered an oerlay 7104 // on top 7105 // of the current activity (eg. not fullscreen, or the assistant) 7106 if (canEnterPipOnTaskSwitch(topActivity, tr, null /* toFrontActivity */, 7107 options)) { 7108 topActivity.supportsEnterPipOnTaskSwitch = true; 7109 } 7110 7111 if (!deferResume) { 7112 mRootWindowContainer.resumeFocusedTasksTopActivities(); 7113 } 7114 } finally { 7115 mDisplayContent.continueUpdateImeTarget(); 7116 } 7117 } 7118 7119 /** 7120 * Worker method for rearranging history task. Implements the function of moving all 7121 * activities for a specific task (gathering them if disjoint) into a single group at the 7122 * bottom of the root task. 7123 * 7124 * If a watcher is installed, the action is preflighted and the watcher has an opportunity 7125 * to premeptively cancel the move. 7126 * 7127 * @param tr The task to collect and move to the bottom. 7128 * @return Returns true if the move completed, false if not. 7129 */ 7130 boolean moveTaskToBack(Task tr) { 7131 Slog.i(TAG, "moveTaskToBack: " + tr); 7132 7133 // In LockTask mode, moving a locked task to the back of the root task may expose unlocked 7134 // ones. Therefore we need to check if this operation is allowed. 7135 if (!mAtmService.getLockTaskController().canMoveTaskToBack(tr)) { 7136 return false; 7137 } 7138 7139 // If we have a watcher, preflight the move before committing to it. First check 7140 // for *other* available tasks, but if none are available, then try again allowing the 7141 // current task to be selected. 7142 if (isTopRootTaskInDisplayArea() && mAtmService.mController != null) { 7143 ActivityRecord next = topRunningActivity(null, tr.mTaskId); 7144 if (next == null) { 7145 next = topRunningActivity(null, INVALID_TASK_ID); 7146 } 7147 if (next != null) { 7148 // ask watcher if this is allowed 7149 boolean moveOK = true; 7150 try { 7151 moveOK = mAtmService.mController.activityResuming(next.packageName); 7152 } catch (RemoteException e) { 7153 mAtmService.mController = null; 7154 Watchdog.getInstance().setActivityController(null); 7155 } 7156 if (!moveOK) { 7157 return false; 7158 } 7159 } 7160 } 7161 7162 if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task=" 7163 + tr.mTaskId); 7164 7165 // Skip the transition for pinned task. 7166 if (!inPinnedWindowingMode()) { 7167 mDisplayContent.prepareAppTransition(TRANSIT_TO_BACK); 7168 mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_TO_BACK, tr); 7169 } 7170 moveToBack("moveTaskToBackLocked", tr); 7171 7172 if (inPinnedWindowingMode()) { 7173 mTaskSupervisor.removeRootTask(this); 7174 return true; 7175 } 7176 7177 mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */, 7178 mDisplayContent.mDisplayId, false /* markFrozenIfConfigChanged */, 7179 false /* deferResume */); 7180 7181 ActivityRecord topActivity = getDisplayArea().topRunningActivity(); 7182 Task topRootTask = topActivity.getRootTask(); 7183 if (topRootTask != null && topRootTask != this && topActivity.isState(RESUMED)) { 7184 // Usually resuming a top activity triggers the next app transition, but nothing's got 7185 // resumed in this case, so we need to execute it explicitly. 7186 mDisplayContent.executeAppTransition(); 7187 } else { 7188 mRootWindowContainer.resumeFocusedTasksTopActivities(); 7189 } 7190 return true; 7191 } 7192 7193 /** 7194 * Ensures all visible activities at or below the input activity have the right configuration. 7195 */ 7196 void ensureVisibleActivitiesConfiguration(ActivityRecord start, boolean preserveWindow) { 7197 mEnsureVisibleActivitiesConfigHelper.process(start, preserveWindow); 7198 } 7199 7200 // TODO: Can only be called from special methods in ActivityTaskSupervisor. 7201 // Need to consolidate those calls points into this resize method so anyone can call directly. 7202 void resize(Rect displayedBounds, boolean preserveWindows, boolean deferResume) { 7203 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "task.resize_" + getRootTaskId()); 7204 mAtmService.deferWindowLayout(); 7205 try { 7206 // TODO: Why not just set this on the root task directly vs. on each tasks? 7207 // Update override configurations of all tasks in the root task. 7208 final PooledConsumer c = PooledLambda.obtainConsumer( 7209 Task::processTaskResizeBounds, PooledLambda.__(Task.class), 7210 displayedBounds); 7211 forAllTasks(c, true /* traverseTopToBottom */); 7212 c.recycle(); 7213 7214 if (!deferResume) { 7215 ensureVisibleActivitiesConfiguration(topRunningActivity(), preserveWindows); 7216 } 7217 } finally { 7218 mAtmService.continueWindowLayout(); 7219 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 7220 } 7221 } 7222 7223 private static void processTaskResizeBounds(Task task, Rect displayedBounds) { 7224 if (!task.isResizeable()) return; 7225 7226 task.setBounds(displayedBounds); 7227 } 7228 7229 boolean willActivityBeVisible(IBinder token) { 7230 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 7231 if (r == null) { 7232 return false; 7233 } 7234 7235 // See if there is an occluding activity on-top of this one. 7236 final ActivityRecord occludingActivity = getOccludingActivityAbove(r); 7237 if (occludingActivity != null) return false; 7238 7239 if (r.finishing) Slog.e(TAG, "willActivityBeVisible: Returning false," 7240 + " would have returned true for r=" + r); 7241 return !r.finishing; 7242 } 7243 7244 void unhandledBackLocked() { 7245 final ActivityRecord topActivity = getTopMostActivity(); 7246 if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, 7247 "Performing unhandledBack(): top activity: " + topActivity); 7248 if (topActivity != null) { 7249 topActivity.finishIfPossible("unhandled-back", true /* oomAdj */); 7250 } 7251 } 7252 7253 /** 7254 * Reset local parameters because an app's activity died. 7255 * @param app The app of the activity that died. 7256 * @return {@code true} if the process of the pausing activity is died. 7257 */ 7258 boolean handleAppDied(WindowProcessController app) { 7259 warnForNonLeafTask("handleAppDied"); 7260 boolean isPausingDied = false; 7261 if (mPausingActivity != null && mPausingActivity.app == app) { 7262 ProtoLog.v(WM_DEBUG_STATES, "App died while pausing: %s", 7263 mPausingActivity); 7264 mPausingActivity = null; 7265 isPausingDied = true; 7266 } 7267 if (mLastPausedActivity != null && mLastPausedActivity.app == app) { 7268 if (mLastPausedActivity.isNoHistory()) { 7269 mTaskSupervisor.mNoHistoryActivities.remove(mLastPausedActivity); 7270 } 7271 mLastPausedActivity = null; 7272 } 7273 return isPausingDied; 7274 } 7275 7276 boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, 7277 String dumpPackage, final boolean needSep) { 7278 Runnable headerPrinter = () -> { 7279 if (needSep) { 7280 pw.println(); 7281 } 7282 pw.println(" RootTask #" + getRootTaskId() 7283 + ": type=" + activityTypeToString(getActivityType()) 7284 + " mode=" + windowingModeToString(getWindowingMode())); 7285 pw.println(" isSleeping=" + shouldSleepActivities()); 7286 pw.println(" mBounds=" + getRequestedOverrideBounds()); 7287 pw.println(" mCreatedByOrganizer=" + mCreatedByOrganizer); 7288 }; 7289 7290 boolean printed = false; 7291 7292 if (dumpPackage == null) { 7293 // If we are not filtering by package, we want to print absolutely everything, 7294 // so always print the header even if there are no tasks/activities inside. 7295 headerPrinter.run(); 7296 headerPrinter = null; 7297 printed = true; 7298 } 7299 7300 printed |= printThisActivity(pw, getPausingActivity(), dumpPackage, false, 7301 " mPausingActivity: ", null); 7302 printed |= printThisActivity(pw, getResumedActivity(), dumpPackage, false, 7303 " mResumedActivity: ", null); 7304 if (dumpAll) { 7305 printed |= printThisActivity(pw, mLastPausedActivity, dumpPackage, false, 7306 " mLastPausedActivity: ", null); 7307 } 7308 7309 printed |= dumpActivities(fd, pw, dumpAll, dumpClient, dumpPackage, false, headerPrinter); 7310 7311 return printed; 7312 } 7313 7314 private boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll, 7315 boolean dumpClient, String dumpPackage, boolean needSep, Runnable header) { 7316 if (!hasChild()) { 7317 return false; 7318 } 7319 final AtomicBoolean printedHeader = new AtomicBoolean(false); 7320 final AtomicBoolean printed = new AtomicBoolean(false); 7321 forAllLeafTasks((task) -> { 7322 final String prefix = " "; 7323 Runnable headerPrinter = () -> { 7324 printed.set(true); 7325 if (!printedHeader.get()) { 7326 if (needSep) { 7327 pw.println(""); 7328 } 7329 if (header != null) { 7330 header.run(); 7331 } 7332 printedHeader.set(true); 7333 } 7334 pw.print(prefix); pw.print("* "); pw.println(task); 7335 pw.print(prefix); pw.print(" mBounds="); 7336 pw.println(task.getRequestedOverrideBounds()); 7337 pw.print(prefix); pw.print(" mMinWidth="); pw.print(task.mMinWidth); 7338 pw.print(" mMinHeight="); pw.println(task.mMinHeight); 7339 if (mLastNonFullscreenBounds != null) { 7340 pw.print(prefix); 7341 pw.print(" mLastNonFullscreenBounds="); 7342 pw.println(task.mLastNonFullscreenBounds); 7343 } 7344 task.dump(pw, prefix + " "); 7345 }; 7346 if (dumpPackage == null) { 7347 // If we are not filtering by package, we want to print absolutely everything, 7348 // so always print the header even if there are no activities inside. 7349 headerPrinter.run(); 7350 headerPrinter = null; 7351 } 7352 final ArrayList<ActivityRecord> activities = new ArrayList<>(); 7353 // Add activities by traversing the hierarchy from bottom to top, since activities 7354 // are dumped in reverse order in {@link ActivityTaskSupervisor#dumpHistoryList()}. 7355 task.forAllActivities((Consumer<ActivityRecord>) activities::add, 7356 false /* traverseTopToBottom */); 7357 dumpHistoryList(fd, pw, activities, prefix, "Hist", true, !dumpAll, dumpClient, 7358 dumpPackage, false, headerPrinter, task); 7359 }, true /* traverseTopToBottom */); 7360 return printed.get(); 7361 } 7362 7363 ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) { 7364 ArrayList<ActivityRecord> activities = new ArrayList<>(); 7365 7366 if ("all".equals(name)) { 7367 forAllActivities((Consumer<ActivityRecord>) activities::add); 7368 } else if ("top".equals(name)) { 7369 final ActivityRecord topActivity = getTopMostActivity(); 7370 if (topActivity != null) { 7371 activities.add(topActivity); 7372 } 7373 } else { 7374 ActivityManagerService.ItemMatcher matcher = new ActivityManagerService.ItemMatcher(); 7375 matcher.build(name); 7376 7377 forAllActivities((r) -> { 7378 if (matcher.match(r, r.intent.getComponent())) { 7379 activities.add(r); 7380 } 7381 }); 7382 } 7383 7384 return activities; 7385 } 7386 7387 ActivityRecord restartPackage(String packageName) { 7388 ActivityRecord starting = topRunningActivity(); 7389 7390 // All activities that came from the package must be 7391 // restarted as if there was a config change. 7392 PooledConsumer c = PooledLambda.obtainConsumer(Task::restartPackage, 7393 PooledLambda.__(ActivityRecord.class), starting, packageName); 7394 forAllActivities(c); 7395 c.recycle(); 7396 7397 return starting; 7398 } 7399 7400 private static void restartPackage( 7401 ActivityRecord r, ActivityRecord starting, String packageName) { 7402 if (r.info.packageName.equals(packageName)) { 7403 r.forceNewConfig = true; 7404 if (starting != null && r == starting && r.mVisibleRequested) { 7405 r.startFreezingScreenLocked(CONFIG_SCREEN_LAYOUT); 7406 } 7407 } 7408 } 7409 7410 Task reuseOrCreateTask(ActivityInfo info, Intent intent, boolean toTop) { 7411 return reuseOrCreateTask(info, intent, null /*voiceSession*/, null /*voiceInteractor*/, 7412 toTop, null /*activity*/, null /*source*/, null /*options*/); 7413 } 7414 7415 // TODO: Can be removed once we change callpoints creating root tasks to be creating tasks. 7416 /** Either returns this current task to be re-used or creates a new child task. */ 7417 Task reuseOrCreateTask(ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession, 7418 IVoiceInteractor voiceInteractor, boolean toTop, ActivityRecord activity, 7419 ActivityRecord source, ActivityOptions options) { 7420 7421 Task task; 7422 if (canReuseAsLeafTask()) { 7423 // This root task will only contain one task, so just return itself since all root 7424 // tasks ara now tasks and all tasks are now root tasks. 7425 task = reuseAsLeafTask(voiceSession, voiceInteractor, intent, info, activity); 7426 } else { 7427 // Create child task since this root task can contain multiple tasks. 7428 final int taskId = activity != null 7429 ? mTaskSupervisor.getNextTaskIdForUser(activity.mUserId) 7430 : mTaskSupervisor.getNextTaskIdForUser(); 7431 task = new Task.Builder(mAtmService) 7432 .setTaskId(taskId) 7433 .setActivityInfo(info) 7434 .setActivityOptions(options) 7435 .setIntent(intent) 7436 .setVoiceSession(voiceSession) 7437 .setVoiceInteractor(voiceInteractor) 7438 .setOnTop(toTop) 7439 .setParent(this) 7440 .build(); 7441 } 7442 7443 int displayId = getDisplayId(); 7444 if (displayId == INVALID_DISPLAY) displayId = DEFAULT_DISPLAY; 7445 final boolean isLockscreenShown = mAtmService.mTaskSupervisor.getKeyguardController() 7446 .isKeyguardOrAodShowing(displayId); 7447 if (!mTaskSupervisor.getLaunchParamsController() 7448 .layoutTask(task, info.windowLayout, activity, source, options) 7449 && !getRequestedOverrideBounds().isEmpty() 7450 && task.isResizeable() && !isLockscreenShown) { 7451 task.setBounds(getRequestedOverrideBounds()); 7452 } 7453 7454 return task; 7455 } 7456 7457 /** Return {@code true} if this task can be reused as leaf task. */ 7458 private boolean canReuseAsLeafTask() { 7459 // Cannot be reused as leaf task if this task is created by organizer or having child tasks. 7460 if (mCreatedByOrganizer || !isLeafTask()) { 7461 return false; 7462 } 7463 7464 // Existing Tasks can be reused if a new root task will be created anyway, or for the 7465 // Dream - because there can only ever be one DreamActivity. 7466 final int windowingMode = getWindowingMode(); 7467 final int activityType = getActivityType(); 7468 return DisplayContent.alwaysCreateRootTask(windowingMode, activityType) 7469 || activityType == ACTIVITY_TYPE_DREAM; 7470 } 7471 7472 void addChild(WindowContainer child, final boolean toTop, boolean showForAllUsers) { 7473 Task task = child.asTask(); 7474 try { 7475 if (task != null) { 7476 task.setForceShowForAllUsers(showForAllUsers); 7477 } 7478 // We only want to move the parents to the parents if we are creating this task at the 7479 // top of its root task. 7480 addChild(child, toTop ? MAX_VALUE : 0, toTop /*moveParents*/); 7481 } finally { 7482 if (task != null) { 7483 task.setForceShowForAllUsers(false); 7484 } 7485 } 7486 } 7487 7488 public void setAlwaysOnTop(boolean alwaysOnTop) { 7489 // {@link #isAwaysonTop} overrides the original behavior which also evaluates if this 7490 // task is force hidden, so super.isAlwaysOnTop() is used here to see whether the 7491 // alwaysOnTop attributes should be updated. 7492 if (super.isAlwaysOnTop() == alwaysOnTop) { 7493 return; 7494 } 7495 super.setAlwaysOnTop(alwaysOnTop); 7496 // positionChildAtTop() must be called even when always on top gets turned off because we 7497 // need to make sure that the root task is moved from among always on top windows to 7498 // below other always on top windows. Since the position the root task should be inserted 7499 // into is calculated properly in {@link DisplayContent#getTopInsertPosition()} in both 7500 // cases, we can just request that the root task is put at top here. 7501 // Don't bother moving task to top if this task is force hidden and invisible to user. 7502 if (!isForceHidden()) { 7503 getDisplayArea().positionChildAt(POSITION_TOP, this, false /* includingParents */); 7504 } 7505 } 7506 7507 void dismissPip() { 7508 if (!isActivityTypeStandardOrUndefined()) { 7509 throw new IllegalArgumentException( 7510 "You can't move tasks from non-standard root tasks."); 7511 } 7512 if (getWindowingMode() != WINDOWING_MODE_PINNED) { 7513 throw new IllegalArgumentException( 7514 "Can't exit pinned mode if it's not pinned already."); 7515 } 7516 7517 mWmService.inSurfaceTransaction(() -> { 7518 final Task task = getBottomMostTask(); 7519 setWindowingMode(WINDOWING_MODE_UNDEFINED); 7520 7521 // Task could have been removed from the hierarchy due to windowing mode change 7522 // where its only child is reparented back to their original parent task. 7523 if (isAttached()) { 7524 getDisplayArea().positionChildAt(POSITION_TOP, this, false /* includingParents */); 7525 } 7526 7527 mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this); 7528 }); 7529 } 7530 7531 private int setBounds(Rect existing, Rect bounds) { 7532 if (equivalentBounds(existing, bounds)) { 7533 return BOUNDS_CHANGE_NONE; 7534 } 7535 7536 final int result = super.setBounds(!inMultiWindowMode() ? null : bounds); 7537 7538 updateSurfaceBounds(); 7539 return result; 7540 } 7541 7542 @Override 7543 public void getBounds(Rect bounds) { 7544 bounds.set(getBounds()); 7545 } 7546 7547 /** 7548 * Put a Task in this root task. Used for adding only. 7549 * When task is added to top of the root task, the entire branch of the hierarchy (including 7550 * root task and display) will be brought to top. 7551 * @param child The child to add. 7552 * @param position Target position to add the task to. 7553 */ 7554 private void addChild(WindowContainer child, int position, boolean moveParents) { 7555 // Add child task. 7556 addChild(child, null); 7557 7558 // Move child to a proper position, as some restriction for position might apply. 7559 positionChildAt(position, child, moveParents /* includingParents */); 7560 } 7561 7562 void positionChildAtTop(Task child) { 7563 if (child == null) { 7564 // TODO: Fix the call-points that cause this to happen. 7565 return; 7566 } 7567 7568 if (child == this) { 7569 // TODO: Fix call-points 7570 moveToFront("positionChildAtTop"); 7571 return; 7572 } 7573 7574 positionChildAt(POSITION_TOP, child, true /* includingParents */); 7575 7576 final DisplayContent displayContent = getDisplayContent(); 7577 displayContent.layoutAndAssignWindowLayersIfNeeded(); 7578 } 7579 7580 void positionChildAtBottom(Task child) { 7581 // If there are other focusable root tasks on the display, the z-order of the display 7582 // should not be changed just because a task was placed at the bottom. E.g. if it is 7583 // moving the topmost task to bottom, the next focusable root task on the same display 7584 // should be focused. 7585 final Task nextFocusableRootTask = getDisplayArea().getNextFocusableRootTask( 7586 child.getRootTask(), true /* ignoreCurrent */); 7587 positionChildAtBottom(child, nextFocusableRootTask == null /* includingParents */); 7588 } 7589 7590 @VisibleForTesting 7591 void positionChildAtBottom(Task child, boolean includingParents) { 7592 if (child == null) { 7593 // TODO: Fix the call-points that cause this to happen. 7594 return; 7595 } 7596 7597 positionChildAt(POSITION_BOTTOM, child, includingParents); 7598 getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); 7599 } 7600 7601 @Override 7602 void onChildPositionChanged(WindowContainer child) { 7603 dispatchTaskInfoChangedIfNeeded(false /* force */); 7604 7605 if (!mChildren.contains(child)) { 7606 return; 7607 } 7608 if (child.asTask() != null) { 7609 // Non-root task position changed. 7610 mRootWindowContainer.invalidateTaskLayers(); 7611 } 7612 7613 final boolean isTop = getTopChild() == child; 7614 if (isTop) { 7615 final DisplayContent displayContent = getDisplayContent(); 7616 displayContent.layoutAndAssignWindowLayersIfNeeded(); 7617 } 7618 } 7619 7620 void reparent(TaskDisplayArea newParent, boolean onTop) { 7621 reparent(newParent, onTop ? POSITION_TOP : POSITION_BOTTOM); 7622 } 7623 7624 void setLastRecentsAnimationTransaction(@NonNull PictureInPictureSurfaceTransaction transaction, 7625 @Nullable SurfaceControl overlay) { 7626 mLastRecentsAnimationTransaction = new PictureInPictureSurfaceTransaction(transaction); 7627 mLastRecentsAnimationOverlay = overlay; 7628 } 7629 7630 void clearLastRecentsAnimationTransaction(boolean forceRemoveOverlay) { 7631 if (forceRemoveOverlay && mLastRecentsAnimationOverlay != null) { 7632 getPendingTransaction().remove(mLastRecentsAnimationOverlay); 7633 } 7634 mLastRecentsAnimationTransaction = null; 7635 mLastRecentsAnimationOverlay = null; 7636 // reset also the crop and transform introduced by mLastRecentsAnimationTransaction 7637 getPendingTransaction().setMatrix(mSurfaceControl, Matrix.IDENTITY_MATRIX, new float[9]) 7638 .setWindowCrop(mSurfaceControl, null) 7639 .setCornerRadius(mSurfaceControl, 0); 7640 } 7641 7642 void maybeApplyLastRecentsAnimationTransaction() { 7643 if (mLastRecentsAnimationTransaction != null) { 7644 final SurfaceControl.Transaction tx = getPendingTransaction(); 7645 if (mLastRecentsAnimationOverlay != null) { 7646 tx.reparent(mLastRecentsAnimationOverlay, mSurfaceControl); 7647 } 7648 PictureInPictureSurfaceTransaction.apply(mLastRecentsAnimationTransaction, 7649 mSurfaceControl, tx); 7650 // If we are transferring the transform from the root task entering PIP, then also show 7651 // the new task immediately 7652 tx.show(mSurfaceControl); 7653 mLastRecentsAnimationTransaction = null; 7654 mLastRecentsAnimationOverlay = null; 7655 } 7656 } 7657 7658 private void updateSurfaceBounds() { 7659 updateSurfaceSize(getSyncTransaction()); 7660 updateSurfacePositionNonOrganized(); 7661 scheduleAnimation(); 7662 } 7663 7664 @Override 7665 void getRelativePosition(Point outPos) { 7666 super.getRelativePosition(outPos); 7667 final int outset = getTaskOutset(); 7668 outPos.x -= outset; 7669 outPos.y -= outset; 7670 } 7671 7672 private Point getRelativePosition() { 7673 Point position = new Point(); 7674 getRelativePosition(position); 7675 return position; 7676 } 7677 7678 boolean shouldIgnoreInput() { 7679 if (inSplitScreenPrimaryWindowingMode() && !isFocusable()) { 7680 return true; 7681 } 7682 if (mAtmService.mHasLeanbackFeature && inPinnedWindowingMode() 7683 && !isFocusedRootTaskOnDisplay()) { 7684 // Preventing Picture-in-Picture root task from receiving input on TVs. 7685 return true; 7686 } 7687 return false; 7688 } 7689 7690 /** 7691 * Simply check and give warning logs if this is not operated on leaf task. 7692 */ 7693 private void warnForNonLeafTask(String func) { 7694 if (!isLeafTask()) { 7695 Slog.w(TAG, func + " on non-leaf task " + this); 7696 } 7697 } 7698 7699 /** 7700 * Sets the current picture-in-picture aspect ratio. 7701 */ 7702 void setPictureInPictureAspectRatio(float aspectRatio) { 7703 if (!mWmService.mAtmService.mSupportsPictureInPicture) { 7704 return; 7705 } 7706 7707 final DisplayContent displayContent = getDisplayContent(); 7708 if (displayContent == null) { 7709 return; 7710 } 7711 7712 if (!inPinnedWindowingMode()) { 7713 return; 7714 } 7715 7716 final PinnedTaskController pinnedTaskController = 7717 getDisplayContent().getPinnedTaskController(); 7718 7719 if (Float.compare(aspectRatio, pinnedTaskController.getAspectRatio()) == 0) { 7720 return; 7721 } 7722 7723 // Notify the pinned stack controller about aspect ratio change. 7724 // This would result a callback delivered from SystemUI to WM to start animation, 7725 // if the bounds are ought to be altered due to aspect ratio change. 7726 pinnedTaskController.setAspectRatio( 7727 pinnedTaskController.isValidPictureInPictureAspectRatio(aspectRatio) 7728 ? aspectRatio : -1f); 7729 } 7730 7731 /** 7732 * Sets the current picture-in-picture actions. 7733 */ 7734 void setPictureInPictureActions(List<RemoteAction> actions) { 7735 if (!mWmService.mAtmService.mSupportsPictureInPicture) { 7736 return; 7737 } 7738 7739 if (!inPinnedWindowingMode()) { 7740 return; 7741 } 7742 7743 getDisplayContent().getPinnedTaskController().setActions(actions); 7744 } 7745 7746 /** Returns true if a removal action is still being deferred. */ 7747 boolean handleCompleteDeferredRemoval() { 7748 if (isAnimating(TRANSITION | CHILDREN)) { 7749 return true; 7750 } 7751 7752 return super.handleCompleteDeferredRemoval(); 7753 } 7754 7755 public DisplayInfo getDisplayInfo() { 7756 return mDisplayContent.getDisplayInfo(); 7757 } 7758 7759 AnimatingActivityRegistry getAnimatingActivityRegistry() { 7760 return mAnimatingActivityRegistry; 7761 } 7762 7763 void executeAppTransition(ActivityOptions options) { 7764 mDisplayContent.executeAppTransition(); 7765 ActivityOptions.abort(options); 7766 } 7767 7768 boolean shouldSleepActivities() { 7769 final DisplayContent display = mDisplayContent; 7770 7771 // Do not sleep activities in this root task if we're marked as focused and the keyguard 7772 // is in the process of going away. 7773 if (mTaskSupervisor.getKeyguardController().isKeyguardGoingAway() 7774 && isFocusedRootTaskOnDisplay() 7775 // Avoid resuming activities on secondary displays since we don't want bubble 7776 // activities to be resumed while bubble is still collapsed. 7777 // TODO(b/113840485): Having keyguard going away state for secondary displays. 7778 && display.isDefaultDisplay) { 7779 return false; 7780 } 7781 7782 return display != null ? display.isSleeping() : mAtmService.isSleepingLocked(); 7783 } 7784 7785 boolean shouldSleepOrShutDownActivities() { 7786 return shouldSleepActivities() || mAtmService.mShuttingDown; 7787 } 7788 7789 private Rect getRawBounds() { 7790 return super.getBounds(); 7791 } 7792 7793 void dispatchTaskInfoChangedIfNeeded(boolean force) { 7794 if (isOrganized()) { 7795 mAtmService.mTaskOrganizerController.onTaskInfoChanged(this, force); 7796 } 7797 } 7798 7799 @Override 7800 public void dumpDebug(ProtoOutputStream proto, long fieldId, 7801 @WindowTraceLogLevel int logLevel) { 7802 if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { 7803 return; 7804 } 7805 7806 final long token = proto.start(fieldId); 7807 super.dumpDebug(proto, WINDOW_CONTAINER, logLevel); 7808 7809 proto.write(TaskProto.ID, mTaskId); 7810 proto.write(DISPLAY_ID, getDisplayId()); 7811 proto.write(ROOT_TASK_ID, getRootTaskId()); 7812 7813 if (mResumedActivity != null) { 7814 mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY); 7815 } 7816 if (realActivity != null) { 7817 proto.write(REAL_ACTIVITY, realActivity.flattenToShortString()); 7818 } 7819 if (origActivity != null) { 7820 proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString()); 7821 } 7822 proto.write(ACTIVITY_TYPE, getActivityType()); 7823 proto.write(RESIZE_MODE, mResizeMode); 7824 proto.write(MIN_WIDTH, mMinWidth); 7825 proto.write(MIN_HEIGHT, mMinHeight); 7826 7827 proto.write(FILLS_PARENT, matchParentBounds()); 7828 getRawBounds().dumpDebug(proto, BOUNDS); 7829 7830 if (mLastNonFullscreenBounds != null) { 7831 mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS); 7832 } 7833 7834 if (mSurfaceControl != null) { 7835 proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth()); 7836 proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight()); 7837 } 7838 7839 proto.write(CREATED_BY_ORGANIZER, mCreatedByOrganizer); 7840 proto.write(AFFINITY, affinity); 7841 proto.write(HAS_CHILD_PIP_ACTIVITY, mChildPipActivity != null); 7842 7843 proto.end(token); 7844 } 7845 7846 static class Builder { 7847 private final ActivityTaskManagerService mAtmService; 7848 private WindowContainer mParent; 7849 private int mTaskId; 7850 private Intent mIntent; 7851 private Intent mAffinityIntent; 7852 private String mAffinity; 7853 private String mRootAffinity; 7854 private ComponentName mRealActivity; 7855 private ComponentName mOrigActivity; 7856 private boolean mRootWasReset; 7857 private boolean mAutoRemoveRecents; 7858 private boolean mAskedCompatMode; 7859 private int mUserId; 7860 private int mEffectiveUid; 7861 private String mLastDescription; 7862 private long mLastTimeMoved; 7863 private boolean mNeverRelinquishIdentity; 7864 private TaskDescription mLastTaskDescription; 7865 private PersistedTaskSnapshotData mLastSnapshotData; 7866 private int mTaskAffiliation; 7867 private int mPrevAffiliateTaskId = INVALID_TASK_ID; 7868 private int mNextAffiliateTaskId = INVALID_TASK_ID; 7869 private int mCallingUid; 7870 private String mCallingPackage; 7871 private String mCallingFeatureId; 7872 private int mResizeMode; 7873 private boolean mSupportsPictureInPicture; 7874 private boolean mRealActivitySuspended; 7875 private boolean mUserSetupComplete; 7876 private int mMinWidth = INVALID_MIN_SIZE; 7877 private int mMinHeight = INVALID_MIN_SIZE; 7878 private ActivityInfo mActivityInfo; 7879 private ActivityOptions mActivityOptions; 7880 private IVoiceInteractionSession mVoiceSession; 7881 private IVoiceInteractor mVoiceInteractor; 7882 private int mActivityType; 7883 private int mWindowingMode = WINDOWING_MODE_UNDEFINED; 7884 private boolean mCreatedByOrganizer; 7885 private boolean mDeferTaskAppear; 7886 private IBinder mLaunchCookie; 7887 private boolean mOnTop; 7888 private boolean mHasBeenVisible; 7889 private boolean mRemoveWithTaskOrganizer; 7890 7891 /** 7892 * Records the source task that requesting to build a new task, used to determine which of 7893 * the adjacent roots should be launch root of the new task. 7894 */ 7895 private Task mSourceTask; 7896 7897 /** 7898 * Records launch flags to apply when launching new task. 7899 */ 7900 private int mLaunchFlags; 7901 7902 Builder(ActivityTaskManagerService atm) { 7903 mAtmService = atm; 7904 } 7905 7906 Builder setParent(WindowContainer parent) { 7907 mParent = parent; 7908 return this; 7909 } 7910 7911 Builder setSourceTask(Task sourceTask) { 7912 mSourceTask = sourceTask; 7913 return this; 7914 } 7915 7916 Builder setLaunchFlags(int launchFlags) { 7917 mLaunchFlags = launchFlags; 7918 return this; 7919 } 7920 7921 Builder setTaskId(int taskId) { 7922 mTaskId = taskId; 7923 return this; 7924 } 7925 7926 Builder setIntent(Intent intent) { 7927 mIntent = intent; 7928 return this; 7929 } 7930 7931 Builder setRealActivity(ComponentName realActivity) { 7932 mRealActivity = realActivity; 7933 return this; 7934 } 7935 7936 Builder setEffectiveUid(int effectiveUid) { 7937 mEffectiveUid = effectiveUid; 7938 return this; 7939 } 7940 7941 Builder setMinWidth(int minWidth) { 7942 mMinWidth = minWidth; 7943 return this; 7944 } 7945 7946 Builder setMinHeight(int minHeight) { 7947 mMinHeight = minHeight; 7948 return this; 7949 } 7950 7951 Builder setActivityInfo(ActivityInfo info) { 7952 mActivityInfo = info; 7953 return this; 7954 } 7955 7956 Builder setActivityOptions(ActivityOptions opts) { 7957 mActivityOptions = opts; 7958 return this; 7959 } 7960 7961 Builder setVoiceSession(IVoiceInteractionSession voiceSession) { 7962 mVoiceSession = voiceSession; 7963 return this; 7964 } 7965 7966 Builder setActivityType(int activityType) { 7967 mActivityType = activityType; 7968 return this; 7969 } 7970 7971 int getActivityType() { 7972 return mActivityType; 7973 } 7974 7975 Builder setWindowingMode(int windowingMode) { 7976 mWindowingMode = windowingMode; 7977 return this; 7978 } 7979 7980 int getWindowingMode() { 7981 return mWindowingMode; 7982 } 7983 7984 Builder setCreatedByOrganizer(boolean createdByOrganizer) { 7985 mCreatedByOrganizer = createdByOrganizer; 7986 return this; 7987 } 7988 7989 boolean getCreatedByOrganizer() { 7990 return mCreatedByOrganizer; 7991 } 7992 7993 Builder setDeferTaskAppear(boolean defer) { 7994 mDeferTaskAppear = defer; 7995 return this; 7996 } 7997 7998 Builder setLaunchCookie(IBinder launchCookie) { 7999 mLaunchCookie = launchCookie; 8000 return this; 8001 } 8002 8003 Builder setOnTop(boolean onTop) { 8004 mOnTop = onTop; 8005 return this; 8006 } 8007 8008 Builder setHasBeenVisible(boolean hasBeenVisible) { 8009 mHasBeenVisible = hasBeenVisible; 8010 return this; 8011 } 8012 8013 private Builder setUserId(int userId) { 8014 mUserId = userId; 8015 return this; 8016 } 8017 8018 private Builder setLastTimeMoved(long lastTimeMoved) { 8019 mLastTimeMoved = lastTimeMoved; 8020 return this; 8021 } 8022 8023 private Builder setNeverRelinquishIdentity(boolean neverRelinquishIdentity) { 8024 mNeverRelinquishIdentity = neverRelinquishIdentity; 8025 return this; 8026 } 8027 8028 private Builder setCallingUid(int callingUid) { 8029 mCallingUid = callingUid; 8030 return this; 8031 } 8032 8033 private Builder setCallingPackage(String callingPackage) { 8034 mCallingPackage = callingPackage; 8035 return this; 8036 } 8037 8038 private Builder setResizeMode(int resizeMode) { 8039 mResizeMode = resizeMode; 8040 return this; 8041 } 8042 8043 private Builder setSupportsPictureInPicture(boolean supportsPictureInPicture) { 8044 mSupportsPictureInPicture = supportsPictureInPicture; 8045 return this; 8046 } 8047 8048 private Builder setUserSetupComplete(boolean userSetupComplete) { 8049 mUserSetupComplete = userSetupComplete; 8050 return this; 8051 } 8052 8053 private Builder setTaskAffiliation(int taskAffiliation) { 8054 mTaskAffiliation = taskAffiliation; 8055 return this; 8056 } 8057 8058 private Builder setPrevAffiliateTaskId(int prevAffiliateTaskId) { 8059 mPrevAffiliateTaskId = prevAffiliateTaskId; 8060 return this; 8061 } 8062 8063 private Builder setNextAffiliateTaskId(int nextAffiliateTaskId) { 8064 mNextAffiliateTaskId = nextAffiliateTaskId; 8065 return this; 8066 } 8067 8068 private Builder setCallingFeatureId(String callingFeatureId) { 8069 mCallingFeatureId = callingFeatureId; 8070 return this; 8071 } 8072 8073 private Builder setRealActivitySuspended(boolean realActivitySuspended) { 8074 mRealActivitySuspended = realActivitySuspended; 8075 return this; 8076 } 8077 8078 private Builder setLastDescription(String lastDescription) { 8079 mLastDescription = lastDescription; 8080 return this; 8081 } 8082 8083 private Builder setLastTaskDescription(TaskDescription lastTaskDescription) { 8084 mLastTaskDescription = lastTaskDescription; 8085 return this; 8086 } 8087 8088 private Builder setLastSnapshotData(PersistedTaskSnapshotData lastSnapshotData) { 8089 mLastSnapshotData = lastSnapshotData; 8090 return this; 8091 } 8092 8093 private Builder setOrigActivity(ComponentName origActivity) { 8094 mOrigActivity = origActivity; 8095 return this; 8096 } 8097 8098 private Builder setRootWasReset(boolean rootWasReset) { 8099 mRootWasReset = rootWasReset; 8100 return this; 8101 } 8102 8103 private Builder setAutoRemoveRecents(boolean autoRemoveRecents) { 8104 mAutoRemoveRecents = autoRemoveRecents; 8105 return this; 8106 } 8107 8108 private Builder setAskedCompatMode(boolean askedCompatMode) { 8109 mAskedCompatMode = askedCompatMode; 8110 return this; 8111 } 8112 8113 private Builder setAffinityIntent(Intent affinityIntent) { 8114 mAffinityIntent = affinityIntent; 8115 return this; 8116 } 8117 8118 private Builder setAffinity(String affinity) { 8119 mAffinity = affinity; 8120 return this; 8121 } 8122 8123 private Builder setRootAffinity(String rootAffinity) { 8124 mRootAffinity = rootAffinity; 8125 return this; 8126 } 8127 8128 private Builder setVoiceInteractor(IVoiceInteractor voiceInteractor) { 8129 mVoiceInteractor = voiceInteractor; 8130 return this; 8131 } 8132 8133 private void validateRootTask(TaskDisplayArea tda) { 8134 if (mActivityType == ACTIVITY_TYPE_UNDEFINED && !mCreatedByOrganizer) { 8135 // Can't have an undefined root task type yet...so re-map to standard. Anyone 8136 // that wants anything else should be passing it in anyways...except for the task 8137 // organizer. 8138 mActivityType = ACTIVITY_TYPE_STANDARD; 8139 } 8140 8141 if (mActivityType != ACTIVITY_TYPE_STANDARD 8142 && mActivityType != ACTIVITY_TYPE_UNDEFINED) { 8143 // For now there can be only one root task of a particular non-standard activity 8144 // type on a display. So, get that ignoring whatever windowing mode it is 8145 // currently in. 8146 Task rootTask = tda.getRootTask(WINDOWING_MODE_UNDEFINED, mActivityType); 8147 if (rootTask != null) { 8148 throw new IllegalArgumentException("Root task=" + rootTask + " of activityType=" 8149 + mActivityType + " already on display=" + tda 8150 + ". Can't have multiple."); 8151 } 8152 } 8153 8154 if (!TaskDisplayArea.isWindowingModeSupported(mWindowingMode, 8155 mAtmService.mSupportsMultiWindow, 8156 mAtmService.mSupportsSplitScreenMultiWindow, 8157 mAtmService.mSupportsFreeformWindowManagement, 8158 mAtmService.mSupportsPictureInPicture, mActivityType)) { 8159 throw new IllegalArgumentException("Can't create root task for unsupported " 8160 + "windowingMode=" + mWindowingMode); 8161 } 8162 8163 if (mWindowingMode == WINDOWING_MODE_PINNED 8164 && mActivityType != ACTIVITY_TYPE_STANDARD) { 8165 throw new IllegalArgumentException( 8166 "Root task with pinned windowing mode cannot with " 8167 + "non-standard activity type."); 8168 } 8169 8170 if (mWindowingMode == WINDOWING_MODE_PINNED && tda.getRootPinnedTask() != null) { 8171 // Only 1 root task can be PINNED at a time, so dismiss the existing one 8172 tda.getRootPinnedTask().dismissPip(); 8173 } 8174 8175 if (mIntent != null) { 8176 mLaunchFlags |= mIntent.getFlags(); 8177 } 8178 8179 // Task created by organizer are added as root. 8180 final Task launchRootTask = mCreatedByOrganizer 8181 ? null : tda.getLaunchRootTask(mWindowingMode, mActivityType, mActivityOptions, 8182 mSourceTask, mLaunchFlags); 8183 if (launchRootTask != null) { 8184 // Since this task will be put into a root task, its windowingMode will be 8185 // inherited. 8186 mWindowingMode = WINDOWING_MODE_UNDEFINED; 8187 mParent = launchRootTask; 8188 } 8189 8190 mTaskId = tda.getNextRootTaskId(); 8191 } 8192 8193 Task build() { 8194 if (mParent != null && mParent instanceof TaskDisplayArea) { 8195 validateRootTask((TaskDisplayArea) mParent); 8196 } 8197 8198 if (mActivityInfo == null) { 8199 mActivityInfo = new ActivityInfo(); 8200 mActivityInfo.applicationInfo = new ApplicationInfo(); 8201 } 8202 8203 mUserId = UserHandle.getUserId(mActivityInfo.applicationInfo.uid); 8204 mTaskAffiliation = mTaskId; 8205 mLastTimeMoved = System.currentTimeMillis(); 8206 mNeverRelinquishIdentity = true; 8207 mCallingUid = mActivityInfo.applicationInfo.uid; 8208 mCallingPackage = mActivityInfo.packageName; 8209 mResizeMode = mActivityInfo.resizeMode; 8210 mSupportsPictureInPicture = mActivityInfo.supportsPictureInPicture(); 8211 if (mActivityOptions != null) { 8212 mRemoveWithTaskOrganizer = mActivityOptions.getRemoveWithTaskOranizer(); 8213 } 8214 8215 final Task task = buildInner(); 8216 task.mHasBeenVisible = mHasBeenVisible; 8217 8218 // Set activity type before adding the root task to TaskDisplayArea, so home task can 8219 // be cached, see TaskDisplayArea#addRootTaskReferenceIfNeeded(). 8220 if (mActivityType != ACTIVITY_TYPE_UNDEFINED) { 8221 task.setActivityType(mActivityType); 8222 } 8223 8224 if (mParent != null) { 8225 if (mParent instanceof Task) { 8226 final Task parentTask = (Task) mParent; 8227 parentTask.addChild(task, mOnTop ? POSITION_TOP : POSITION_BOTTOM, 8228 (mActivityInfo.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); 8229 } else { 8230 mParent.addChild(task, mOnTop ? POSITION_TOP : POSITION_BOTTOM); 8231 } 8232 } 8233 8234 // Set windowing mode after attached to display area or it abort silently. 8235 if (mWindowingMode != WINDOWING_MODE_UNDEFINED) { 8236 task.setWindowingMode(mWindowingMode, true /* creating */); 8237 } 8238 return task; 8239 } 8240 8241 /** Don't use {@link Builder#buildInner()} directly. This is only used by XML parser. */ 8242 @VisibleForTesting 8243 Task buildInner() { 8244 return new Task(mAtmService, mTaskId, mIntent, mAffinityIntent, mAffinity, 8245 mRootAffinity, mRealActivity, mOrigActivity, mRootWasReset, mAutoRemoveRecents, 8246 mAskedCompatMode, mUserId, mEffectiveUid, mLastDescription, mLastTimeMoved, 8247 mNeverRelinquishIdentity, mLastTaskDescription, mLastSnapshotData, 8248 mTaskAffiliation, mPrevAffiliateTaskId, mNextAffiliateTaskId, mCallingUid, 8249 mCallingPackage, mCallingFeatureId, mResizeMode, mSupportsPictureInPicture, 8250 mRealActivitySuspended, mUserSetupComplete, mMinWidth, mMinHeight, 8251 mActivityInfo, mVoiceSession, mVoiceInteractor, mCreatedByOrganizer, 8252 mLaunchCookie, mDeferTaskAppear, mRemoveWithTaskOrganizer); 8253 } 8254 } 8255 } 8256