1 /*
2  * Copyright (C) 2021 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.WindowConfiguration.ACTIVITY_TYPE_HOME;
21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
22 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
23 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
24 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
25 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
26 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
27 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
28 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
29 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
30 import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
31 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
32 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
33 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
34 import static android.os.Process.INVALID_UID;
35 import static android.os.UserHandle.USER_NULL;
36 import static android.view.Display.INVALID_DISPLAY;
37 import static android.view.WindowManager.TRANSIT_CLOSE;
38 import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
39 import static android.view.WindowManager.TRANSIT_NONE;
40 import static android.view.WindowManager.TRANSIT_OPEN;
41 
42 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
43 import static com.android.server.wm.ActivityRecord.State.PAUSED;
44 import static com.android.server.wm.ActivityRecord.State.PAUSING;
45 import static com.android.server.wm.ActivityRecord.State.RESUMED;
46 import static com.android.server.wm.ActivityRecord.State.STOPPING;
47 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
48 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
49 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
50 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS;
51 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
52 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION;
53 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
54 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
55 import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
56 import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity;
57 import static com.android.server.wm.IdentifierProto.HASH_CODE;
58 import static com.android.server.wm.IdentifierProto.TITLE;
59 import static com.android.server.wm.IdentifierProto.USER_ID;
60 import static com.android.server.wm.TaskFragmentProto.ACTIVITY_TYPE;
61 import static com.android.server.wm.TaskFragmentProto.DISPLAY_ID;
62 import static com.android.server.wm.TaskFragmentProto.MIN_HEIGHT;
63 import static com.android.server.wm.TaskFragmentProto.MIN_WIDTH;
64 import static com.android.server.wm.TaskFragmentProto.WINDOW_CONTAINER;
65 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
66 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
67 import static com.android.server.wm.WindowContainerChildProto.TASK_FRAGMENT;
68 
69 import android.annotation.IntDef;
70 import android.annotation.NonNull;
71 import android.annotation.Nullable;
72 import android.app.ActivityOptions;
73 import android.app.ResultInfo;
74 import android.app.WindowConfiguration;
75 import android.app.servertransaction.ActivityResultItem;
76 import android.app.servertransaction.ClientTransaction;
77 import android.app.servertransaction.NewIntentItem;
78 import android.app.servertransaction.PauseActivityItem;
79 import android.app.servertransaction.ResumeActivityItem;
80 import android.content.res.Configuration;
81 import android.graphics.Point;
82 import android.graphics.Rect;
83 import android.os.IBinder;
84 import android.os.RemoteException;
85 import android.util.DisplayMetrics;
86 import android.util.Slog;
87 import android.util.proto.ProtoOutputStream;
88 import android.view.DisplayInfo;
89 import android.view.RemoteAnimationTarget;
90 import android.view.SurfaceControl;
91 import android.window.ITaskFragmentOrganizer;
92 import android.window.TaskFragmentInfo;
93 import android.window.TaskFragmentOrganizerToken;
94 
95 import com.android.internal.annotations.VisibleForTesting;
96 import com.android.internal.protolog.common.ProtoLog;
97 import com.android.internal.util.function.pooled.PooledFunction;
98 import com.android.internal.util.function.pooled.PooledLambda;
99 import com.android.internal.util.function.pooled.PooledPredicate;
100 
101 import java.io.FileDescriptor;
102 import java.io.PrintWriter;
103 import java.util.ArrayList;
104 import java.util.List;
105 import java.util.Objects;
106 import java.util.function.Consumer;
107 import java.util.function.Function;
108 
109 /**
110  * A basic container that can be used to contain activities or other {@link TaskFragment}, which
111  * also able to manage the activity lifecycle and updates the visibilities of the activities in it.
112  */
113 class TaskFragment extends WindowContainer<WindowContainer> {
114     @IntDef(prefix = {"TASK_FRAGMENT_VISIBILITY"}, value = {
115             TASK_FRAGMENT_VISIBILITY_VISIBLE,
116             TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
117             TASK_FRAGMENT_VISIBILITY_INVISIBLE,
118     })
119     @interface TaskFragmentVisibility {}
120 
121     /**
122      * TaskFragment is visible. No other TaskFragment(s) on top that fully or partially occlude it.
123      */
124     static final int TASK_FRAGMENT_VISIBILITY_VISIBLE = 0;
125 
126     /** TaskFragment is partially occluded by other translucent TaskFragment(s) on top of it. */
127     static final int TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT = 1;
128 
129     /** TaskFragment is completely invisible. */
130     static final int TASK_FRAGMENT_VISIBILITY_INVISIBLE = 2;
131 
132     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskFragment" : TAG_ATM;
133     private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
134     private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
135     private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION;
136 
137     /** Set to false to disable the preview that is shown while a new activity is being started. */
138     static final boolean SHOW_APP_STARTING_PREVIEW = true;
139 
140     /**
141      * Indicate that the minimal width/height should use the default value.
142      *
143      * @see #mMinWidth
144      * @see #mMinHeight
145      */
146     static final int INVALID_MIN_SIZE = -1;
147 
148     final ActivityTaskManagerService mAtmService;
149     final ActivityTaskSupervisor mTaskSupervisor;
150     final RootWindowContainer mRootWindowContainer;
151     private final TaskFragmentOrganizerController mTaskFragmentOrganizerController;
152 
153     /**
154      * Minimal width of this task fragment when it's resizeable. {@link #INVALID_MIN_SIZE} means it
155      * should use the default minimal width.
156      */
157     int mMinWidth;
158 
159     /**
160      * Minimal height of this task fragment when it's resizeable. {@link #INVALID_MIN_SIZE} means it
161      * should use the default minimal height.
162      */
163     int mMinHeight;
164 
165     Dimmer mDimmer = new Dimmer(this);
166 
167     /** This task fragment will be removed when the cleanup of its children are done. */
168     private boolean mIsRemovalRequested;
169 
170     /** The TaskFragment that is adjacent to this one. */
171     @Nullable
172     private TaskFragment mAdjacentTaskFragment;
173 
174     /**
175      * Whether to move adjacent task fragment together when re-positioning.
176      *
177      * @see #mAdjacentTaskFragment
178      */
179     // TODO(b/207185041): Remove this once having a single-top root for split screen.
180     boolean mMoveAdjacentTogether;
181 
182     /**
183      * Prevents duplicate calls to onTaskAppeared.
184      */
185     boolean mTaskFragmentAppearedSent;
186 
187     /**
188      * The last running activity of the TaskFragment was finished due to clear task while launching
189      * an activity in the Task.
190      */
191     boolean mClearedTaskForReuse;
192 
193     /**
194      * When we are in the process of pausing an activity, before starting the
195      * next one, this variable holds the activity that is currently being paused.
196      *
197      * Only set at leaf task fragments.
198      */
199     @Nullable
200     private ActivityRecord mPausingActivity = null;
201 
202     /**
203      * This is the last activity that we put into the paused state.  This is
204      * used to determine if we need to do an activity transition while sleeping,
205      * when we normally hold the top activity paused.
206      */
207     ActivityRecord mLastPausedActivity = null;
208 
209     /**
210      * Current activity that is resumed, or null if there is none.
211      * Only set at leaf task fragments.
212      */
213     @Nullable
214     private ActivityRecord mResumedActivity = null;
215 
216     /**
217      * This TaskFragment was created by an organizer which has the following implementations.
218      * <ul>
219      *     <li>The TaskFragment won't be removed when it is empty. Removal has to be an explicit
220      *     request from the organizer.</li>
221      *     <li>If this fragment is a Task object then unlike other non-root tasks, it's direct
222      *     children are visible to the organizer for ordering purposes.</li>
223      *     <li>A TaskFragment can be created by {@link android.window.TaskFragmentOrganizer}, and
224      *     a Task can be created by {@link android.window.TaskOrganizer}.</li>
225      * </ul>
226      */
227     @VisibleForTesting
228     boolean mCreatedByOrganizer;
229 
230     /** Whether this TaskFragment is embedded in a task. */
231     private final boolean mIsEmbedded;
232 
233     /** Organizer that organizing this TaskFragment. */
234     @Nullable
235     private ITaskFragmentOrganizer mTaskFragmentOrganizer;
236     private int mTaskFragmentOrganizerUid = INVALID_UID;
237     private @Nullable String mTaskFragmentOrganizerProcessName;
238 
239     /** Client assigned unique token for this TaskFragment if this is created by an organizer. */
240     @Nullable
241     private IBinder mFragmentToken;
242 
243     /**
244      * Whether to delay the last activity of TaskFragment being immediately removed while finishing.
245      * This should only be set on a embedded TaskFragment, where the organizer can have the
246      * opportunity to perform animations and finishing the adjacent TaskFragment.
247      */
248     private boolean mDelayLastActivityRemoval;
249 
250     final Point mLastSurfaceSize = new Point();
251 
252     private final Rect mTmpInsets = new Rect();
253     private final Rect mTmpBounds = new Rect();
254     private final Rect mTmpFullBounds = new Rect();
255     private final Rect mTmpStableBounds = new Rect();
256     private final Rect mTmpNonDecorBounds = new Rect();
257 
258     private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper =
259             new EnsureActivitiesVisibleHelper(this);
260     private final EnsureVisibleActivitiesConfigHelper mEnsureVisibleActivitiesConfigHelper =
261             new EnsureVisibleActivitiesConfigHelper();
262     private class EnsureVisibleActivitiesConfigHelper {
263         private boolean mUpdateConfig;
264         private boolean mPreserveWindow;
265         private boolean mBehindFullscreen;
266 
reset(boolean preserveWindow)267         void reset(boolean preserveWindow) {
268             mPreserveWindow = preserveWindow;
269             mUpdateConfig = false;
270             mBehindFullscreen = false;
271         }
272 
process(ActivityRecord start, boolean preserveWindow)273         void process(ActivityRecord start, boolean preserveWindow) {
274             if (start == null || !start.mVisibleRequested) {
275                 return;
276             }
277             reset(preserveWindow);
278 
279             final PooledFunction f = PooledLambda.obtainFunction(
280                     EnsureVisibleActivitiesConfigHelper::processActivity, this,
281                     PooledLambda.__(ActivityRecord.class));
282             forAllActivities(f, start, true /*includeBoundary*/, true /*traverseTopToBottom*/);
283             f.recycle();
284 
285             if (mUpdateConfig) {
286                 // Ensure the resumed state of the focus activity if we updated the configuration of
287                 // any activity.
288                 mRootWindowContainer.resumeFocusedTasksTopActivities();
289             }
290         }
291 
processActivity(ActivityRecord r)292         boolean processActivity(ActivityRecord r) {
293             mUpdateConfig |= r.ensureActivityConfiguration(0 /*globalChanges*/, mPreserveWindow);
294             mBehindFullscreen |= r.occludesParent();
295             return mBehindFullscreen;
296         }
297     }
298 
299     /** Creates an embedded task fragment. */
TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken, boolean createdByOrganizer)300     TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken,
301             boolean createdByOrganizer) {
302         this(atmService, fragmentToken, createdByOrganizer, true /* isEmbedded */);
303     }
304 
TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken, boolean createdByOrganizer, boolean isEmbedded)305     TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken,
306             boolean createdByOrganizer, boolean isEmbedded) {
307         super(atmService.mWindowManager);
308 
309         mAtmService = atmService;
310         mTaskSupervisor = mAtmService.mTaskSupervisor;
311         mRootWindowContainer = mAtmService.mRootWindowContainer;
312         mCreatedByOrganizer = createdByOrganizer;
313         mIsEmbedded = isEmbedded;
314         mTaskFragmentOrganizerController =
315                 mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController;
316         mFragmentToken = fragmentToken;
317         mRemoteToken = new RemoteToken(this);
318     }
319 
320     @NonNull
fromTaskFragmentToken(@ullable IBinder token, @NonNull ActivityTaskManagerService service)321     static TaskFragment fromTaskFragmentToken(@Nullable IBinder token,
322             @NonNull ActivityTaskManagerService service) {
323         if (token == null) return null;
324         return service.mWindowOrganizerController.getTaskFragment(token);
325     }
326 
setAdjacentTaskFragment(@ullable TaskFragment taskFragment, boolean moveTogether)327     void setAdjacentTaskFragment(@Nullable TaskFragment taskFragment, boolean moveTogether) {
328         if (mAdjacentTaskFragment == taskFragment) {
329             return;
330         }
331         resetAdjacentTaskFragment();
332         if (taskFragment != null) {
333             mAdjacentTaskFragment = taskFragment;
334             mMoveAdjacentTogether = moveTogether;
335             taskFragment.setAdjacentTaskFragment(this, moveTogether);
336         }
337     }
338 
resetAdjacentTaskFragment()339     private void resetAdjacentTaskFragment() {
340         // Reset the adjacent TaskFragment if its adjacent TaskFragment is also this TaskFragment.
341         if (mAdjacentTaskFragment != null && mAdjacentTaskFragment.mAdjacentTaskFragment == this) {
342             mAdjacentTaskFragment.mAdjacentTaskFragment = null;
343             mAdjacentTaskFragment.mDelayLastActivityRemoval = false;
344             mAdjacentTaskFragment.mMoveAdjacentTogether = false;
345         }
346         mAdjacentTaskFragment = null;
347         mDelayLastActivityRemoval = false;
348         mMoveAdjacentTogether = false;
349     }
350 
setTaskFragmentOrganizer(@onNull TaskFragmentOrganizerToken organizer, int uid, @NonNull String processName)351     void setTaskFragmentOrganizer(@NonNull TaskFragmentOrganizerToken organizer, int uid,
352             @NonNull String processName) {
353         mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(organizer.asBinder());
354         mTaskFragmentOrganizerUid = uid;
355         mTaskFragmentOrganizerProcessName = processName;
356     }
357 
358     /** Whether this TaskFragment is organized by the given {@code organizer}. */
hasTaskFragmentOrganizer(ITaskFragmentOrganizer organizer)359     boolean hasTaskFragmentOrganizer(ITaskFragmentOrganizer organizer) {
360         return organizer != null && mTaskFragmentOrganizer != null
361                 && organizer.asBinder().equals(mTaskFragmentOrganizer.asBinder());
362     }
363 
getAdjacentTaskFragment()364     TaskFragment getAdjacentTaskFragment() {
365         return mAdjacentTaskFragment;
366     }
367 
368     /** Returns the currently topmost resumed activity. */
369     @Nullable
getTopResumedActivity()370     ActivityRecord getTopResumedActivity() {
371         final ActivityRecord taskFragResumedActivity = getResumedActivity();
372         for (int i = getChildCount() - 1; i >= 0; --i) {
373             WindowContainer<?> child = getChildAt(i);
374             ActivityRecord topResumedActivity = null;
375             if (taskFragResumedActivity != null && child == taskFragResumedActivity) {
376                 topResumedActivity = child.asActivityRecord();
377             } else if (child.asTaskFragment() != null) {
378                 topResumedActivity = child.asTaskFragment().getTopResumedActivity();
379             }
380             if (topResumedActivity != null) {
381                 return topResumedActivity;
382             }
383         }
384         return null;
385     }
386 
387     /**
388      * Returns the currently resumed activity in this TaskFragment's
389      * {@link #mChildren direct children}
390      */
getResumedActivity()391     ActivityRecord getResumedActivity() {
392         return mResumedActivity;
393     }
394 
setResumedActivity(ActivityRecord r, String reason)395     void setResumedActivity(ActivityRecord r, String reason) {
396         warnForNonLeafTaskFragment("setResumedActivity");
397         if (mResumedActivity == r) {
398             return;
399         }
400 
401         if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
402             Slog.d(TAG, "setResumedActivity taskFrag:" + this + " + from: "
403                     + mResumedActivity + " to:" + r + " reason:" + reason);
404         }
405         mResumedActivity = r;
406         mTaskSupervisor.updateTopResumedActivityIfNeeded();
407     }
408 
409     @VisibleForTesting
setPausingActivity(ActivityRecord pausing)410     void setPausingActivity(ActivityRecord pausing) {
411         mPausingActivity = pausing;
412     }
413 
414     /** Returns the currently topmost pausing activity. */
415     @Nullable
getTopPausingActivity()416     ActivityRecord getTopPausingActivity() {
417         final ActivityRecord taskFragPausingActivity = getPausingActivity();
418         for (int i = getChildCount() - 1; i >= 0; --i) {
419             WindowContainer<?> child = getChildAt(i);
420             ActivityRecord topPausingActivity = null;
421             if (taskFragPausingActivity != null && child == taskFragPausingActivity) {
422                 topPausingActivity = child.asActivityRecord();
423             } else if (child.asTaskFragment() != null) {
424                 topPausingActivity = child.asTaskFragment().getTopPausingActivity();
425             }
426             if (topPausingActivity != null) {
427                 return topPausingActivity;
428             }
429         }
430         return null;
431     }
432 
getPausingActivity()433     ActivityRecord getPausingActivity() {
434         return mPausingActivity;
435     }
436 
getDisplayId()437     int getDisplayId() {
438         final DisplayContent dc = getDisplayContent();
439         return dc != null ? dc.mDisplayId : INVALID_DISPLAY;
440     }
441 
442     @Nullable
getTask()443     Task getTask() {
444         if (asTask() != null) {
445             return asTask();
446         }
447 
448         TaskFragment parent = getParent() != null ? getParent().asTaskFragment() : null;
449         return parent != null ? parent.getTask() : null;
450     }
451 
452     @Override
453     @Nullable
getDisplayArea()454     TaskDisplayArea getDisplayArea() {
455         return (TaskDisplayArea) super.getDisplayArea();
456     }
457 
458     @Override
isAttached()459     public boolean isAttached() {
460         final TaskDisplayArea taskDisplayArea = getDisplayArea();
461         return taskDisplayArea != null && !taskDisplayArea.isRemoved();
462     }
463 
464     /**
465      * Returns the root {@link TaskFragment}, which is usually also a {@link Task}.
466      */
467     @NonNull
getRootTaskFragment()468     TaskFragment getRootTaskFragment() {
469         final WindowContainer parent = getParent();
470         if (parent == null) return this;
471 
472         final TaskFragment parentTaskFragment = parent.asTaskFragment();
473         return parentTaskFragment == null ? this : parentTaskFragment.getRootTaskFragment();
474     }
475 
476     @Nullable
getRootTask()477     Task getRootTask() {
478         return getRootTaskFragment().asTask();
479     }
480 
481     @Override
asTaskFragment()482     TaskFragment asTaskFragment() {
483         return this;
484     }
485 
486     @Override
isEmbedded()487     boolean isEmbedded() {
488         if (mIsEmbedded) {
489             return true;
490         }
491         final WindowContainer<?> parent = getParent();
492         if (parent != null) {
493             final TaskFragment taskFragment = parent.asTaskFragment();
494             return taskFragment != null && taskFragment.isEmbedded();
495         }
496         return false;
497     }
498 
499     /**
500      * Returns the TaskFragment that is being organized, which could be this or the ascendant
501      * TaskFragment.
502      */
503     @Nullable
getOrganizedTaskFragment()504     TaskFragment getOrganizedTaskFragment() {
505         if (mTaskFragmentOrganizer != null) {
506             return this;
507         }
508 
509         TaskFragment parentTaskFragment = getParent() != null ? getParent().asTaskFragment() : null;
510         return parentTaskFragment != null ? parentTaskFragment.getOrganizedTaskFragment() : null;
511     }
512 
513     /**
514      * Simply check and give warning logs if this is not operated on leaf {@link TaskFragment}.
515      */
warnForNonLeafTaskFragment(String func)516     private void warnForNonLeafTaskFragment(String func) {
517         if (!isLeafTaskFragment()) {
518             Slog.w(TAG, func + " on non-leaf task fragment " + this);
519         }
520     }
521 
hasDirectChildActivities()522     boolean hasDirectChildActivities() {
523         for (int i = mChildren.size() - 1; i >= 0; --i) {
524             if (mChildren.get(i).asActivityRecord() != null) {
525                 return true;
526             }
527         }
528         return false;
529     }
530 
cleanUpActivityReferences(@onNull ActivityRecord r)531     void cleanUpActivityReferences(@NonNull ActivityRecord r) {
532         if (mPausingActivity != null && mPausingActivity == r) {
533             mPausingActivity = null;
534         }
535 
536         if (mResumedActivity != null && mResumedActivity == r) {
537             setResumedActivity(null, "cleanUpActivityReferences");
538         }
539         r.removeTimeouts();
540     }
541 
542     /**
543      * Returns whether this TaskFragment is currently forced to be hidden for any reason.
544      */
isForceHidden()545     protected boolean isForceHidden() {
546         return false;
547     }
548 
isLeafTaskFragment()549     boolean isLeafTaskFragment() {
550         for (int i = mChildren.size() - 1; i >= 0; --i) {
551             if (mChildren.get(i).asTaskFragment() != null) {
552                 return false;
553             }
554         }
555         return true;
556     }
557 
558     /**
559      * This should be called when an child activity changes state. This should only
560      * be called from
561      * {@link ActivityRecord#setState(ActivityRecord.State, String)} .
562      * @param record The {@link ActivityRecord} whose state has changed.
563      * @param state The new state.
564      * @param reason The reason for the change.
565      */
onActivityStateChanged(ActivityRecord record, ActivityRecord.State state, String reason)566     void onActivityStateChanged(ActivityRecord record, ActivityRecord.State state,
567             String reason) {
568         warnForNonLeafTaskFragment("onActivityStateChanged");
569         if (record == mResumedActivity && state != RESUMED) {
570             setResumedActivity(null, reason + " - onActivityStateChanged");
571         }
572 
573         if (state == RESUMED) {
574             if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
575                 Slog.v(TAG, "set resumed activity to:" + record + " reason:" + reason);
576             }
577             setResumedActivity(record, reason + " - onActivityStateChanged");
578             if (record == mRootWindowContainer.getTopResumedActivity()) {
579                 mAtmService.setResumedActivityUncheckLocked(record, reason);
580             }
581             mTaskSupervisor.mRecentTasks.add(record.getTask());
582         }
583     }
584 
585     /**
586      * Resets local parameters because an app's activity died.
587      * @param app The app of the activity that died.
588      * @return {@code true} if the process of the pausing activity is died.
589      */
handleAppDied(WindowProcessController app)590     boolean handleAppDied(WindowProcessController app) {
591         warnForNonLeafTaskFragment("handleAppDied");
592         boolean isPausingDied = false;
593         if (mPausingActivity != null && mPausingActivity.app == app) {
594             ProtoLog.v(WM_DEBUG_STATES, "App died while pausing: %s",
595                     mPausingActivity);
596             mPausingActivity = null;
597             isPausingDied = true;
598         }
599         if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
600             mLastPausedActivity = null;
601         }
602         return isPausingDied;
603     }
604 
awakeFromSleeping()605     void awakeFromSleeping() {
606         if (mPausingActivity != null) {
607             Slog.d(TAG, "awakeFromSleeping: previously pausing activity didn't pause");
608             mPausingActivity.activityPaused(true);
609         }
610     }
611 
612     /**
613      * Tries to put the activities in the task fragment to sleep.
614      *
615      * If the task fragment is not in a state where its activities can be put to sleep, this
616      * function will start any necessary actions to move the task fragment into such a state.
617      * It is expected that this function get called again when those actions complete.
618      *
619      * @param shuttingDown {@code true} when the called because the device is shutting down.
620      * @return true if the root task finished going to sleep, false if the root task only started
621      * the process of going to sleep (checkReadyForSleep will be called when that process finishes).
622      */
sleepIfPossible(boolean shuttingDown)623     boolean sleepIfPossible(boolean shuttingDown) {
624         boolean shouldSleep = true;
625         if (mResumedActivity != null) {
626             // Still have something resumed; can't sleep until it is paused.
627             ProtoLog.v(WM_DEBUG_STATES, "Sleep needs to pause %s", mResumedActivity);
628             startPausing(false /* userLeaving */, true /* uiSleeping */, null /* resuming */,
629                     "sleep");
630             shouldSleep = false;
631         } else if (mPausingActivity != null) {
632             // Still waiting for something to pause; can't sleep yet.
633             ProtoLog.v(WM_DEBUG_STATES, "Sleep still waiting to pause %s", mPausingActivity);
634             shouldSleep = false;
635         }
636 
637         if (!shuttingDown) {
638             if (containsStoppingActivity()) {
639                 // Still need to tell some activities to stop; can't sleep yet.
640                 ProtoLog.v(WM_DEBUG_STATES, "Sleep still need to stop %d activities",
641                         mTaskSupervisor.mStoppingActivities.size());
642 
643                 mTaskSupervisor.scheduleIdle();
644                 shouldSleep = false;
645             }
646         }
647 
648         if (shouldSleep) {
649             updateActivityVisibilities(null /* starting */, 0 /* configChanges */,
650                     !PRESERVE_WINDOWS, true /* notifyClients */);
651         }
652 
653         return shouldSleep;
654     }
655 
containsStoppingActivity()656     private boolean containsStoppingActivity() {
657         for (int i = mTaskSupervisor.mStoppingActivities.size() - 1; i >= 0; --i) {
658             ActivityRecord r = mTaskSupervisor.mStoppingActivities.get(i);
659             if (r.getTaskFragment() == this) {
660                 return true;
661             }
662         }
663         return false;
664     }
665 
666     /**
667      * Returns true if the TaskFragment is translucent and can have other contents visible behind
668      * it if needed. A TaskFragment is considered translucent if it don't contain a visible or
669      * starting (about to be visible) activity that is fullscreen (opaque).
670      * @param starting The currently starting activity or null if there is none.
671      */
672     @VisibleForTesting
isTranslucent(ActivityRecord starting)673     boolean isTranslucent(ActivityRecord starting) {
674         if (!isAttached() || isForceHidden()) {
675             return true;
676         }
677         final PooledPredicate p = PooledLambda.obtainPredicate(TaskFragment::isOpaqueActivity,
678                 PooledLambda.__(ActivityRecord.class), starting);
679         final ActivityRecord opaque = getActivity(p);
680         p.recycle();
681         return opaque == null;
682     }
683 
isOpaqueActivity(ActivityRecord r, ActivityRecord starting)684     private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) {
685         if (r.finishing) {
686             // We don't factor in finishing activities when determining translucency since
687             // they will be gone soon.
688             return false;
689         }
690 
691         if (!r.visibleIgnoringKeyguard && r != starting) {
692             // Also ignore invisible activities that are not the currently starting
693             // activity (about to be visible).
694             return false;
695         }
696 
697         if (r.occludesParent()) {
698             // Root task isn't translucent if it has at least one fullscreen activity
699             // that is visible.
700             return true;
701         }
702         return false;
703     }
704 
getTopNonFinishingActivity()705     ActivityRecord getTopNonFinishingActivity() {
706         return getTopNonFinishingActivity(true /* includeOverlays */);
707     }
708 
getTopNonFinishingActivity(boolean includeOverlays)709     ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
710         return getTopNonFinishingActivity(includeOverlays, true /* includingEmbeddedTask */);
711     }
712 
713     /**
714      * Returns the top-most non-finishing activity, even if the activity is NOT ok to show to
715      * the current user.
716      * @param includeOverlays whether the task overlay activity should be included.
717      * @param includingEmbeddedTask whether the activity in a task that being embedded from this
718      *                              one should be included.
719      * @see #topRunningActivity(boolean, boolean)
720      */
getTopNonFinishingActivity(boolean includeOverlays, boolean includingEmbeddedTask)721     ActivityRecord getTopNonFinishingActivity(boolean includeOverlays,
722             boolean includingEmbeddedTask) {
723         // Split into 4 to avoid object creation due to variable capture.
724         if (includeOverlays) {
725             if (includingEmbeddedTask) {
726                 return getActivity((r) -> !r.finishing);
727             }
728             return getActivity((r) -> !r.finishing && r.getTask() == this.getTask());
729         }
730 
731         if (includingEmbeddedTask) {
732             return getActivity((r) -> !r.finishing && !r.isTaskOverlay());
733         }
734         return getActivity(
735                 (r) -> !r.finishing && !r.isTaskOverlay() && r.getTask() == this.getTask());
736     }
737 
topRunningActivity()738     ActivityRecord topRunningActivity() {
739         return topRunningActivity(false /* focusableOnly */);
740     }
741 
topRunningActivity(boolean focusableOnly)742     ActivityRecord topRunningActivity(boolean focusableOnly) {
743         return topRunningActivity(focusableOnly, true /* includingEmbeddedTask */);
744     }
745 
746     /**
747      * Returns the top-most running activity, which the activity is non-finishing and ok to show
748      * to the current user.
749      *
750      * @see ActivityRecord#canBeTopRunning()
751      */
topRunningActivity(boolean focusableOnly, boolean includingEmbeddedTask)752     ActivityRecord topRunningActivity(boolean focusableOnly, boolean includingEmbeddedTask) {
753         // Split into 4 to avoid object creation due to variable capture.
754         if (focusableOnly) {
755             if (includingEmbeddedTask) {
756                 return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
757             }
758             return getActivity(
759                     (r) -> r.canBeTopRunning() && r.isFocusable() && r.getTask() == this.getTask());
760         }
761 
762         if (includingEmbeddedTask) {
763             return getActivity(ActivityRecord::canBeTopRunning);
764         }
765         return getActivity((r) -> r.canBeTopRunning() && r.getTask() == this.getTask());
766     }
767 
isTopActivityFocusable()768     boolean isTopActivityFocusable() {
769         final ActivityRecord r = topRunningActivity();
770         return r != null ? r.isFocusable()
771                 : (isFocusable() && getWindowConfiguration().canReceiveKeys());
772     }
773 
774     /**
775      * Returns the visibility state of this TaskFragment.
776      *
777      * @param starting The currently starting activity or null if there is none.
778      */
779     @TaskFragmentVisibility
getVisibility(ActivityRecord starting)780     int getVisibility(ActivityRecord starting) {
781         if (!isAttached() || isForceHidden()) {
782             return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
783         }
784 
785         if (isTopActivityLaunchedBehind()) {
786             return TASK_FRAGMENT_VISIBILITY_VISIBLE;
787         }
788 
789         boolean gotRootSplitScreenFragment = false;
790         boolean gotOpaqueSplitScreenPrimary = false;
791         boolean gotOpaqueSplitScreenSecondary = false;
792         boolean gotTranslucentFullscreen = false;
793         boolean gotTranslucentAdjacent = false;
794         boolean gotTranslucentSplitScreenPrimary = false;
795         boolean gotTranslucentSplitScreenSecondary = false;
796         boolean shouldBeVisible = true;
797 
798         // This TaskFragment is only considered visible if all its parent TaskFragments are
799         // considered visible, so check the visibility of all ancestor TaskFragment first.
800         final WindowContainer parent = getParent();
801         if (parent.asTaskFragment() != null) {
802             final int parentVisibility = parent.asTaskFragment().getVisibility(starting);
803             if (parentVisibility == TASK_FRAGMENT_VISIBILITY_INVISIBLE) {
804                 // Can't be visible if parent isn't visible
805                 return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
806             } else if (parentVisibility == TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) {
807                 // Parent is behind a translucent container so the highest visibility this container
808                 // can get is that.
809                 gotTranslucentFullscreen = true;
810             }
811         }
812 
813         final List<TaskFragment> adjacentTaskFragments = new ArrayList<>();
814         final int windowingMode = getWindowingMode();
815         final boolean isAssistantType = isActivityTypeAssistant();
816         for (int i = parent.getChildCount() - 1; i >= 0; --i) {
817             final WindowContainer other = parent.getChildAt(i);
818             if (other == null) continue;
819 
820             final boolean hasRunningActivities = hasRunningActivity(other);
821             if (other == this) {
822                 if (!adjacentTaskFragments.isEmpty() && !gotTranslucentAdjacent) {
823                     // The z-order of this TaskFragment is in middle of two adjacent TaskFragments
824                     // and it cannot be visible if the TaskFragment on top is not translucent and
825                     // is fully occluding this one.
826                     for (int j = adjacentTaskFragments.size() - 1; j >= 0; --j) {
827                         final TaskFragment taskFragment = adjacentTaskFragments.get(j);
828                         if (!taskFragment.isTranslucent(starting)
829                                 && taskFragment.getBounds().contains(this.getBounds())) {
830                             return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
831                         }
832                     }
833                 }
834                 // Should be visible if there is no other fragment occluding it, unless it doesn't
835                 // have any running activities, not starting one and not home stack.
836                 shouldBeVisible = hasRunningActivities
837                         || (starting != null && starting.isDescendantOf(this))
838                         || isActivityTypeHome();
839                 break;
840             }
841 
842             if (!hasRunningActivities) {
843                 continue;
844             }
845 
846             final int otherWindowingMode = other.getWindowingMode();
847             if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) {
848                 if (isTranslucent(other, starting)) {
849                     // Can be visible behind a translucent fullscreen TaskFragment.
850                     gotTranslucentFullscreen = true;
851                     continue;
852                 }
853                 return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
854             } else if (otherWindowingMode == WINDOWING_MODE_MULTI_WINDOW
855                     && other.matchParentBounds()) {
856                 if (isTranslucent(other, starting)) {
857                     // Can be visible behind a translucent TaskFragment.
858                     gotTranslucentFullscreen = true;
859                     continue;
860                 }
861                 // Multi-window TaskFragment that matches parent bounds would occlude other children
862                 return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
863             } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
864                     && !gotOpaqueSplitScreenPrimary) {
865                 gotRootSplitScreenFragment = true;
866                 gotTranslucentSplitScreenPrimary = isTranslucent(other, starting);
867                 gotOpaqueSplitScreenPrimary = !gotTranslucentSplitScreenPrimary;
868                 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
869                         && gotOpaqueSplitScreenPrimary) {
870                     // Can't be visible behind another opaque TaskFragment in split-screen-primary.
871                     return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
872                 }
873             } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
874                     && !gotOpaqueSplitScreenSecondary) {
875                 gotRootSplitScreenFragment = true;
876                 gotTranslucentSplitScreenSecondary = isTranslucent(other, starting);
877                 gotOpaqueSplitScreenSecondary = !gotTranslucentSplitScreenSecondary;
878                 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
879                         && gotOpaqueSplitScreenSecondary) {
880                     // Can't be visible behind another opaque TaskFragment in split-screen-secondary
881                     return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
882                 }
883             }
884             if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) {
885                 // Can not be visible if we are in split-screen windowing mode and both halves of
886                 // the screen are opaque.
887                 return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
888             }
889             if (isAssistantType && gotRootSplitScreenFragment) {
890                 // Assistant TaskFragment can't be visible behind split-screen. In addition to
891                 // this not making sense, it also works around an issue here we boost the z-order
892                 // of the assistant window surfaces in window manager whenever it is visible.
893                 return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
894             }
895 
896             final TaskFragment otherTaskFrag = other.asTaskFragment();
897             if (otherTaskFrag != null && otherTaskFrag.mAdjacentTaskFragment != null) {
898                 if (adjacentTaskFragments.contains(otherTaskFrag.mAdjacentTaskFragment)) {
899                     if (otherTaskFrag.isTranslucent(starting)
900                             || otherTaskFrag.mAdjacentTaskFragment.isTranslucent(starting)) {
901                         // Can be visible behind a translucent adjacent TaskFragments.
902                         gotTranslucentFullscreen = true;
903                         gotTranslucentAdjacent = true;
904                         continue;
905                     }
906                     // Can not be visible behind adjacent TaskFragments.
907                     return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
908                 } else {
909                     adjacentTaskFragments.add(otherTaskFrag);
910                 }
911             }
912 
913         }
914 
915         if (!shouldBeVisible) {
916             return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
917         }
918 
919         // Handle cases when there can be a translucent split-screen TaskFragment on top.
920         switch (windowingMode) {
921             case WINDOWING_MODE_FULLSCREEN:
922                 if (gotTranslucentSplitScreenPrimary || gotTranslucentSplitScreenSecondary) {
923                     // At least one of the split-screen TaskFragment that covers this one is
924                     // translucent.
925                     // When in split mode, home will be reparented to the secondary split while
926                     // leaving TaskFragments not supporting split below. Due to
927                     // TaskDisplayArea#assignRootTaskOrdering always adjusts home surface layer to
928                     // the bottom, this makes sure TaskFragments not in split roots won't occlude
929                     // home task unexpectedly.
930                     return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
931                 }
932                 break;
933             case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
934                 if (gotTranslucentSplitScreenPrimary) {
935                     // Covered by translucent primary split-screen on top.
936                     return TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
937                 }
938                 break;
939             case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
940                 if (gotTranslucentSplitScreenSecondary) {
941                     // Covered by translucent secondary split-screen on top.
942                     return TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
943                 }
944                 break;
945         }
946 
947         // Lastly - check if there is a translucent fullscreen TaskFragment on top.
948         return gotTranslucentFullscreen
949                 ? TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT
950                 : TASK_FRAGMENT_VISIBILITY_VISIBLE;
951     }
952 
hasRunningActivity(WindowContainer wc)953     private static boolean hasRunningActivity(WindowContainer wc) {
954         if (wc.asTaskFragment() != null) {
955             return wc.asTaskFragment().topRunningActivity() != null;
956         }
957         return wc.asActivityRecord() != null && !wc.asActivityRecord().finishing;
958     }
959 
isTranslucent(WindowContainer wc, ActivityRecord starting)960     private static boolean isTranslucent(WindowContainer wc, ActivityRecord starting) {
961         if (wc.asTaskFragment() != null) {
962             return wc.asTaskFragment().isTranslucent(starting);
963         } else if (wc.asActivityRecord() != null) {
964             return !wc.asActivityRecord().occludesParent();
965         }
966         return false;
967     }
968 
969 
isTopActivityLaunchedBehind()970     private boolean isTopActivityLaunchedBehind() {
971         final ActivityRecord top = topRunningActivity();
972         return top != null && top.mLaunchTaskBehind;
973     }
974 
updateActivityVisibilities(@ullable ActivityRecord starting, int configChanges, boolean preserveWindows, boolean notifyClients)975     final void updateActivityVisibilities(@Nullable ActivityRecord starting, int configChanges,
976             boolean preserveWindows, boolean notifyClients) {
977         mTaskSupervisor.beginActivityVisibilityUpdate();
978         try {
979             mEnsureActivitiesVisibleHelper.process(
980                     starting, configChanges, preserveWindows, notifyClients);
981         } finally {
982             mTaskSupervisor.endActivityVisibilityUpdate();
983         }
984     }
985 
resumeTopActivity(ActivityRecord prev, ActivityOptions options, boolean deferPause)986     final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,
987             boolean deferPause) {
988         ActivityRecord next = topRunningActivity(true /* focusableOnly */);
989         if (next == null || !next.canResumeByCompat()) {
990             return false;
991         }
992 
993         next.delayedResume = false;
994         final TaskDisplayArea taskDisplayArea = getDisplayArea();
995 
996         // If the top activity is the resumed one, nothing to do.
997         if (mResumedActivity == next && next.isState(RESUMED)
998                 && taskDisplayArea.allResumedActivitiesComplete()) {
999             // Make sure we have executed any pending transitions, since there
1000             // should be nothing left to do at this point.
1001             executeAppTransition(options);
1002             // For devices that are not in fullscreen mode (e.g. freeform windows), it's possible
1003             // we still want to check if the visibility of other windows have changed (e.g. bringing
1004             // a fullscreen window forward to cover another freeform activity.)
1005             if (taskDisplayArea.inMultiWindowMode()) {
1006                 taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
1007                         false /* preserveWindows */, true /* notifyClients */);
1008             }
1009             ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity "
1010                     + "resumed %s", next);
1011             return false;
1012         }
1013 
1014         // If we are currently pausing an activity, then don't do anything until that is done.
1015         final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
1016         if (!allPausedComplete) {
1017             ProtoLog.v(WM_DEBUG_STATES,
1018                     "resumeTopActivity: Skip resume: some activity pausing.");
1019             return false;
1020         }
1021 
1022         // If we are sleeping, and there is no resumed activity, and the top activity is paused,
1023         // well that is the state we want.
1024         if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) {
1025             // Make sure we have executed any pending transitions, since there
1026             // should be nothing left to do at this point.
1027             executeAppTransition(options);
1028             ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Going to sleep and"
1029                     + " all paused");
1030             return false;
1031         }
1032 
1033         // Make sure that the user who owns this activity is started.  If not,
1034         // we will just leave it as is because someone should be bringing
1035         // another user's activities to the top of the stack.
1036         if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) {
1037             Slog.w(TAG, "Skipping resume of top activity " + next
1038                     + ": user " + next.mUserId + " is stopped");
1039             return false;
1040         }
1041 
1042         // The activity may be waiting for stop, but that is no longer
1043         // appropriate for it.
1044         mTaskSupervisor.mStoppingActivities.remove(next);
1045 
1046         if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
1047 
1048         mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid);
1049 
1050         ActivityRecord lastResumed = null;
1051         final Task lastFocusedRootTask = taskDisplayArea.getLastFocusedRootTask();
1052         if (lastFocusedRootTask != null && lastFocusedRootTask != getRootTaskFragment().asTask()) {
1053             // So, why aren't we using prev here??? See the param comment on the method. prev
1054             // doesn't represent the last resumed activity. However, the last focus stack does if
1055             // it isn't null.
1056             lastResumed = lastFocusedRootTask.getTopResumedActivity();
1057         }
1058 
1059         boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);
1060         if (mResumedActivity != null) {
1061             ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Pausing %s", mResumedActivity);
1062             pausing |= startPausing(mTaskSupervisor.mUserLeaving, false /* uiSleeping */,
1063                     next, "resumeTopActivity");
1064         }
1065         if (pausing) {
1066             ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: need to"
1067                     + " start pausing");
1068             // At this point we want to put the upcoming activity's process
1069             // at the top of the LRU list, since we know we will be needing it
1070             // very soon and it would be a waste to let it get killed if it
1071             // happens to be sitting towards the end.
1072             if (next.attachedToProcess()) {
1073                 next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
1074                         true /* activityChange */, false /* updateOomAdj */,
1075                         false /* addPendingTopUid */);
1076             } else if (!next.isProcessRunning()) {
1077                 // Since the start-process is asynchronous, if we already know the process of next
1078                 // activity isn't running, we can start the process earlier to save the time to wait
1079                 // for the current activity to be paused.
1080                 final boolean isTop = this == taskDisplayArea.getFocusedRootTask();
1081                 mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
1082                         isTop ? "pre-top-activity" : "pre-activity");
1083             }
1084             if (lastResumed != null) {
1085                 lastResumed.setWillCloseOrEnterPip(true);
1086             }
1087             return true;
1088         } else if (mResumedActivity == next && next.isState(RESUMED)
1089                 && taskDisplayArea.allResumedActivitiesComplete()) {
1090             // It is possible for the activity to be resumed when we paused back stacks above if the
1091             // next activity doesn't have to wait for pause to complete.
1092             // So, nothing else to-do except:
1093             // Make sure we have executed any pending transitions, since there
1094             // should be nothing left to do at this point.
1095             executeAppTransition(options);
1096             ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity resumed "
1097                     + "(dontWaitForPause) %s", next);
1098             return true;
1099         }
1100 
1101         // If the most recent activity was noHistory but was only stopped rather
1102         // than stopped+finished because the device went to sleep, we need to make
1103         // sure to finish it as we're making a new activity topmost.
1104         if (shouldSleepActivities()) {
1105             mTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next);
1106         }
1107 
1108         if (prev != null && prev != next && next.nowVisible) {
1109             // The next activity is already visible, so hide the previous
1110             // activity's windows right now so we can show the new one ASAP.
1111             // We only do this if the previous is finishing, which should mean
1112             // it is on top of the one being resumed so hiding it quickly
1113             // is good.  Otherwise, we want to do the normal route of allowing
1114             // the resumed activity to be shown so we can decide if the
1115             // previous should actually be hidden depending on whether the
1116             // new one is found to be full-screen or not.
1117             if (prev.finishing) {
1118                 prev.setVisibility(false);
1119                 if (DEBUG_SWITCH) {
1120                     Slog.v(TAG_SWITCH, "Not waiting for visible to hide: " + prev
1121                             + ", nowVisible=" + next.nowVisible);
1122                 }
1123             } else {
1124                 if (DEBUG_SWITCH) {
1125                     Slog.v(TAG_SWITCH, "Previous already visible but still waiting to hide: " + prev
1126                             + ", nowVisible=" + next.nowVisible);
1127                 }
1128             }
1129         }
1130 
1131         // Launching this app's activity, make sure the app is no longer
1132         // considered stopped.
1133         try {
1134             mTaskSupervisor.getActivityMetricsLogger()
1135                     .notifyBeforePackageUnstopped(next.packageName);
1136             mAtmService.getPackageManager().setPackageStoppedState(
1137                     next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */
1138         } catch (RemoteException e1) {
1139         } catch (IllegalArgumentException e) {
1140             Slog.w(TAG, "Failed trying to unstop package "
1141                     + next.packageName + ": " + e);
1142         }
1143 
1144         // We are starting up the next activity, so tell the window manager
1145         // that the previous one will be hidden soon.  This way it can know
1146         // to ignore it when computing the desired screen orientation.
1147         boolean anim = true;
1148         final DisplayContent dc = taskDisplayArea.mDisplayContent;
1149         if (prev != null) {
1150             if (prev.finishing) {
1151                 if (DEBUG_TRANSITION) {
1152                     Slog.v(TAG_TRANSITION, "Prepare close transition: prev=" + prev);
1153                 }
1154                 if (mTaskSupervisor.mNoAnimActivities.contains(prev)) {
1155                     anim = false;
1156                     dc.prepareAppTransition(TRANSIT_NONE);
1157                 } else {
1158                     dc.prepareAppTransition(TRANSIT_CLOSE);
1159                 }
1160                 prev.setVisibility(false);
1161             } else {
1162                 if (DEBUG_TRANSITION) {
1163                     Slog.v(TAG_TRANSITION, "Prepare open transition: prev=" + prev);
1164                 }
1165                 if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
1166                     anim = false;
1167                     dc.prepareAppTransition(TRANSIT_NONE);
1168                 } else {
1169                     dc.prepareAppTransition(TRANSIT_OPEN,
1170                             next.mLaunchTaskBehind ? TRANSIT_FLAG_OPEN_BEHIND : 0);
1171                 }
1172             }
1173         } else {
1174             if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
1175             if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
1176                 anim = false;
1177                 dc.prepareAppTransition(TRANSIT_NONE);
1178             } else {
1179                 dc.prepareAppTransition(TRANSIT_OPEN);
1180             }
1181         }
1182 
1183         if (anim) {
1184             next.applyOptionsAnimation();
1185         } else {
1186             next.abortAndClearOptionsAnimation();
1187         }
1188 
1189         mTaskSupervisor.mNoAnimActivities.clear();
1190 
1191         if (next.attachedToProcess()) {
1192             if (DEBUG_SWITCH) {
1193                 Slog.v(TAG_SWITCH, "Resume running: " + next + " stopped=" + next.stopped
1194                         + " visibleRequested=" + next.mVisibleRequested);
1195             }
1196 
1197             // If the previous activity is translucent, force a visibility update of
1198             // the next activity, so that it's added to WM's opening app list, and
1199             // transition animation can be set up properly.
1200             // For example, pressing Home button with a translucent activity in focus.
1201             // Launcher is already visible in this case. If we don't add it to opening
1202             // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a
1203             // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation.
1204             final boolean lastActivityTranslucent = inMultiWindowMode()
1205                     || mLastPausedActivity != null && !mLastPausedActivity.occludesParent();
1206 
1207             // This activity is now becoming visible.
1208             if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) {
1209                 next.setVisibility(true);
1210             }
1211 
1212             // schedule launch ticks to collect information about slow apps.
1213             next.startLaunchTickingLocked();
1214 
1215             ActivityRecord lastResumedActivity =
1216                     lastFocusedRootTask == null ? null
1217                             : lastFocusedRootTask.getTopResumedActivity();
1218             final ActivityRecord.State lastState = next.getState();
1219 
1220             mAtmService.updateCpuStats();
1221 
1222             ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (in existing)", next);
1223 
1224             next.setState(RESUMED, "resumeTopActivity");
1225 
1226             // Have the window manager re-evaluate the orientation of
1227             // the screen based on the new activity order.
1228             boolean notUpdated = true;
1229 
1230             // Activity should also be visible if set mLaunchTaskBehind to true (see
1231             // ActivityRecord#shouldBeVisibleIgnoringKeyguard()).
1232             if (shouldBeVisible(next)) {
1233                 // We have special rotation behavior when here is some active activity that
1234                 // requests specific orientation or Keyguard is locked. Make sure all activity
1235                 // visibilities are set correctly as well as the transition is updated if needed
1236                 // to get the correct rotation behavior. Otherwise the following call to update
1237                 // the orientation may cause incorrect configurations delivered to client as a
1238                 // result of invisible window resize.
1239                 // TODO: Remove this once visibilities are set correctly immediately when
1240                 // starting an activity.
1241                 notUpdated = !mRootWindowContainer.ensureVisibilityAndConfig(next, getDisplayId(),
1242                         true /* markFrozenIfConfigChanged */, false /* deferResume */);
1243             }
1244 
1245             if (notUpdated) {
1246                 // The configuration update wasn't able to keep the existing
1247                 // instance of the activity, and instead started a new one.
1248                 // We should be all done, but let's just make sure our activity
1249                 // is still at the top and schedule another run if something
1250                 // weird happened.
1251                 ActivityRecord nextNext = topRunningActivity();
1252                 ProtoLog.i(WM_DEBUG_STATES, "Activity config changed during resume: "
1253                         + "%s, new next: %s", next, nextNext);
1254                 if (nextNext != next) {
1255                     // Do over!
1256                     mTaskSupervisor.scheduleResumeTopActivities();
1257                 }
1258                 if (!next.mVisibleRequested || next.stopped) {
1259                     next.setVisibility(true);
1260                 }
1261                 next.completeResumeLocked();
1262                 return true;
1263             }
1264 
1265             try {
1266                 final ClientTransaction transaction =
1267                         ClientTransaction.obtain(next.app.getThread(), next.appToken);
1268                 // Deliver all pending results.
1269                 ArrayList<ResultInfo> a = next.results;
1270                 if (a != null) {
1271                     final int size = a.size();
1272                     if (!next.finishing && size > 0) {
1273                         if (DEBUG_RESULTS) {
1274                             Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a);
1275                         }
1276                         transaction.addCallback(ActivityResultItem.obtain(a));
1277                     }
1278                 }
1279 
1280                 if (next.newIntents != null) {
1281                     transaction.addCallback(
1282                             NewIntentItem.obtain(next.newIntents, true /* resume */));
1283                 }
1284 
1285                 // Well the app will no longer be stopped.
1286                 // Clear app token stopped state in window manager if needed.
1287                 next.notifyAppResumed(next.stopped);
1288 
1289                 EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),
1290                         next.getTask().mTaskId, next.shortComponentName);
1291 
1292                 mAtmService.getAppWarningsLocked().onResumeActivity(next);
1293                 next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState);
1294                 next.abortAndClearOptionsAnimation();
1295                 transaction.setLifecycleStateRequest(
1296                         ResumeActivityItem.obtain(next.app.getReportedProcState(),
1297                                 dc.isNextTransitionForward()));
1298                 mAtmService.getLifecycleManager().scheduleTransaction(transaction);
1299 
1300                 ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Resumed %s", next);
1301             } catch (Exception e) {
1302                 // Whoops, need to restart this activity!
1303                 ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: "
1304                         + "%s", lastState, next);
1305                 next.setState(lastState, "resumeTopActivityInnerLocked");
1306 
1307                 // lastResumedActivity being non-null implies there is a lastStack present.
1308                 if (lastResumedActivity != null) {
1309                     lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked");
1310                 }
1311 
1312                 Slog.i(TAG, "Restarting because process died: " + next);
1313                 if (!next.hasBeenLaunched) {
1314                     next.hasBeenLaunched = true;
1315                 } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null
1316                         && lastFocusedRootTask.isTopRootTaskInDisplayArea()) {
1317                     next.showStartingWindow(false /* taskSwitch */);
1318                 }
1319                 mTaskSupervisor.startSpecificActivity(next, true, false);
1320                 return true;
1321             }
1322 
1323             // From this point on, if something goes wrong there is no way
1324             // to recover the activity.
1325             try {
1326                 next.completeResumeLocked();
1327             } catch (Exception e) {
1328                 // If any exception gets thrown, toss away this
1329                 // activity and try the next one.
1330                 Slog.w(TAG, "Exception thrown during resume of " + next, e);
1331                 next.finishIfPossible("resume-exception", true /* oomAdj */);
1332                 return true;
1333             }
1334         } else {
1335             // Whoops, need to restart this activity!
1336             if (!next.hasBeenLaunched) {
1337                 next.hasBeenLaunched = true;
1338             } else {
1339                 if (SHOW_APP_STARTING_PREVIEW) {
1340                     next.showStartingWindow(false /* taskSwich */);
1341                 }
1342                 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
1343             }
1344             ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Restarting %s", next);
1345             mTaskSupervisor.startSpecificActivity(next, true, true);
1346         }
1347 
1348         return true;
1349     }
1350 
shouldSleepOrShutDownActivities()1351     boolean shouldSleepOrShutDownActivities() {
1352         return shouldSleepActivities() || mAtmService.mShuttingDown;
1353     }
1354 
1355     /**
1356      * Returns true if the TaskFragment should be visible.
1357      *
1358      * @param starting The currently starting activity or null if there is none.
1359      */
shouldBeVisible(ActivityRecord starting)1360     boolean shouldBeVisible(ActivityRecord starting) {
1361         return getVisibility(starting) != TASK_FRAGMENT_VISIBILITY_INVISIBLE;
1362     }
1363 
1364     /**
1365      * Returns {@code true} is the activity in this TaskFragment can be resumed.
1366      *
1367      * @param starting The currently starting activity or {@code null} if there is none.
1368      */
canBeResumed(@ullable ActivityRecord starting)1369     boolean canBeResumed(@Nullable ActivityRecord starting) {
1370         // No need to resume activity in TaskFragment that is not visible.
1371         return isTopActivityFocusable()
1372                 && getVisibility(starting) == TASK_FRAGMENT_VISIBILITY_VISIBLE;
1373     }
1374 
isFocusableAndVisible()1375     boolean isFocusableAndVisible() {
1376         return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
1377     }
1378 
startPausing(boolean uiSleeping, ActivityRecord resuming, String reason)1379     final boolean startPausing(boolean uiSleeping, ActivityRecord resuming, String reason) {
1380         return startPausing(mTaskSupervisor.mUserLeaving, uiSleeping, resuming, reason);
1381     }
1382 
1383     /**
1384      * Start pausing the currently resumed activity.  It is an error to call this if there
1385      * is already an activity being paused or there is no resumed activity.
1386      *
1387      * @param userLeaving True if this should result in an onUserLeaving to the current activity.
1388      * @param uiSleeping True if this is happening with the user interface going to sleep (the
1389      * screen turning off).
1390      * @param resuming The activity we are currently trying to resume or null if this is not being
1391      *                 called as part of resuming the top activity, so we shouldn't try to instigate
1392      *                 a resume here if not null.
1393      * @param reason The reason of pausing the activity.
1394      * @return Returns true if an activity now is in the PAUSING state, and we are waiting for
1395      * it to tell us when it is done.
1396      */
startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming, String reason)1397     boolean startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming,
1398             String reason) {
1399         if (!hasDirectChildActivities()) {
1400             return false;
1401         }
1402 
1403         ProtoLog.d(WM_DEBUG_STATES, "startPausing: taskFrag =%s " + "mResumedActivity=%s", this,
1404                 mResumedActivity);
1405 
1406         if (mPausingActivity != null) {
1407             Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
1408                     + " state=" + mPausingActivity.getState());
1409             if (!shouldSleepActivities()) {
1410                 // Avoid recursion among check for sleep and complete pause during sleeping.
1411                 // Because activity will be paused immediately after resume, just let pause
1412                 // be completed by the order of activity paused from clients.
1413                 completePause(false, resuming);
1414             }
1415         }
1416         ActivityRecord prev = mResumedActivity;
1417 
1418         if (prev == null) {
1419             if (resuming == null) {
1420                 Slog.wtf(TAG, "Trying to pause when nothing is resumed");
1421                 mRootWindowContainer.resumeFocusedTasksTopActivities();
1422             }
1423             return false;
1424         }
1425 
1426         if (prev == resuming) {
1427             Slog.wtf(TAG, "Trying to pause activity that is in process of being resumed");
1428             return false;
1429         }
1430 
1431         ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSING: %s", prev);
1432         mPausingActivity = prev;
1433         mLastPausedActivity = prev;
1434         if (!prev.finishing && prev.isNoHistory()
1435                 && !mTaskSupervisor.mNoHistoryActivities.contains(prev)) {
1436             mTaskSupervisor.mNoHistoryActivities.add(prev);
1437         }
1438         prev.setState(PAUSING, "startPausingLocked");
1439         prev.getTask().touchActiveTime();
1440 
1441         mAtmService.updateCpuStats();
1442 
1443         boolean pauseImmediately = false;
1444         boolean shouldAutoPip = false;
1445         if (resuming != null) {
1446             // Resuming the new resume activity only if the previous activity can't go into Pip
1447             // since we want to give Pip activities a chance to enter Pip before resuming the
1448             // next activity.
1449             final boolean lastResumedCanPip = prev.checkEnterPictureInPictureState(
1450                     "shouldAutoPipWhilePausing", userLeaving);
1451             if (lastResumedCanPip && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
1452                 shouldAutoPip = true;
1453             } else if (!lastResumedCanPip) {
1454                 // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
1455                 // activity to be paused.
1456                 pauseImmediately = (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
1457             } else {
1458                 // The previous activity may still enter PIP even though it did not allow auto-PIP.
1459             }
1460         }
1461 
1462         if (prev.attachedToProcess()) {
1463             if (shouldAutoPip) {
1464                 boolean didAutoPip = mAtmService.enterPictureInPictureMode(
1465                         prev, prev.pictureInPictureArgs);
1466                 ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode "
1467                         + "directly: %s, didAutoPip: %b", prev, didAutoPip);
1468             } else {
1469                 schedulePauseActivity(prev, userLeaving, pauseImmediately, reason);
1470             }
1471         } else {
1472             mPausingActivity = null;
1473             mLastPausedActivity = null;
1474             mTaskSupervisor.mNoHistoryActivities.remove(prev);
1475         }
1476 
1477         // If we are not going to sleep, we want to ensure the device is
1478         // awake until the next activity is started.
1479         if (!uiSleeping && !mAtmService.isSleepingOrShuttingDownLocked()) {
1480             mTaskSupervisor.acquireLaunchWakelock();
1481         }
1482 
1483         // If already entered PIP mode, no need to keep pausing.
1484         if (mPausingActivity != null) {
1485             // Have the window manager pause its key dispatching until the new
1486             // activity has started.  If we're pausing the activity just because
1487             // the screen is being turned off and the UI is sleeping, don't interrupt
1488             // key dispatch; the same activity will pick it up again on wakeup.
1489             if (!uiSleeping) {
1490                 prev.pauseKeyDispatchingLocked();
1491             } else {
1492                 ProtoLog.v(WM_DEBUG_STATES, "Key dispatch not paused for screen off");
1493             }
1494 
1495             if (pauseImmediately) {
1496                 // If the caller said they don't want to wait for the pause, then complete
1497                 // the pause now.
1498                 completePause(false, resuming);
1499                 return false;
1500 
1501             } else {
1502                 prev.schedulePauseTimeout();
1503                 // Unset readiness since we now need to wait until this pause is complete.
1504                 mTransitionController.setReady(this, false /* ready */);
1505                 return true;
1506             }
1507 
1508         } else {
1509             // This activity either failed to schedule the pause or it entered PIP mode,
1510             // so just treat it as being paused now.
1511             ProtoLog.v(WM_DEBUG_STATES, "Activity not running or entered PiP, resuming next.");
1512             if (resuming == null) {
1513                 mRootWindowContainer.resumeFocusedTasksTopActivities();
1514             }
1515             return false;
1516         }
1517     }
1518 
schedulePauseActivity(ActivityRecord prev, boolean userLeaving, boolean pauseImmediately, String reason)1519     void schedulePauseActivity(ActivityRecord prev, boolean userLeaving,
1520             boolean pauseImmediately, String reason) {
1521         ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev);
1522         try {
1523             EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
1524                     prev.shortComponentName, "userLeaving=" + userLeaving, reason);
1525 
1526             mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
1527                     prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
1528                             prev.configChangeFlags, pauseImmediately));
1529         } catch (Exception e) {
1530             // Ignore exception, if process died other code will cleanup.
1531             Slog.w(TAG, "Exception thrown during pause", e);
1532             mPausingActivity = null;
1533             mLastPausedActivity = null;
1534             mTaskSupervisor.mNoHistoryActivities.remove(prev);
1535         }
1536     }
1537 
1538     @VisibleForTesting
completePause(boolean resumeNext, ActivityRecord resuming)1539     void completePause(boolean resumeNext, ActivityRecord resuming) {
1540         // Complete the pausing process of a pausing activity, so it doesn't make sense to
1541         // operate on non-leaf tasks.
1542         // warnForNonLeafTask("completePauseLocked");
1543 
1544         ActivityRecord prev = mPausingActivity;
1545         ProtoLog.v(WM_DEBUG_STATES, "Complete pause: %s", prev);
1546 
1547         if (prev != null) {
1548             prev.setWillCloseOrEnterPip(false);
1549             final boolean wasStopping = prev.isState(STOPPING);
1550             prev.setState(PAUSED, "completePausedLocked");
1551             if (prev.finishing) {
1552                 // We will update the activity visibility later, no need to do in
1553                 // completeFinishing(). Updating visibility here might also making the next
1554                 // activities to be resumed, and could result in wrong app transition due to
1555                 // lack of previous activity information.
1556                 ProtoLog.v(WM_DEBUG_STATES, "Executing finish of activity: %s", prev);
1557                 prev = prev.completeFinishing(false /* updateVisibility */,
1558                         "completePausedLocked");
1559             } else if (prev.hasProcess()) {
1560                 ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s "
1561                                 + "wasStopping=%b visibleRequested=%b",  prev,  wasStopping,
1562                         prev.mVisibleRequested);
1563                 if (prev.deferRelaunchUntilPaused) {
1564                     // Complete the deferred relaunch that was waiting for pause to complete.
1565                     ProtoLog.v(WM_DEBUG_STATES, "Re-launching after pause: %s", prev);
1566                     prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch);
1567                 } else if (wasStopping) {
1568                     // We are also stopping, the stop request must have gone soon after the pause.
1569                     // We can't clobber it, because the stop confirmation will not be handled.
1570                     // We don't need to schedule another stop, we only need to let it happen.
1571                     prev.setState(STOPPING, "completePausedLocked");
1572                 } else if (!prev.mVisibleRequested || shouldSleepOrShutDownActivities()) {
1573                     // Clear out any deferred client hide we might currently have.
1574                     prev.setDeferHidingClient(false);
1575                     // If we were visible then resumeTopActivities will release resources before
1576                     // stopping.
1577                     prev.addToStopping(true /* scheduleIdle */, false /* idleDelayed */,
1578                             "completePauseLocked");
1579                 }
1580             } else {
1581                 ProtoLog.v(WM_DEBUG_STATES, "App died during pause, not stopping: %s", prev);
1582                 prev = null;
1583             }
1584             // It is possible the activity was freezing the screen before it was paused.
1585             // In that case go ahead and remove the freeze this activity has on the screen
1586             // since it is no longer visible.
1587             if (prev != null) {
1588                 prev.stopFreezingScreenLocked(true /*force*/);
1589             }
1590             mPausingActivity = null;
1591         }
1592 
1593         if (resumeNext) {
1594             final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
1595             if (topRootTask != null && !topRootTask.shouldSleepOrShutDownActivities()) {
1596                 mRootWindowContainer.resumeFocusedTasksTopActivities(topRootTask, prev,
1597                         null /* targetOptions */);
1598             } else {
1599                 // checkReadyForSleep();
1600                 final ActivityRecord top =
1601                         topRootTask != null ? topRootTask.topRunningActivity() : null;
1602                 if (top == null || (prev != null && top != prev)) {
1603                     // If there are no more activities available to run, do resume anyway to start
1604                     // something. Also if the top activity on the root task is not the just paused
1605                     // activity, we need to go ahead and resume it to ensure we complete an
1606                     // in-flight app switch.
1607                     mRootWindowContainer.resumeFocusedTasksTopActivities();
1608                 }
1609             }
1610         }
1611 
1612         if (prev != null) {
1613             prev.resumeKeyDispatchingLocked();
1614         }
1615 
1616         mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
1617 
1618         // Notify when the task stack has changed, but only if visibilities changed (not just
1619         // focus). Also if there is an active root pinned task - we always want to notify it about
1620         // task stack changes, because its positioning may depend on it.
1621         if (mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause
1622                 || (getDisplayArea() != null && getDisplayArea().hasPinnedTask())) {
1623             mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
1624             mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
1625         }
1626     }
1627 
1628     @Override
forAllTaskFragments(Consumer<TaskFragment> callback, boolean traverseTopToBottom)1629     void forAllTaskFragments(Consumer<TaskFragment> callback, boolean traverseTopToBottom) {
1630         super.forAllTaskFragments(callback, traverseTopToBottom);
1631         callback.accept(this);
1632     }
1633 
1634     @Override
forAllLeafTaskFragments(Consumer<TaskFragment> callback, boolean traverseTopToBottom)1635     void forAllLeafTaskFragments(Consumer<TaskFragment> callback, boolean traverseTopToBottom) {
1636         final int count = mChildren.size();
1637         boolean isLeafTaskFrag = true;
1638         if (traverseTopToBottom) {
1639             for (int i = count - 1; i >= 0; --i) {
1640                 final TaskFragment child = mChildren.get(i).asTaskFragment();
1641                 if (child != null) {
1642                     isLeafTaskFrag = false;
1643                     child.forAllLeafTaskFragments(callback, traverseTopToBottom);
1644                 }
1645             }
1646         } else {
1647             for (int i = 0; i < count; i++) {
1648                 final TaskFragment child = mChildren.get(i).asTaskFragment();
1649                 if (child != null) {
1650                     isLeafTaskFrag = false;
1651                     child.forAllLeafTaskFragments(callback, traverseTopToBottom);
1652                 }
1653             }
1654         }
1655         if (isLeafTaskFrag) callback.accept(this);
1656     }
1657 
1658     @Override
forAllLeafTaskFragments(Function<TaskFragment, Boolean> callback)1659     boolean forAllLeafTaskFragments(Function<TaskFragment, Boolean> callback) {
1660         boolean isLeafTaskFrag = true;
1661         for (int i = mChildren.size() - 1; i >= 0; --i) {
1662             final TaskFragment child = mChildren.get(i).asTaskFragment();
1663             if (child != null) {
1664                 isLeafTaskFrag = false;
1665                 if (child.forAllLeafTaskFragments(callback)) {
1666                     return true;
1667                 }
1668             }
1669         }
1670         if (isLeafTaskFrag) {
1671             return callback.apply(this);
1672         }
1673         return false;
1674     }
1675 
addChild(ActivityRecord r)1676     void addChild(ActivityRecord r) {
1677         addChild(r, POSITION_TOP);
1678     }
1679 
1680     @Override
addChild(WindowContainer child, int index)1681     void addChild(WindowContainer child, int index) {
1682         mClearedTaskForReuse = false;
1683 
1684         boolean isAddingActivity = child.asActivityRecord() != null;
1685         final Task task = isAddingActivity ? getTask() : null;
1686 
1687         // If this task had any activity before we added this one.
1688         boolean taskHadActivity = task != null && task.getActivity(Objects::nonNull) != null;
1689         // getActivityType() looks at the top child, so we need to read the type before adding
1690         // a new child in case the new child is on top and UNDEFINED.
1691         final int activityType = task != null ? task.getActivityType() : ACTIVITY_TYPE_UNDEFINED;
1692 
1693         super.addChild(child, index);
1694 
1695         if (isAddingActivity && task != null) {
1696             child.asActivityRecord().inHistory = true;
1697             task.onDescendantActivityAdded(taskHadActivity, activityType, child.asActivityRecord());
1698         }
1699     }
1700 
1701     @Override
onChildPositionChanged(WindowContainer child)1702     void onChildPositionChanged(WindowContainer child) {
1703         super.onChildPositionChanged(child);
1704 
1705         sendTaskFragmentInfoChanged();
1706     }
1707 
executeAppTransition(ActivityOptions options)1708     void executeAppTransition(ActivityOptions options) {
1709         // No app transition applied to the task fragment.
1710     }
1711 
1712     @Override
createRemoteAnimationTarget( RemoteAnimationController.RemoteAnimationRecord record)1713     RemoteAnimationTarget createRemoteAnimationTarget(
1714             RemoteAnimationController.RemoteAnimationRecord record) {
1715         final ActivityRecord activity = record.getMode() == RemoteAnimationTarget.MODE_OPENING
1716                 // There may be a trampoline activity without window on top of the existing task
1717                 // which is moving to front. Exclude the finishing activity so the window of next
1718                 // activity can be chosen to create the animation target.
1719                 ? getTopNonFinishingActivity()
1720                 : getTopMostActivity();
1721         return activity != null ? activity.createRemoteAnimationTarget(record) : null;
1722     }
1723 
1724     @Override
canCreateRemoteAnimationTarget()1725     boolean canCreateRemoteAnimationTarget() {
1726         return true;
1727     }
1728 
shouldSleepActivities()1729     boolean shouldSleepActivities() {
1730         return false;
1731     }
1732 
1733     @Override
resolveOverrideConfiguration(Configuration newParentConfig)1734     void resolveOverrideConfiguration(Configuration newParentConfig) {
1735         mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
1736         super.resolveOverrideConfiguration(newParentConfig);
1737 
1738         int windowingMode =
1739                 getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
1740         final int parentWindowingMode = newParentConfig.windowConfiguration.getWindowingMode();
1741 
1742         // Resolve override windowing mode to fullscreen for home task (even on freeform
1743         // display), or split-screen if in split-screen mode.
1744         if (getActivityType() == ACTIVITY_TYPE_HOME && windowingMode == WINDOWING_MODE_UNDEFINED) {
1745             windowingMode = WindowConfiguration.isSplitScreenWindowingMode(parentWindowingMode)
1746                     ? parentWindowingMode : WINDOWING_MODE_FULLSCREEN;
1747             getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode);
1748         }
1749 
1750         // Do not allow tasks not support multi window to be in a multi-window mode, unless it is in
1751         // pinned windowing mode.
1752         if (!supportsMultiWindow()) {
1753             final int candidateWindowingMode =
1754                     windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : parentWindowingMode;
1755             if (WindowConfiguration.inMultiWindowMode(candidateWindowingMode)
1756                     && candidateWindowingMode != WINDOWING_MODE_PINNED) {
1757                 getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(
1758                         WINDOWING_MODE_FULLSCREEN);
1759             }
1760         }
1761 
1762         final Task thisTask = asTask();
1763         // Embedded Task's configuration should go with parent TaskFragment, so we don't re-compute
1764         // configuration here.
1765         if (thisTask != null && !thisTask.isEmbedded()) {
1766             thisTask.resolveLeafTaskOnlyOverrideConfigs(newParentConfig,
1767                     mTmpBounds /* previousBounds */);
1768         }
1769         computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
1770     }
1771 
supportsMultiWindow()1772     boolean supportsMultiWindow() {
1773         return supportsMultiWindowInDisplayArea(getDisplayArea());
1774     }
1775 
1776     /**
1777      * @return whether this task supports multi-window if it is in the given
1778      *         {@link TaskDisplayArea}.
1779      */
supportsMultiWindowInDisplayArea(@ullable TaskDisplayArea tda)1780     boolean supportsMultiWindowInDisplayArea(@Nullable TaskDisplayArea tda) {
1781         if (!mAtmService.mSupportsMultiWindow) {
1782             return false;
1783         }
1784         final Task task = getTask();
1785         if (task == null) {
1786             return false;
1787         }
1788         if (tda == null) {
1789             Slog.w(TAG, "Can't find TaskDisplayArea to determine support for multi"
1790                     + " window. Task id=" + getTaskId() + " attached=" + isAttached());
1791             return false;
1792         }
1793         if (!getTask().isResizeable() && !tda.supportsNonResizableMultiWindow()) {
1794             // Not support non-resizable in multi window.
1795             return false;
1796         }
1797 
1798         final ActivityRecord rootActivity = getTask().getRootActivity();
1799         return tda.supportsActivityMinWidthHeightMultiWindow(mMinWidth, mMinHeight,
1800                 rootActivity != null ? rootActivity.info : null);
1801     }
1802 
getTaskId()1803     private int getTaskId() {
1804         return getTask() != null ? getTask().mTaskId : INVALID_TASK_ID;
1805     }
1806 
1807     /**
1808      * Ensures all visible activities at or below the input activity have the right configuration.
1809      */
ensureVisibleActivitiesConfiguration(ActivityRecord start, boolean preserveWindow)1810     void ensureVisibleActivitiesConfiguration(ActivityRecord start, boolean preserveWindow) {
1811         mEnsureVisibleActivitiesConfigHelper.process(start, preserveWindow);
1812     }
1813 
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig)1814     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
1815             @NonNull Configuration parentConfig) {
1816         computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
1817                 null /* compatInsets */);
1818     }
1819 
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo)1820     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
1821             @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) {
1822         if (overrideDisplayInfo != null) {
1823             // Make sure the screen related configs can be computed by the provided display info.
1824             inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
1825             invalidateAppBoundsConfig(inOutConfig);
1826         }
1827         computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
1828                 null /* compatInsets */);
1829     }
1830 
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)1831     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
1832             @NonNull Configuration parentConfig,
1833             @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
1834         if (compatInsets != null) {
1835             // Make sure the app bounds can be computed by the compat insets.
1836             invalidateAppBoundsConfig(inOutConfig);
1837         }
1838         computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
1839                 compatInsets);
1840     }
1841 
1842     /**
1843      * Forces the app bounds related configuration can be computed by
1844      * {@link #computeConfigResourceOverrides(Configuration, Configuration, DisplayInfo,
1845      * ActivityRecord.CompatDisplayInsets)}.
1846      */
invalidateAppBoundsConfig(@onNull Configuration inOutConfig)1847     private static void invalidateAppBoundsConfig(@NonNull Configuration inOutConfig) {
1848         final Rect appBounds = inOutConfig.windowConfiguration.getAppBounds();
1849         if (appBounds != null) {
1850             appBounds.setEmpty();
1851         }
1852         inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
1853         inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
1854     }
1855 
1856     /**
1857      * Calculates configuration values used by the client to get resources. This should be run
1858      * using app-facing bounds (bounds unmodified by animations or transient interactions).
1859      *
1860      * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely
1861      * configuring an "inherit-bounds" window which means that all configuration settings would
1862      * just be inherited from the parent configuration.
1863      **/
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)1864     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
1865             @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
1866             @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
1867         int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
1868         if (windowingMode == WINDOWING_MODE_UNDEFINED) {
1869             windowingMode = parentConfig.windowConfiguration.getWindowingMode();
1870         }
1871 
1872         float density = inOutConfig.densityDpi;
1873         if (density == Configuration.DENSITY_DPI_UNDEFINED) {
1874             density = parentConfig.densityDpi;
1875         }
1876         density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
1877 
1878         // The bounds may have been overridden at this level. If the parent cannot cover these
1879         // bounds, the configuration is still computed according to the override bounds.
1880         final boolean insideParentBounds;
1881 
1882         final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
1883         final Rect resolvedBounds = inOutConfig.windowConfiguration.getBounds();
1884         if (resolvedBounds == null || resolvedBounds.isEmpty()) {
1885             mTmpFullBounds.set(parentBounds);
1886             insideParentBounds = true;
1887         } else {
1888             mTmpFullBounds.set(resolvedBounds);
1889             insideParentBounds = parentBounds.contains(resolvedBounds);
1890         }
1891 
1892         // Non-null compatibility insets means the activity prefers to keep its original size, so
1893         // out bounds doesn't need to be restricted by the parent or current display
1894         final boolean customContainerPolicy = compatInsets != null;
1895 
1896         Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
1897         if (outAppBounds == null || outAppBounds.isEmpty()) {
1898             // App-bounds hasn't been overridden, so calculate a value for it.
1899             inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds);
1900             outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
1901 
1902             if (!customContainerPolicy && windowingMode != WINDOWING_MODE_FREEFORM) {
1903                 final Rect containingAppBounds;
1904                 if (insideParentBounds) {
1905                     containingAppBounds = parentConfig.windowConfiguration.getAppBounds();
1906                 } else {
1907                     // Restrict appBounds to display non-decor rather than parent because the
1908                     // override bounds are beyond the parent. Otherwise, it won't match the
1909                     // overridden bounds.
1910                     final TaskDisplayArea displayArea = getDisplayArea();
1911                     containingAppBounds = displayArea != null
1912                             ? displayArea.getWindowConfiguration().getAppBounds() : null;
1913                 }
1914                 if (containingAppBounds != null && !containingAppBounds.isEmpty()) {
1915                     outAppBounds.intersect(containingAppBounds);
1916                 }
1917             }
1918         }
1919 
1920         if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
1921                 || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
1922             if (!customContainerPolicy && WindowConfiguration.isFloating(windowingMode)) {
1923                 mTmpNonDecorBounds.set(mTmpFullBounds);
1924                 mTmpStableBounds.set(mTmpFullBounds);
1925             } else if (!customContainerPolicy
1926                     && (overrideDisplayInfo != null || getDisplayContent() != null)) {
1927                 final DisplayInfo di = overrideDisplayInfo != null
1928                         ? overrideDisplayInfo
1929                         : getDisplayContent().getDisplayInfo();
1930 
1931                 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
1932                 // area, i.e. the screen area without the system bars.
1933                 // The non decor inset are areas that could never be removed in Honeycomb. See
1934                 // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
1935                 calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di);
1936             } else {
1937                 // Apply the given non-decor and stable insets to calculate the corresponding bounds
1938                 // for screen size of configuration.
1939                 int rotation = inOutConfig.windowConfiguration.getRotation();
1940                 if (rotation == ROTATION_UNDEFINED) {
1941                     rotation = parentConfig.windowConfiguration.getRotation();
1942                 }
1943                 if (rotation != ROTATION_UNDEFINED && customContainerPolicy) {
1944                     mTmpNonDecorBounds.set(mTmpFullBounds);
1945                     mTmpStableBounds.set(mTmpFullBounds);
1946                     compatInsets.getBoundsByRotation(mTmpBounds, rotation);
1947                     intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
1948                             compatInsets.mNonDecorInsets[rotation]);
1949                     intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
1950                             compatInsets.mStableInsets[rotation]);
1951                     outAppBounds.set(mTmpNonDecorBounds);
1952                 } else {
1953                     // Set to app bounds because it excludes decor insets.
1954                     mTmpNonDecorBounds.set(outAppBounds);
1955                     mTmpStableBounds.set(outAppBounds);
1956                 }
1957             }
1958 
1959             if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
1960                 final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
1961                 inOutConfig.screenWidthDp = (insideParentBounds && !customContainerPolicy)
1962                         ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
1963                         : overrideScreenWidthDp;
1964             }
1965             if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
1966                 final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
1967                 inOutConfig.screenHeightDp = (insideParentBounds && !customContainerPolicy)
1968                         ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
1969                         : overrideScreenHeightDp;
1970             }
1971 
1972             if (inOutConfig.smallestScreenWidthDp
1973                     == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
1974                 // When entering to or exiting from Pip, the PipTaskOrganizer will set the
1975                 // windowing mode of the activity in the task to WINDOWING_MODE_FULLSCREEN and
1976                 // temporarily set the bounds of the task to fullscreen size for transitioning.
1977                 // It will get the wrong value if the calculation is based on this temporary
1978                 // fullscreen bounds.
1979                 // We should just inherit the value from parent for this temporary state.
1980                 final boolean inPipTransition = windowingMode == WINDOWING_MODE_PINNED
1981                         && !mTmpFullBounds.isEmpty() && mTmpFullBounds.equals(parentBounds);
1982                 if (WindowConfiguration.isFloating(windowingMode) && !inPipTransition) {
1983                     // For floating tasks, calculate the smallest width from the bounds of the task
1984                     inOutConfig.smallestScreenWidthDp = (int) (
1985                             Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
1986                 }
1987                 // otherwise, it will just inherit
1988             }
1989         }
1990 
1991         if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
1992             inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
1993                     ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
1994         }
1995         if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
1996             // For calculating screen layout, we need to use the non-decor inset screen area for the
1997             // calculation for compatibility reasons, i.e. screen area without system bars that
1998             // could never go away in Honeycomb.
1999             int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
2000             int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
2001             // Use overrides if provided. If both overrides are provided, mTmpNonDecorBounds is
2002             // undefined so it can't be used.
2003             if (inOutConfig.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
2004                 compatScreenWidthDp = inOutConfig.screenWidthDp;
2005             }
2006             if (inOutConfig.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
2007                 compatScreenHeightDp = inOutConfig.screenHeightDp;
2008             }
2009             // Reducing the screen layout starting from its parent config.
2010             inOutConfig.screenLayout = computeScreenLayoutOverride(parentConfig.screenLayout,
2011                     compatScreenWidthDp, compatScreenHeightDp);
2012         }
2013     }
2014 
2015     /**
2016      * Gets bounds with non-decor and stable insets applied respectively.
2017      *
2018      * If bounds overhangs the display, those edges will not get insets. See
2019      * {@link #intersectWithInsetsIfFits}
2020      *
2021      * @param outNonDecorBounds where to place bounds with non-decor insets applied.
2022      * @param outStableBounds where to place bounds with stable insets applied.
2023      * @param bounds the bounds to inset.
2024      */
calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, DisplayInfo displayInfo)2025     void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds,
2026             DisplayInfo displayInfo) {
2027         outNonDecorBounds.set(bounds);
2028         outStableBounds.set(bounds);
2029         final Task rootTask = getRootTaskFragment().asTask();
2030         if (rootTask == null || rootTask.mDisplayContent == null) {
2031             return;
2032         }
2033         mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
2034 
2035         final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy();
2036         policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
2037                 displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
2038         intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
2039 
2040         policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
2041         intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
2042     }
2043 
2044     /**
2045      * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
2046      * intersectBounds on a side, then the respective side will not be intersected.
2047      *
2048      * The assumption is that if inOutBounds is initially larger than intersectBounds, then the
2049      * inset on that side is no-longer applicable. This scenario happens when a task's minimal
2050      * bounds are larger than the provided parent/display bounds.
2051      *
2052      * @param inOutBounds the bounds to intersect.
2053      * @param intersectBounds the bounds to intersect with.
2054      * @param intersectInsets insets to apply to intersectBounds before intersecting.
2055      */
intersectWithInsetsIfFits( Rect inOutBounds, Rect intersectBounds, Rect intersectInsets)2056     static void intersectWithInsetsIfFits(
2057             Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) {
2058         if (inOutBounds.right <= intersectBounds.right) {
2059             inOutBounds.right =
2060                     Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right);
2061         }
2062         if (inOutBounds.bottom <= intersectBounds.bottom) {
2063             inOutBounds.bottom =
2064                     Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom);
2065         }
2066         if (inOutBounds.left >= intersectBounds.left) {
2067             inOutBounds.left =
2068                     Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left);
2069         }
2070         if (inOutBounds.top >= intersectBounds.top) {
2071             inOutBounds.top =
2072                     Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top);
2073         }
2074     }
2075 
2076     /** Computes LONG, SIZE and COMPAT parts of {@link Configuration#screenLayout}. */
computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp, int screenHeightDp)2077     static int computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp,
2078             int screenHeightDp) {
2079         sourceScreenLayout = sourceScreenLayout
2080                 & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
2081         final int longSize = Math.max(screenWidthDp, screenHeightDp);
2082         final int shortSize = Math.min(screenWidthDp, screenHeightDp);
2083         return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize);
2084     }
2085 
2086     @Override
getActivityType()2087     public int getActivityType() {
2088         final int applicationType = super.getActivityType();
2089         if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
2090             return applicationType;
2091         }
2092         return getTopChild().getActivityType();
2093     }
2094 
2095     @Override
onConfigurationChanged(Configuration newParentConfig)2096     public void onConfigurationChanged(Configuration newParentConfig) {
2097         // Task will animate differently.
2098         if (mTaskFragmentOrganizer != null) {
2099             mTmpPrevBounds.set(getBounds());
2100         }
2101 
2102         super.onConfigurationChanged(newParentConfig);
2103 
2104         if (shouldStartChangeTransition(mTmpPrevBounds)) {
2105             initializeChangeTransition(mTmpPrevBounds);
2106         } else if (mTaskFragmentOrganizer != null) {
2107             // Update the surface here instead of in the organizer so that we can make sure
2108             // it can be synced with the surface freezer.
2109             final SurfaceControl.Transaction t = getSyncTransaction();
2110             updateSurfacePosition(t);
2111             updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */);
2112         }
2113 
2114         sendTaskFragmentInfoChanged();
2115     }
2116 
2117     /** Updates the surface size so that the sub windows cannot be shown out of bounds. */
updateOrganizedTaskFragmentSurfaceSize(SurfaceControl.Transaction t, boolean forceUpdate)2118     private void updateOrganizedTaskFragmentSurfaceSize(SurfaceControl.Transaction t,
2119             boolean forceUpdate) {
2120         if (mTaskFragmentOrganizer == null) {
2121             // We only want to update for organized TaskFragment. Task will handle itself.
2122             return;
2123         }
2124         if (mSurfaceControl == null || mSurfaceAnimator.hasLeash() || mSurfaceFreezer.hasLeash()) {
2125             return;
2126         }
2127 
2128         final Rect bounds = getBounds();
2129         final int width = bounds.width();
2130         final int height = bounds.height();
2131         if (!forceUpdate && width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
2132             return;
2133         }
2134         t.setWindowCrop(mSurfaceControl, width, height);
2135         mLastSurfaceSize.set(width, height);
2136     }
2137 
2138     @Override
onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash)2139     public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) {
2140         super.onAnimationLeashCreated(t, leash);
2141         // Reset surface bounds for animation. It will be taken care by the animation leash, and
2142         // reset again onAnimationLeashLost.
2143         if (mTaskFragmentOrganizer != null
2144                 && (mLastSurfaceSize.x != 0 || mLastSurfaceSize.y != 0)) {
2145             t.setWindowCrop(mSurfaceControl, 0, 0);
2146             mLastSurfaceSize.set(0, 0);
2147         }
2148     }
2149 
2150     @Override
onAnimationLeashLost(SurfaceControl.Transaction t)2151     public void onAnimationLeashLost(SurfaceControl.Transaction t) {
2152         super.onAnimationLeashLost(t);
2153         // Update the surface bounds after animation.
2154         if (mTaskFragmentOrganizer != null) {
2155             updateOrganizedTaskFragmentSurfaceSize(t, true /* forceUpdate */);
2156         }
2157     }
2158 
2159     /** Whether we should prepare a transition for this {@link TaskFragment} bounds change. */
shouldStartChangeTransition(Rect startBounds)2160     private boolean shouldStartChangeTransition(Rect startBounds) {
2161         if (mTaskFragmentOrganizer == null || !canStartChangeTransition()) {
2162             return false;
2163         }
2164 
2165         return !startBounds.equals(getBounds());
2166     }
2167 
2168     @Override
setSurfaceControl(SurfaceControl sc)2169     void setSurfaceControl(SurfaceControl sc) {
2170         super.setSurfaceControl(sc);
2171         if (mTaskFragmentOrganizer != null) {
2172             final SurfaceControl.Transaction t = getSyncTransaction();
2173             updateSurfacePosition(t);
2174             updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */);
2175             // If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to
2176             // emit the callbacks now.
2177             sendTaskFragmentAppeared();
2178         }
2179     }
2180 
sendTaskFragmentInfoChanged()2181     void sendTaskFragmentInfoChanged() {
2182         if (mTaskFragmentOrganizer != null) {
2183             mTaskFragmentOrganizerController
2184                     .onTaskFragmentInfoChanged(mTaskFragmentOrganizer, this);
2185         }
2186     }
2187 
sendTaskFragmentAppeared()2188     private void sendTaskFragmentAppeared() {
2189         if (mTaskFragmentOrganizer != null) {
2190             mTaskFragmentOrganizerController.onTaskFragmentAppeared(mTaskFragmentOrganizer, this);
2191         }
2192     }
2193 
sendTaskFragmentVanished()2194     private void sendTaskFragmentVanished() {
2195         if (mTaskFragmentOrganizer != null) {
2196             mTaskFragmentOrganizerController.onTaskFragmentVanished(mTaskFragmentOrganizer, this);
2197         }
2198     }
2199 
2200     /**
2201      * Returns a {@link TaskFragmentInfo} with information from this TaskFragment. Should not be
2202      * called from {@link Task}.
2203      */
getTaskFragmentInfo()2204     TaskFragmentInfo getTaskFragmentInfo() {
2205         List<IBinder> childActivities = new ArrayList<>();
2206         for (int i = 0; i < getChildCount(); i++) {
2207             final WindowContainer wc = getChildAt(i);
2208             final ActivityRecord ar = wc.asActivityRecord();
2209             if (mTaskFragmentOrganizerUid != INVALID_UID && ar != null
2210                     && ar.info.processName.equals(mTaskFragmentOrganizerProcessName)
2211                     && ar.getUid() == mTaskFragmentOrganizerUid && !ar.finishing) {
2212                 // Only includes Activities that belong to the organizer process for security.
2213                 childActivities.add(ar.appToken);
2214             }
2215         }
2216         final Point positionInParent = new Point();
2217         getRelativePosition(positionInParent);
2218         final int[] runningActivityCount = new int[1];
2219         forAllActivities(a -> {
2220             if (!a.finishing) {
2221                 runningActivityCount[0]++;
2222             }
2223         });
2224         return new TaskFragmentInfo(
2225                 mFragmentToken,
2226                 mRemoteToken.toWindowContainerToken(),
2227                 getConfiguration(),
2228                 getChildCount() == 0,
2229                 runningActivityCount[0],
2230                 isVisible(),
2231                 childActivities,
2232                 positionInParent,
2233                 mClearedTaskForReuse);
2234     }
2235 
2236     @Nullable
getFragmentToken()2237     IBinder getFragmentToken() {
2238         return mFragmentToken;
2239     }
2240 
2241     @Nullable
getTaskFragmentOrganizer()2242     ITaskFragmentOrganizer getTaskFragmentOrganizer() {
2243         return mTaskFragmentOrganizer;
2244     }
2245 
2246     @Override
isOrganized()2247     boolean isOrganized() {
2248         return mTaskFragmentOrganizer != null;
2249     }
2250 
2251     /** Whether this is an organized {@link TaskFragment} and not a {@link Task}. */
isOrganizedTaskFragment()2252     final boolean isOrganizedTaskFragment() {
2253         return mTaskFragmentOrganizer != null;
2254     }
2255 
isReadyToTransit()2256     boolean isReadyToTransit() {
2257         // We don't want to start the transition if the organized TaskFragment is empty, unless
2258         // it is requested to be removed.
2259         return !isOrganizedTaskFragment() || getTopNonFinishingActivity() != null
2260                 || mIsRemovalRequested;
2261     }
2262 
2263     /** Clear {@link #mLastPausedActivity} for all {@link TaskFragment} children */
clearLastPausedActivity()2264     void clearLastPausedActivity() {
2265         forAllTaskFragments(taskFragment -> taskFragment.mLastPausedActivity = null);
2266     }
2267 
2268     /**
2269      * Sets {@link #mMinWidth} and {@link #mMinWidth} to this TaskFragment.
2270      * It is usually set from the parent {@link Task} when adding the TaskFragment to the window
2271      * hierarchy.
2272      */
setMinDimensions(int minWidth, int minHeight)2273     void setMinDimensions(int minWidth, int minHeight) {
2274         if (asTask() != null) {
2275             throw new UnsupportedOperationException("This method must not be used to Task. The "
2276                     + " minimum dimension of Task should be passed from Task constructor.");
2277         }
2278         mMinWidth = minWidth;
2279         mMinHeight = minHeight;
2280     }
2281 
2282     @Override
removeChild(WindowContainer child)2283     void removeChild(WindowContainer child) {
2284         removeChild(child, true /* removeSelfIfPossible */);
2285     }
2286 
removeChild(WindowContainer child, boolean removeSelfIfPossible)2287     void removeChild(WindowContainer child, boolean removeSelfIfPossible) {
2288         super.removeChild(child);
2289         if (removeSelfIfPossible && (!mCreatedByOrganizer || mIsRemovalRequested) && !hasChild()) {
2290             removeImmediately("removeLastChild " + child);
2291         }
2292     }
2293 
2294     /**
2295      * Requests to remove this task fragment. If it doesn't have children, it is removed
2296      * immediately. Otherwise it will be removed until all activities are destroyed.
2297      *
2298      * @param withTransition Whether to use transition animation when removing activities. Set to
2299      *                       {@code false} if this is invisible to user, e.g. display removal.
2300      */
remove(boolean withTransition, String reason)2301     void remove(boolean withTransition, String reason) {
2302         if (!hasChild()) {
2303             removeImmediately(reason);
2304             return;
2305         }
2306         mIsRemovalRequested = true;
2307         forAllActivities(r -> {
2308             if (withTransition) {
2309                 r.finishIfPossible(reason, false /* oomAdj */);
2310             } else {
2311                 r.destroyIfPossible(reason);
2312             }
2313         });
2314     }
2315 
setDelayLastActivityRemoval(boolean delay)2316     void setDelayLastActivityRemoval(boolean delay) {
2317         if (!mIsEmbedded) {
2318             Slog.w(TAG, "Set delaying last activity removal on a non-embedded TF.");
2319         }
2320         mDelayLastActivityRemoval = delay;
2321     }
2322 
isDelayLastActivityRemoval()2323     boolean isDelayLastActivityRemoval() {
2324         return mDelayLastActivityRemoval;
2325     }
2326 
shouldDeferRemoval()2327     boolean shouldDeferRemoval() {
2328         if (!hasChild()) {
2329             return false;
2330         }
2331         return isAnimating(TRANSITION | CHILDREN, WindowState.EXIT_ANIMATING_TYPES)
2332                 || inTransition();
2333     }
2334 
2335     @Override
handleCompleteDeferredRemoval()2336     boolean handleCompleteDeferredRemoval() {
2337         if (shouldDeferRemoval()) {
2338             return true;
2339         }
2340         return super.handleCompleteDeferredRemoval();
2341     }
2342 
2343     /** The overridden method must call {@link #removeImmediately()} instead of super. */
removeImmediately(String reason)2344     void removeImmediately(String reason) {
2345         Slog.d(TAG, "Remove task fragment: " + reason);
2346         removeImmediately();
2347     }
2348 
2349     @Override
removeImmediately()2350     void removeImmediately() {
2351         mIsRemovalRequested = false;
2352         resetAdjacentTaskFragment();
2353         super.removeImmediately();
2354         sendTaskFragmentVanished();
2355     }
2356 
2357     @Override
getDimmer()2358     Dimmer getDimmer() {
2359         // If the window is in an embedded TaskFragment, we want to dim at the TaskFragment.
2360         if (asTask() == null) {
2361             return mDimmer;
2362         }
2363 
2364         return super.getDimmer();
2365     }
2366 
2367     @Override
prepareSurfaces()2368     void prepareSurfaces() {
2369         if (asTask() != null) {
2370             super.prepareSurfaces();
2371             return;
2372         }
2373 
2374         mDimmer.resetDimStates();
2375         super.prepareSurfaces();
2376 
2377         // Bounds need to be relative, as the dim layer is a child.
2378         final Rect dimBounds = getBounds();
2379         dimBounds.offsetTo(0 /* newLeft */, 0 /* newTop */);
2380         if (mDimmer.updateDims(getPendingTransaction(), dimBounds)) {
2381             scheduleAnimation();
2382         }
2383     }
2384 
2385     @Override
canBeAnimationTarget()2386     boolean canBeAnimationTarget() {
2387         return true;
2388     }
2389 
2390     @Override
fillsParent()2391     boolean fillsParent() {
2392         // From the perspective of policy, we still want to report that this task fills parent
2393         // in fullscreen windowing mode even it doesn't match parent bounds because there will be
2394         // letterbox around its real content.
2395         return getWindowingMode() == WINDOWING_MODE_FULLSCREEN || matchParentBounds();
2396     }
2397 
dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, String dumpPackage, final boolean needSep, Runnable header)2398     boolean dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll,
2399             boolean dumpClient, String dumpPackage, final boolean needSep, Runnable header) {
2400         boolean printed = false;
2401         Runnable headerPrinter = () -> {
2402             if (needSep) {
2403                 pw.println();
2404             }
2405             if (header != null) {
2406                 header.run();
2407             }
2408 
2409             dumpInner(prefix, pw, dumpAll, dumpPackage);
2410         };
2411 
2412         if (dumpPackage == null) {
2413             // If we are not filtering by package, we want to print absolutely everything,
2414             // so always print the header even if there are no tasks/activities inside.
2415             headerPrinter.run();
2416             headerPrinter = null;
2417             printed = true;
2418         }
2419 
2420         for (int i = mChildren.size() - 1; i >= 0; --i) {
2421             WindowContainer child = mChildren.get(i);
2422             if (child.asTaskFragment() != null) {
2423                 printed |= child.asTaskFragment().dump(prefix + "  ", fd, pw, dumpAll,
2424                         dumpClient, dumpPackage, needSep, headerPrinter);
2425             } else if (child.asActivityRecord() != null) {
2426                 ActivityRecord.dumpActivity(fd, pw, i, child.asActivityRecord(), prefix + "  ",
2427                         "Hist ", true, !dumpAll, dumpClient, dumpPackage, false, headerPrinter,
2428                         getTask());
2429             }
2430         }
2431 
2432         return printed;
2433     }
2434 
dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage)2435     void dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage) {
2436         pw.print(prefix); pw.print("* "); pw.println(this);
2437         final Rect bounds = getRequestedOverrideBounds();
2438         if (!bounds.isEmpty()) {
2439             pw.println(prefix + "  mBounds=" + bounds);
2440         }
2441         if (mIsRemovalRequested) {
2442             pw.println(prefix + "  mIsRemovalRequested=true");
2443         }
2444         if (dumpAll) {
2445             printThisActivity(pw, mLastPausedActivity, dumpPackage, false,
2446                     prefix + "  mLastPausedActivity: ", null);
2447         }
2448     }
2449 
2450     @Override
dump(PrintWriter pw, String prefix, boolean dumpAll)2451     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
2452         super.dump(pw, prefix, dumpAll);
2453         pw.println(prefix + "bounds=" + getBounds().toShortString());
2454         final String doublePrefix = prefix + "  ";
2455         for (int i = mChildren.size() - 1; i >= 0; i--) {
2456             final WindowContainer<?> child = mChildren.get(i);
2457             pw.println(prefix + "* " + child);
2458             // Only dump non-activity because full activity info is already printed by
2459             // RootWindowContainer#dumpActivities.
2460             if (child.asActivityRecord() == null) {
2461                 child.dump(pw, doublePrefix, dumpAll);
2462             }
2463         }
2464     }
2465 
2466     @Override
writeIdentifierToProto(ProtoOutputStream proto, long fieldId)2467     void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
2468         final long token = proto.start(fieldId);
2469         proto.write(HASH_CODE, System.identityHashCode(this));
2470         final ActivityRecord topActivity = topRunningActivity();
2471         proto.write(USER_ID, topActivity != null ? topActivity.mUserId : USER_NULL);
2472         proto.write(TITLE, topActivity != null ? topActivity.intent.getComponent()
2473                 .flattenToShortString() : "TaskFragment");
2474         proto.end(token);
2475     }
2476 
2477     @Override
getProtoFieldId()2478     long getProtoFieldId() {
2479         return TASK_FRAGMENT;
2480     }
2481 
2482     @Override
dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel)2483     public void dumpDebug(ProtoOutputStream proto, long fieldId,
2484             @WindowTraceLogLevel int logLevel) {
2485         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
2486             return;
2487         }
2488 
2489         final long token = proto.start(fieldId);
2490 
2491         super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
2492 
2493         proto.write(DISPLAY_ID, getDisplayId());
2494         proto.write(ACTIVITY_TYPE, getActivityType());
2495         proto.write(MIN_WIDTH, mMinWidth);
2496         proto.write(MIN_HEIGHT, mMinHeight);
2497 
2498         proto.end(token);
2499     }
2500 }
2501