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_ASSISTANT;
21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
23 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
24 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
25 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
26 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
27 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
28 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
29 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
30 import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
31 import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
32 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
33 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
34 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
35 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
36 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
37 import static android.os.Process.INVALID_UID;
38 import static android.os.Process.SYSTEM_UID;
39 import static android.os.UserHandle.USER_NULL;
40 import static android.view.Display.INVALID_DISPLAY;
41 import static android.view.WindowManager.TRANSIT_CLOSE;
42 import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
43 import static android.view.WindowManager.TRANSIT_NONE;
44 import static android.view.WindowManager.TRANSIT_OPEN;
45 
46 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
47 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
48 import static com.android.server.wm.ActivityRecord.State.PAUSED;
49 import static com.android.server.wm.ActivityRecord.State.PAUSING;
50 import static com.android.server.wm.ActivityRecord.State.RESUMED;
51 import static com.android.server.wm.ActivityRecord.State.STOPPING;
52 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
53 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
54 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
55 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS;
56 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
57 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION;
58 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
59 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
60 import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
61 import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity;
62 import static com.android.server.wm.IdentifierProto.HASH_CODE;
63 import static com.android.server.wm.IdentifierProto.TITLE;
64 import static com.android.server.wm.IdentifierProto.USER_ID;
65 import static com.android.server.wm.TaskFragmentProto.ACTIVITY_TYPE;
66 import static com.android.server.wm.TaskFragmentProto.DISPLAY_ID;
67 import static com.android.server.wm.TaskFragmentProto.MIN_HEIGHT;
68 import static com.android.server.wm.TaskFragmentProto.MIN_WIDTH;
69 import static com.android.server.wm.TaskFragmentProto.WINDOW_CONTAINER;
70 import static com.android.server.wm.WindowContainerChildProto.TASK_FRAGMENT;
71 
72 import android.annotation.IntDef;
73 import android.annotation.NonNull;
74 import android.annotation.Nullable;
75 import android.app.ActivityOptions;
76 import android.app.ResultInfo;
77 import android.app.WindowConfiguration;
78 import android.app.servertransaction.ActivityResultItem;
79 import android.app.servertransaction.ClientTransaction;
80 import android.app.servertransaction.NewIntentItem;
81 import android.app.servertransaction.PauseActivityItem;
82 import android.app.servertransaction.ResumeActivityItem;
83 import android.content.pm.ActivityInfo;
84 import android.content.res.Configuration;
85 import android.graphics.Point;
86 import android.graphics.Rect;
87 import android.hardware.HardwareBuffer;
88 import android.os.IBinder;
89 import android.os.RemoteException;
90 import android.os.UserHandle;
91 import android.util.DisplayMetrics;
92 import android.util.Slog;
93 import android.util.proto.ProtoOutputStream;
94 import android.view.DisplayInfo;
95 import android.view.RemoteAnimationTarget;
96 import android.view.SurfaceControl;
97 import android.window.ITaskFragmentOrganizer;
98 import android.window.ScreenCapture;
99 import android.window.TaskFragmentAnimationParams;
100 import android.window.TaskFragmentInfo;
101 import android.window.TaskFragmentOrganizerToken;
102 
103 import com.android.internal.annotations.VisibleForTesting;
104 import com.android.internal.protolog.common.ProtoLog;
105 import com.android.server.am.HostingRecord;
106 import com.android.server.pm.pkg.AndroidPackage;
107 
108 import java.io.FileDescriptor;
109 import java.io.PrintWriter;
110 import java.util.ArrayList;
111 import java.util.HashMap;
112 import java.util.List;
113 import java.util.Set;
114 import java.util.function.Consumer;
115 import java.util.function.Predicate;
116 
117 /**
118  * A basic container that can be used to contain activities or other {@link TaskFragment}, which
119  * also able to manage the activity lifecycle and updates the visibilities of the activities in it.
120  */
121 class TaskFragment extends WindowContainer<WindowContainer> {
122     @IntDef(prefix = {"TASK_FRAGMENT_VISIBILITY"}, value = {
123             TASK_FRAGMENT_VISIBILITY_VISIBLE,
124             TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
125             TASK_FRAGMENT_VISIBILITY_INVISIBLE,
126     })
127     @interface TaskFragmentVisibility {}
128 
129     /**
130      * TaskFragment is visible. No other TaskFragment(s) on top that fully or partially occlude it.
131      */
132     static final int TASK_FRAGMENT_VISIBILITY_VISIBLE = 0;
133 
134     /** TaskFragment is partially occluded by other translucent TaskFragment(s) on top of it. */
135     static final int TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT = 1;
136 
137     /** TaskFragment is completely invisible. */
138     static final int TASK_FRAGMENT_VISIBILITY_INVISIBLE = 2;
139 
140     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskFragment" : TAG_ATM;
141     private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
142     private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
143     private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION;
144 
145     /** Set to false to disable the preview that is shown while a new activity is being started. */
146     static final boolean SHOW_APP_STARTING_PREVIEW = true;
147 
148     /**
149      * An embedding check result of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
150      * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
151      * indicate that an Activity can be embedded successfully.
152      */
153     static final int EMBEDDING_ALLOWED = 0;
154     /**
155      * An embedding check result of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
156      * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
157      * indicate that an Activity can't be embedded because either the Activity does not allow
158      * untrusted embedding, and the embedding host app is not trusted.
159      */
160     static final int EMBEDDING_DISALLOWED_UNTRUSTED_HOST = 1;
161     /**
162      * An embedding check result of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
163      * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
164      * indicate that an Activity can't be embedded because this taskFragment's bounds are
165      * {@link #smallerThanMinDimension(ActivityRecord)}.
166      */
167     static final int EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION = 2;
168     /**
169      * An embedding check result of
170      * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
171      * indicate that an Activity can't be embedded because the Activity is started on a new task.
172      */
173     static final int EMBEDDING_DISALLOWED_NEW_TASK = 3;
174 
175     /**
176      * Embedding check results of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
177      * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}.
178      */
179     @IntDef(prefix = {"EMBEDDING_"}, value = {
180             EMBEDDING_ALLOWED,
181             EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
182             EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
183             EMBEDDING_DISALLOWED_NEW_TASK,
184     })
185     @interface EmbeddingCheckResult {}
186 
187     /**
188      * Indicate that the minimal width/height should use the default value.
189      *
190      * @see #mMinWidth
191      * @see #mMinHeight
192      */
193     static final int INVALID_MIN_SIZE = -1;
194 
195     final ActivityTaskManagerService mAtmService;
196     final ActivityTaskSupervisor mTaskSupervisor;
197     final RootWindowContainer mRootWindowContainer;
198     private final TaskFragmentOrganizerController mTaskFragmentOrganizerController;
199 
200     // TODO(b/233177466): Move mMinWidth and mMinHeight to Task and remove usages in TaskFragment
201     /**
202      * Minimal width of this task fragment when it's resizeable. {@link #INVALID_MIN_SIZE} means it
203      * should use the default minimal width.
204      */
205     int mMinWidth;
206 
207     /**
208      * Minimal height of this task fragment when it's resizeable. {@link #INVALID_MIN_SIZE} means it
209      * should use the default minimal height.
210      */
211     int mMinHeight;
212 
213     Dimmer mDimmer = new Dimmer(this);
214 
215     /** This task fragment will be removed when the cleanup of its children are done. */
216     private boolean mIsRemovalRequested;
217 
218     /** The TaskFragment that is adjacent to this one. */
219     @Nullable
220     private TaskFragment mAdjacentTaskFragment;
221 
222     /**
223      * Unlike the {@link mAdjacentTaskFragment}, the companion TaskFragment is not always visually
224      * adjacent to this one, but this TaskFragment will be removed by the organizer if the
225      * companion TaskFragment is removed.
226      */
227     @Nullable
228     private TaskFragment mCompanionTaskFragment;
229 
230     /**
231      * Prevents duplicate calls to onTaskFragmentAppeared.
232      */
233     boolean mTaskFragmentAppearedSent;
234 
235     /**
236      * Prevents unnecessary callbacks after onTaskFragmentVanished.
237      */
238     boolean mTaskFragmentVanishedSent;
239 
240     /**
241      * The last running activity of the TaskFragment was finished due to clear task while launching
242      * an activity in the Task.
243      */
244     boolean mClearedTaskForReuse;
245 
246     /**
247      * The last running activity of the TaskFragment was reparented to a different Task because it
248      * is entering PiP.
249      */
250     boolean mClearedTaskFragmentForPip;
251 
252     /**
253      * The last running activity of the TaskFragment was removed and added to the top-most of the
254      * Task because it was launched with FLAG_ACTIVITY_REORDER_TO_FRONT.
255      */
256     boolean mClearedForReorderActivityToFront;
257 
258     /**
259      * When we are in the process of pausing an activity, before starting the
260      * next one, this variable holds the activity that is currently being paused.
261      *
262      * Only set at leaf task fragments.
263      */
264     @Nullable
265     private ActivityRecord mPausingActivity = null;
266 
267     /**
268      * This is the last activity that we put into the paused state.  This is
269      * used to determine if we need to do an activity transition while sleeping,
270      * when we normally hold the top activity paused.
271      */
272     ActivityRecord mLastPausedActivity = null;
273 
274     /**
275      * Current activity that is resumed, or null if there is none.
276      * Only set at leaf task fragments.
277      */
278     @Nullable
279     private ActivityRecord mResumedActivity = null;
280 
281     /**
282      * This TaskFragment was created by an organizer which has the following implementations.
283      * <ul>
284      *     <li>The TaskFragment won't be removed when it is empty. Removal has to be an explicit
285      *     request from the organizer.</li>
286      *     <li>If this fragment is a Task object then unlike other non-root tasks, it's direct
287      *     children are visible to the organizer for ordering purposes.</li>
288      *     <li>A TaskFragment can be created by {@link android.window.TaskFragmentOrganizer}, and
289      *     a Task can be created by {@link android.window.TaskOrganizer}.</li>
290      * </ul>
291      */
292     @VisibleForTesting
293     boolean mCreatedByOrganizer;
294 
295     /** Whether this TaskFragment is embedded in a task. */
296     private final boolean mIsEmbedded;
297 
298     /** Organizer that organizing this TaskFragment. */
299     @Nullable
300     private ITaskFragmentOrganizer mTaskFragmentOrganizer;
301     private int mTaskFragmentOrganizerUid = INVALID_UID;
302     private @Nullable String mTaskFragmentOrganizerProcessName;
303 
304     /** Client assigned unique token for this TaskFragment if this is created by an organizer. */
305     @Nullable
306     private final IBinder mFragmentToken;
307 
308     /** The animation override params for animation running on this TaskFragment. */
309     @NonNull
310     private TaskFragmentAnimationParams mAnimationParams = TaskFragmentAnimationParams.DEFAULT;
311 
312     /**
313      * The organizer requested bounds of the embedded TaskFragment relative to the parent Task.
314      * {@code null} if it is not {@link #mIsEmbedded}
315      */
316     @Nullable
317     private final Rect mRelativeEmbeddedBounds;
318 
319     /**
320      * Whether to delay the call to {@link #updateOrganizedTaskFragmentSurface()} when there is a
321      * configuration change.
322      */
323     private boolean mDelayOrganizedTaskFragmentSurfaceUpdate;
324 
325     /**
326      * Whether to delay the last activity of TaskFragment being immediately removed while finishing.
327      * This should only be set on a embedded TaskFragment, where the organizer can have the
328      * opportunity to perform animations and finishing the adjacent TaskFragment.
329      */
330     private boolean mDelayLastActivityRemoval;
331 
332     /**
333      * Whether the activity navigation should be isolated. That is, Activities cannot be launched
334      * on an isolated TaskFragment, unless the activity is launched from an Activity in the same
335      * isolated TaskFragment, or explicitly requested to be launched to.
336      * <p>
337      * Note that only an embedded TaskFragment can be isolated.
338      */
339     private boolean mIsolatedNav;
340 
341     final Point mLastSurfaceSize = new Point();
342 
343     private final Rect mTmpBounds = new Rect();
344     private final Rect mTmpAbsBounds = new Rect();
345     private final Rect mTmpFullBounds = new Rect();
346     /** For calculating screenWidthDp and screenWidthDp, i.e. the area without the system bars. */
347     private final Rect mTmpStableBounds = new Rect();
348     /** For calculating app bounds, i.e. the area without the nav bar and display cutout. */
349     private final Rect mTmpNonDecorBounds = new Rect();
350 
351     //TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is
352     // implemented
353     HashMap<String, ScreenCapture.ScreenshotHardwareBuffer> mBackScreenshots = new HashMap<>();
354 
355     private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper =
356             new EnsureActivitiesVisibleHelper(this);
357     private final EnsureVisibleActivitiesConfigHelper mEnsureVisibleActivitiesConfigHelper =
358             new EnsureVisibleActivitiesConfigHelper();
359     private class EnsureVisibleActivitiesConfigHelper implements Predicate<ActivityRecord> {
360         private boolean mUpdateConfig;
361         private boolean mPreserveWindow;
362         private boolean mBehindFullscreen;
363 
reset(boolean preserveWindow)364         void reset(boolean preserveWindow) {
365             mPreserveWindow = preserveWindow;
366             mUpdateConfig = false;
367             mBehindFullscreen = false;
368         }
369 
process(ActivityRecord start, boolean preserveWindow)370         void process(ActivityRecord start, boolean preserveWindow) {
371             if (start == null || !start.isVisibleRequested()) {
372                 return;
373             }
374             reset(preserveWindow);
375             forAllActivities(this, start, true /* includeBoundary */,
376                     true /* traverseTopToBottom */);
377 
378             if (mUpdateConfig) {
379                 // Ensure the resumed state of the focus activity if we updated the configuration of
380                 // any activity.
381                 mRootWindowContainer.resumeFocusedTasksTopActivities();
382             }
383         }
384 
385         @Override
test(ActivityRecord r)386         public boolean test(ActivityRecord r) {
387             mUpdateConfig |= r.ensureActivityConfiguration(0 /*globalChanges*/, mPreserveWindow);
388             mBehindFullscreen |= r.occludesParent();
389             return mBehindFullscreen;
390         }
391     }
392 
393     /** Creates an embedded task fragment. */
TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken, boolean createdByOrganizer)394     TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken,
395             boolean createdByOrganizer) {
396         this(atmService, fragmentToken, createdByOrganizer, true /* isEmbedded */);
397     }
398 
TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken, boolean createdByOrganizer, boolean isEmbedded)399     TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken,
400             boolean createdByOrganizer, boolean isEmbedded) {
401         super(atmService.mWindowManager);
402 
403         mAtmService = atmService;
404         mTaskSupervisor = mAtmService.mTaskSupervisor;
405         mRootWindowContainer = mAtmService.mRootWindowContainer;
406         mCreatedByOrganizer = createdByOrganizer;
407         mIsEmbedded = isEmbedded;
408         mRelativeEmbeddedBounds = isEmbedded ? new Rect() : null;
409         mTaskFragmentOrganizerController =
410                 mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController;
411         mFragmentToken = fragmentToken;
412         mRemoteToken = new RemoteToken(this);
413     }
414 
415     @NonNull
fromTaskFragmentToken(@ullable IBinder token, @NonNull ActivityTaskManagerService service)416     static TaskFragment fromTaskFragmentToken(@Nullable IBinder token,
417             @NonNull ActivityTaskManagerService service) {
418         if (token == null) return null;
419         return service.mWindowOrganizerController.getTaskFragment(token);
420     }
421 
setAdjacentTaskFragment(@ullable TaskFragment taskFragment)422     void setAdjacentTaskFragment(@Nullable TaskFragment taskFragment) {
423         if (mAdjacentTaskFragment == taskFragment) {
424             return;
425         }
426         resetAdjacentTaskFragment();
427         if (taskFragment != null) {
428             mAdjacentTaskFragment = taskFragment;
429             taskFragment.setAdjacentTaskFragment(this);
430         }
431     }
432 
setCompanionTaskFragment(@ullable TaskFragment companionTaskFragment)433     void setCompanionTaskFragment(@Nullable TaskFragment companionTaskFragment) {
434         mCompanionTaskFragment = companionTaskFragment;
435     }
436 
getCompanionTaskFragment()437     TaskFragment getCompanionTaskFragment() {
438         return mCompanionTaskFragment;
439     }
440 
resetAdjacentTaskFragment()441     void resetAdjacentTaskFragment() {
442         // Reset the adjacent TaskFragment if its adjacent TaskFragment is also this TaskFragment.
443         if (mAdjacentTaskFragment != null && mAdjacentTaskFragment.mAdjacentTaskFragment == this) {
444             mAdjacentTaskFragment.mAdjacentTaskFragment = null;
445             mAdjacentTaskFragment.mDelayLastActivityRemoval = false;
446         }
447         mAdjacentTaskFragment = null;
448         mDelayLastActivityRemoval = false;
449     }
450 
setTaskFragmentOrganizer(@onNull TaskFragmentOrganizerToken organizer, int uid, @NonNull String processName)451     void setTaskFragmentOrganizer(@NonNull TaskFragmentOrganizerToken organizer, int uid,
452             @NonNull String processName) {
453         mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(organizer.asBinder());
454         mTaskFragmentOrganizerUid = uid;
455         mTaskFragmentOrganizerProcessName = processName;
456     }
457 
onTaskFragmentOrganizerRemoved()458     void onTaskFragmentOrganizerRemoved() {
459         mTaskFragmentOrganizer = null;
460     }
461 
462     /** Whether this TaskFragment is organized by the given {@code organizer}. */
hasTaskFragmentOrganizer(ITaskFragmentOrganizer organizer)463     boolean hasTaskFragmentOrganizer(ITaskFragmentOrganizer organizer) {
464         return organizer != null && mTaskFragmentOrganizer != null
465                 && organizer.asBinder().equals(mTaskFragmentOrganizer.asBinder());
466     }
467 
468     /**
469      * Returns the process of organizer if this TaskFragment is organized and the activity lives in
470      * a different process than the organizer.
471      */
472     @Nullable
getOrganizerProcessIfDifferent(@ullable ActivityRecord r)473     private WindowProcessController getOrganizerProcessIfDifferent(@Nullable ActivityRecord r) {
474         if ((r == null || mTaskFragmentOrganizerProcessName == null)
475                 || (mTaskFragmentOrganizerProcessName.equals(r.processName)
476                 && mTaskFragmentOrganizerUid == r.getUid())) {
477             // No organizer or the process is the same.
478             return null;
479         }
480         return mAtmService.getProcessController(mTaskFragmentOrganizerProcessName,
481                 mTaskFragmentOrganizerUid);
482     }
483 
setAnimationParams(@onNull TaskFragmentAnimationParams animationParams)484     void setAnimationParams(@NonNull TaskFragmentAnimationParams animationParams) {
485         mAnimationParams = animationParams;
486     }
487 
488     @NonNull
getAnimationParams()489     TaskFragmentAnimationParams getAnimationParams() {
490         return mAnimationParams;
491     }
492 
493     /** @see #mIsolatedNav */
setIsolatedNav(boolean isolatedNav)494     void setIsolatedNav(boolean isolatedNav) {
495         if (!isEmbedded()) {
496             return;
497         }
498         mIsolatedNav = isolatedNav;
499     }
500 
501     /** @see #mIsolatedNav */
isIsolatedNav()502     boolean isIsolatedNav() {
503         return isEmbedded() && mIsolatedNav;
504     }
505 
getAdjacentTaskFragment()506     TaskFragment getAdjacentTaskFragment() {
507         return mAdjacentTaskFragment;
508     }
509 
510     /** Returns the currently topmost resumed activity. */
511     @Nullable
getTopResumedActivity()512     ActivityRecord getTopResumedActivity() {
513         final ActivityRecord taskFragResumedActivity = getResumedActivity();
514         for (int i = getChildCount() - 1; i >= 0; --i) {
515             WindowContainer<?> child = getChildAt(i);
516             ActivityRecord topResumedActivity = null;
517             if (taskFragResumedActivity != null && child == taskFragResumedActivity) {
518                 topResumedActivity = child.asActivityRecord();
519             } else if (child.asTaskFragment() != null) {
520                 topResumedActivity = child.asTaskFragment().getTopResumedActivity();
521             }
522             if (topResumedActivity != null) {
523                 return topResumedActivity;
524             }
525         }
526         return null;
527     }
528 
529     /**
530      * Returns the currently resumed activity in this TaskFragment's
531      * {@link #mChildren direct children}
532      */
getResumedActivity()533     ActivityRecord getResumedActivity() {
534         return mResumedActivity;
535     }
536 
setResumedActivity(ActivityRecord r, String reason)537     void setResumedActivity(ActivityRecord r, String reason) {
538         warnForNonLeafTaskFragment("setResumedActivity");
539         if (mResumedActivity == r) {
540             return;
541         }
542 
543         if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
544             Slog.d(TAG, "setResumedActivity taskFrag:" + this + " + from: "
545                     + mResumedActivity + " to:" + r + " reason:" + reason);
546         }
547 
548         if (r != null && mResumedActivity == null) {
549             // Task is becoming active.
550             getTask().touchActiveTime();
551         }
552 
553         final ActivityRecord prevR = mResumedActivity;
554         mResumedActivity = r;
555         mTaskSupervisor.updateTopResumedActivityIfNeeded(reason);
556         if (r == null && prevR.mDisplayContent != null
557                 && prevR.mDisplayContent.getFocusedRootTask() == null) {
558             // Only need to notify DWPC when no activity will resume.
559             prevR.mDisplayContent.onRunningActivityChanged();
560         } else if (r != null) {
561             r.mDisplayContent.onRunningActivityChanged();
562         }
563     }
564 
565     @VisibleForTesting
setPausingActivity(ActivityRecord pausing)566     void setPausingActivity(ActivityRecord pausing) {
567         mPausingActivity = pausing;
568     }
569 
570     /** Returns the currently topmost pausing activity. */
571     @Nullable
getTopPausingActivity()572     ActivityRecord getTopPausingActivity() {
573         final ActivityRecord taskFragPausingActivity = getPausingActivity();
574         for (int i = getChildCount() - 1; i >= 0; --i) {
575             WindowContainer<?> child = getChildAt(i);
576             ActivityRecord topPausingActivity = null;
577             if (taskFragPausingActivity != null && child == taskFragPausingActivity) {
578                 topPausingActivity = child.asActivityRecord();
579             } else if (child.asTaskFragment() != null) {
580                 topPausingActivity = child.asTaskFragment().getTopPausingActivity();
581             }
582             if (topPausingActivity != null) {
583                 return topPausingActivity;
584             }
585         }
586         return null;
587     }
588 
getPausingActivity()589     ActivityRecord getPausingActivity() {
590         return mPausingActivity;
591     }
592 
getDisplayId()593     int getDisplayId() {
594         final DisplayContent dc = getDisplayContent();
595         return dc != null ? dc.mDisplayId : INVALID_DISPLAY;
596     }
597 
598     @Nullable
getTask()599     Task getTask() {
600         if (asTask() != null) {
601             return asTask();
602         }
603 
604         TaskFragment parent = getParent() != null ? getParent().asTaskFragment() : null;
605         return parent != null ? parent.getTask() : null;
606     }
607 
608     @Override
609     @Nullable
getDisplayArea()610     TaskDisplayArea getDisplayArea() {
611         return (TaskDisplayArea) super.getDisplayArea();
612     }
613 
614     @Override
isAttached()615     public boolean isAttached() {
616         final TaskDisplayArea taskDisplayArea = getDisplayArea();
617         return taskDisplayArea != null && !taskDisplayArea.isRemoved();
618     }
619 
620     /**
621      * Returns the root {@link TaskFragment}, which is usually also a {@link Task}.
622      */
623     @NonNull
getRootTaskFragment()624     TaskFragment getRootTaskFragment() {
625         final WindowContainer parent = getParent();
626         if (parent == null) return this;
627 
628         final TaskFragment parentTaskFragment = parent.asTaskFragment();
629         return parentTaskFragment == null ? this : parentTaskFragment.getRootTaskFragment();
630     }
631 
632     @Nullable
getRootTask()633     Task getRootTask() {
634         return getRootTaskFragment().asTask();
635     }
636 
637     @Override
asTaskFragment()638     TaskFragment asTaskFragment() {
639         return this;
640     }
641 
642     @Override
isEmbedded()643     boolean isEmbedded() {
644         return mIsEmbedded;
645     }
646 
647     @EmbeddingCheckResult
isAllowedToEmbedActivity(@onNull ActivityRecord a)648     int isAllowedToEmbedActivity(@NonNull ActivityRecord a) {
649         return isAllowedToEmbedActivity(a, mTaskFragmentOrganizerUid);
650     }
651 
652     /**
653      * Checks if the organized task fragment is allowed to have the specified activity, which is
654      * allowed if an activity allows embedding in untrusted mode, if the trusted mode can be
655      * enabled, or if the organized task fragment bounds are not
656      * {@link #smallerThanMinDimension(ActivityRecord)}.
657      *
658      * @param uid   uid of the TaskFragment organizer.
659      * @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
660      */
661     @EmbeddingCheckResult
isAllowedToEmbedActivity(@onNull ActivityRecord a, int uid)662     int isAllowedToEmbedActivity(@NonNull ActivityRecord a, int uid) {
663         if (!isAllowedToEmbedActivityInUntrustedMode(a)
664                 && !isAllowedToEmbedActivityInTrustedMode(a, uid)) {
665             return EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
666         }
667 
668         if (smallerThanMinDimension(a)) {
669             return EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
670         }
671 
672         return EMBEDDING_ALLOWED;
673     }
674 
smallerThanMinDimension(@onNull ActivityRecord activity)675     boolean smallerThanMinDimension(@NonNull ActivityRecord activity) {
676         final Rect taskFragBounds = getBounds();
677         final Task task = getTask();
678         // Don't need to check if the bounds match parent Task bounds because the fallback mechanism
679         // is to reparent the Activity to parent if minimum dimensions are not satisfied.
680         if (task == null || taskFragBounds.equals(task.getBounds())) {
681             return false;
682         }
683         final Point minDimensions = activity.getMinDimensions();
684         if (minDimensions == null) {
685             return false;
686         }
687         final int minWidth = minDimensions.x;
688         final int minHeight = minDimensions.y;
689         return taskFragBounds.width() < minWidth
690                 || taskFragBounds.height() < minHeight;
691     }
692 
693     /**
694      * Checks if the organized task fragment is allowed to embed activity in untrusted mode.
695      */
isAllowedToEmbedActivityInUntrustedMode(@onNull ActivityRecord a)696     boolean isAllowedToEmbedActivityInUntrustedMode(@NonNull ActivityRecord a) {
697         final WindowContainer parent = getParent();
698         if (parent == null || !parent.getBounds().contains(getBounds())) {
699             // Without full trust between the host and the embedded activity, we don't allow
700             // TaskFragment to have bounds outside of the parent bounds.
701             return false;
702         }
703         return (a.info.flags & FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING)
704                 == FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
705     }
706 
isAllowedToEmbedActivityInTrustedMode(@onNull ActivityRecord a)707     boolean isAllowedToEmbedActivityInTrustedMode(@NonNull ActivityRecord a) {
708         return isAllowedToEmbedActivityInTrustedMode(a, mTaskFragmentOrganizerUid);
709     }
710 
711     /**
712      * Checks if the organized task fragment is allowed to embed activity in fully trusted mode,
713      * which means that all transactions are allowed. This is supported in the following cases:
714      * <li>the activity belongs to the same app as the organizer host;</li>
715      * <li>the activity has declared the organizer host as trusted explicitly via known
716      * certificate.</li>
717      * @param uid   uid of the TaskFragment organizer.
718      */
isAllowedToEmbedActivityInTrustedMode(@onNull ActivityRecord a, int uid)719     boolean isAllowedToEmbedActivityInTrustedMode(@NonNull ActivityRecord a, int uid) {
720         if (isFullyTrustedEmbedding(a, uid)) {
721             return true;
722         }
723 
724         Set<String> knownActivityEmbeddingCerts = a.info.getKnownActivityEmbeddingCerts();
725         if (knownActivityEmbeddingCerts.isEmpty()) {
726             // An application must either declare that it allows untrusted embedding, or specify
727             // a set of app certificates that are allowed to embed it in trusted mode.
728             return false;
729         }
730 
731         AndroidPackage hostPackage = mAtmService.getPackageManagerInternalLocked()
732                 .getPackage(uid);
733 
734         return hostPackage != null && hostPackage.getSigningDetails().hasAncestorOrSelfWithDigest(
735                 knownActivityEmbeddingCerts);
736     }
737 
738     /**
739      * It is fully trusted for embedding in the system app or embedding in the same app. This is
740      * different from {@link #isAllowedToBeEmbeddedInTrustedMode()} since there may be a small
741      * chance for a previous trusted app to start doing something bad.
742      */
isFullyTrustedEmbedding(@onNull ActivityRecord a, int uid)743     private static boolean isFullyTrustedEmbedding(@NonNull ActivityRecord a, int uid) {
744         // The system is trusted to embed other apps securely and for all users.
745         return UserHandle.getAppId(uid) == SYSTEM_UID
746                 // Activities from the same UID can be embedded freely by the host.
747                 || a.isUid(uid);
748     }
749 
750     /**
751      * Checks if all activities in the task fragment are embedded as fully trusted.
752      * @see #isFullyTrustedEmbedding(ActivityRecord, int)
753      * @param uid   uid of the TaskFragment organizer.
754      */
isFullyTrustedEmbedding(int uid)755     boolean isFullyTrustedEmbedding(int uid) {
756         // Traverse all activities to see if any of them are not fully trusted embedding.
757         return !forAllActivities(r -> !isFullyTrustedEmbedding(r, uid));
758     }
759 
760     /**
761      * Checks if all activities in the task fragment are allowed to be embedded in trusted mode.
762      * @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
763      */
isAllowedToBeEmbeddedInTrustedMode()764     boolean isAllowedToBeEmbeddedInTrustedMode() {
765         // Traverse all activities to see if any of them are not in the trusted mode.
766         return !forAllActivities(r -> !isAllowedToEmbedActivityInTrustedMode(r));
767     }
768 
769     /**
770      * Returns the TaskFragment that is being organized, which could be this or the ascendant
771      * TaskFragment.
772      */
773     @Nullable
getOrganizedTaskFragment()774     TaskFragment getOrganizedTaskFragment() {
775         if (mTaskFragmentOrganizer != null) {
776             return this;
777         }
778 
779         TaskFragment parentTaskFragment = getParent() != null ? getParent().asTaskFragment() : null;
780         return parentTaskFragment != null ? parentTaskFragment.getOrganizedTaskFragment() : null;
781     }
782 
783     /**
784      * Simply check and give warning logs if this is not operated on leaf {@link TaskFragment}.
785      */
warnForNonLeafTaskFragment(String func)786     private void warnForNonLeafTaskFragment(String func) {
787         if (!isLeafTaskFragment()) {
788             Slog.w(TAG, func + " on non-leaf task fragment " + this);
789         }
790     }
791 
hasDirectChildActivities()792     boolean hasDirectChildActivities() {
793         for (int i = mChildren.size() - 1; i >= 0; --i) {
794             if (mChildren.get(i).asActivityRecord() != null) {
795                 return true;
796             }
797         }
798         return false;
799     }
800 
cleanUpActivityReferences(@onNull ActivityRecord r)801     void cleanUpActivityReferences(@NonNull ActivityRecord r) {
802         if (mPausingActivity != null && mPausingActivity == r) {
803             mPausingActivity = null;
804         }
805 
806         if (mResumedActivity != null && mResumedActivity == r) {
807             setResumedActivity(null, "cleanUpActivityReferences");
808         }
809         r.removeTimeouts();
810     }
811 
812     /**
813      * Returns whether this TaskFragment is currently forced to be hidden for any reason.
814      */
isForceHidden()815     protected boolean isForceHidden() {
816         return false;
817     }
818 
isForceTranslucent()819     protected boolean isForceTranslucent() {
820         return false;
821     }
822 
isLeafTaskFragment()823     boolean isLeafTaskFragment() {
824         for (int i = mChildren.size() - 1; i >= 0; --i) {
825             if (mChildren.get(i).asTaskFragment() != null) {
826                 return false;
827             }
828         }
829         return true;
830     }
831 
832     /**
833      * This should be called when an child activity changes state. This should only
834      * be called from
835      * {@link ActivityRecord#setState(ActivityRecord.State, String)} .
836      * @param record The {@link ActivityRecord} whose state has changed.
837      * @param state The new state.
838      * @param reason The reason for the change.
839      */
onActivityStateChanged(ActivityRecord record, ActivityRecord.State state, String reason)840     void onActivityStateChanged(ActivityRecord record, ActivityRecord.State state,
841             String reason) {
842         warnForNonLeafTaskFragment("onActivityStateChanged");
843         if (record == mResumedActivity && state != RESUMED) {
844             setResumedActivity(null, reason + " - onActivityStateChanged");
845         }
846 
847         if (state == RESUMED) {
848             if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
849                 Slog.v(TAG, "set resumed activity to:" + record + " reason:" + reason);
850             }
851             setResumedActivity(record, reason + " - onActivityStateChanged");
852             mTaskSupervisor.mRecentTasks.add(record.getTask());
853         }
854 
855         // Update the process state for the organizer process if the activity is in a different
856         // process in case the organizer process may not have activity state change in its process.
857         final WindowProcessController hostProcess = getOrganizerProcessIfDifferent(record);
858         if (hostProcess != null) {
859             mTaskSupervisor.onProcessActivityStateChanged(hostProcess, false /* forceBatch */);
860             hostProcess.updateProcessInfo(false /* updateServiceConnectionActivities */,
861                     true /* activityChange */, true /* updateOomAdj */,
862                     false /* addPendingTopUid */);
863         }
864     }
865 
866     /**
867      * Resets local parameters because an app's activity died.
868      * @param app The app of the activity that died.
869      * @return {@code true} if the process of the pausing activity is died.
870      */
handleAppDied(WindowProcessController app)871     boolean handleAppDied(WindowProcessController app) {
872         warnForNonLeafTaskFragment("handleAppDied");
873         boolean isPausingDied = false;
874         if (mPausingActivity != null && mPausingActivity.app == app) {
875             ProtoLog.v(WM_DEBUG_STATES, "App died while pausing: %s",
876                     mPausingActivity);
877             mPausingActivity = null;
878             isPausingDied = true;
879         }
880         if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
881             mLastPausedActivity = null;
882         }
883         return isPausingDied;
884     }
885 
awakeFromSleeping()886     void awakeFromSleeping() {
887         if (mPausingActivity != null) {
888             Slog.d(TAG, "awakeFromSleeping: previously pausing activity didn't pause");
889             mPausingActivity.activityPaused(true);
890         }
891     }
892 
893     /**
894      * Tries to put the activities in the task fragment to sleep.
895      *
896      * If the task fragment is not in a state where its activities can be put to sleep, this
897      * function will start any necessary actions to move the task fragment into such a state.
898      * It is expected that this function get called again when those actions complete.
899      *
900      * @param shuttingDown {@code true} when the called because the device is shutting down.
901      * @return true if the root task finished going to sleep, false if the root task only started
902      * the process of going to sleep (checkReadyForSleep will be called when that process finishes).
903      */
sleepIfPossible(boolean shuttingDown)904     boolean sleepIfPossible(boolean shuttingDown) {
905         boolean shouldSleep = true;
906         if (mResumedActivity != null) {
907             // Still have something resumed; can't sleep until it is paused.
908             ProtoLog.v(WM_DEBUG_STATES, "Sleep needs to pause %s", mResumedActivity);
909             startPausing(false /* userLeaving */, true /* uiSleeping */, null /* resuming */,
910                     "sleep");
911             shouldSleep = false;
912         } else if (mPausingActivity != null) {
913             // Still waiting for something to pause; can't sleep yet.
914             ProtoLog.v(WM_DEBUG_STATES, "Sleep still waiting to pause %s", mPausingActivity);
915             shouldSleep = false;
916         }
917 
918         if (!shuttingDown) {
919             if (containsStoppingActivity()) {
920                 // Still need to tell some activities to stop; can't sleep yet.
921                 ProtoLog.v(WM_DEBUG_STATES, "Sleep still need to stop %d activities",
922                         mTaskSupervisor.mStoppingActivities.size());
923 
924                 mTaskSupervisor.scheduleIdle();
925                 shouldSleep = false;
926             }
927         }
928 
929         if (shouldSleep) {
930             updateActivityVisibilities(null /* starting */, 0 /* configChanges */,
931                     !PRESERVE_WINDOWS, true /* notifyClients */);
932         }
933 
934         return shouldSleep;
935     }
936 
containsStoppingActivity()937     private boolean containsStoppingActivity() {
938         for (int i = mTaskSupervisor.mStoppingActivities.size() - 1; i >= 0; --i) {
939             ActivityRecord r = mTaskSupervisor.mStoppingActivities.get(i);
940             if (r.getTaskFragment() == this) {
941                 return true;
942             }
943         }
944         return false;
945     }
946 
947     /**
948      * Returns true if the TaskFragment is translucent and can have other contents visible behind
949      * it if needed. A TaskFragment is considered translucent if it don't contain a visible or
950      * starting (about to be visible) activity that is fullscreen (opaque).
951      * @param starting The currently starting activity or null if there is none.
952      */
isTranslucent(@ullable ActivityRecord starting)953     boolean isTranslucent(@Nullable ActivityRecord starting) {
954         if (!isAttached() || isForceHidden() || isForceTranslucent()) {
955             return true;
956         }
957         // A TaskFragment isn't translucent if it has at least one visible activity that occludes
958         // this TaskFragment.
959         return mTaskSupervisor.mOpaqueActivityHelper.getVisibleOpaqueActivity(this,
960                 starting) == null;
961     }
962 
963     /**
964      * Whether the TaskFragment should be treated as translucent for the current transition.
965      * This is different from {@link #isTranslucent(ActivityRecord)} as this function also checks
966      * finishing activities when the TaskFragment itself is becoming invisible.
967      */
isTranslucentForTransition()968     boolean isTranslucentForTransition() {
969         if (!isAttached() || isForceHidden() || isForceTranslucent()) {
970             return true;
971         }
972         // Including finishing Activity if the TaskFragment is becoming invisible in the transition.
973         return mTaskSupervisor.mOpaqueActivityHelper.getOpaqueActivity(this) == null;
974     }
975 
getTopNonFinishingActivity()976     ActivityRecord getTopNonFinishingActivity() {
977         return getTopNonFinishingActivity(true /* includeOverlays */);
978     }
979 
980     /**
981      * Returns the top-most non-finishing activity, even if the activity is NOT ok to show to
982      * the current user.
983      * @param includeOverlays whether the task overlay activity should be included.
984      * @see #topRunningActivity(boolean)
985      */
getTopNonFinishingActivity(boolean includeOverlays)986     ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
987         // Split into 2 to avoid object creation due to variable capture.
988         if (includeOverlays) {
989             return getActivity((r) -> !r.finishing);
990         }
991         return getActivity((r) -> !r.finishing && !r.isTaskOverlay());
992     }
993 
topRunningActivity()994     ActivityRecord topRunningActivity() {
995         return topRunningActivity(false /* focusableOnly */);
996     }
997 
998     /**
999      * Returns the top-most running activity, which the activity is non-finishing and ok to show
1000      * to the current user.
1001      *
1002      * @see ActivityRecord#canBeTopRunning()
1003      */
topRunningActivity(boolean focusableOnly)1004     ActivityRecord topRunningActivity(boolean focusableOnly) {
1005         // Split into 2 to avoid object creation due to variable capture.
1006         if (focusableOnly) {
1007             return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
1008         }
1009         return getActivity(ActivityRecord::canBeTopRunning);
1010     }
1011 
getNonFinishingActivityCount()1012     int getNonFinishingActivityCount() {
1013         final int[] runningActivityCount = new int[1];
1014         forAllActivities(a -> {
1015             if (!a.finishing) {
1016                 runningActivityCount[0]++;
1017             }
1018         });
1019         return runningActivityCount[0];
1020     }
1021 
isTopActivityFocusable()1022     boolean isTopActivityFocusable() {
1023         final ActivityRecord r = topRunningActivity();
1024         return r != null ? r.isFocusable()
1025                 : (isFocusable() && getWindowConfiguration().canReceiveKeys());
1026     }
1027 
1028     /**
1029      * Returns the visibility state of this TaskFragment.
1030      *
1031      * @param starting The currently starting activity or null if there is none.
1032      */
1033     @TaskFragmentVisibility
getVisibility(ActivityRecord starting)1034     int getVisibility(ActivityRecord starting) {
1035         if (!isAttached() || isForceHidden()) {
1036             return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
1037         }
1038 
1039         if (isTopActivityLaunchedBehind()) {
1040             return TASK_FRAGMENT_VISIBILITY_VISIBLE;
1041         }
1042         final WindowContainer<?> parent = getParent();
1043         final Task thisTask = asTask();
1044         if (thisTask != null && parent.asTask() == null
1045                 && mTransitionController.isTransientVisible(thisTask)) {
1046             // Keep transient-hide root tasks visible. Non-root tasks still follow standard rule.
1047             return TASK_FRAGMENT_VISIBILITY_VISIBLE;
1048         }
1049 
1050         boolean gotTranslucentFullscreen = false;
1051         boolean gotTranslucentAdjacent = false;
1052         boolean shouldBeVisible = true;
1053 
1054         // This TaskFragment is only considered visible if all its parent TaskFragments are
1055         // considered visible, so check the visibility of all ancestor TaskFragment first.
1056         if (parent.asTaskFragment() != null) {
1057             final int parentVisibility = parent.asTaskFragment().getVisibility(starting);
1058             if (parentVisibility == TASK_FRAGMENT_VISIBILITY_INVISIBLE) {
1059                 // Can't be visible if parent isn't visible
1060                 return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
1061             } else if (parentVisibility == TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) {
1062                 // Parent is behind a translucent container so the highest visibility this container
1063                 // can get is that.
1064                 gotTranslucentFullscreen = true;
1065             }
1066         }
1067 
1068         final List<TaskFragment> adjacentTaskFragments = new ArrayList<>();
1069         for (int i = parent.getChildCount() - 1; i >= 0; --i) {
1070             final WindowContainer other = parent.getChildAt(i);
1071             if (other == null) continue;
1072 
1073             final boolean hasRunningActivities = hasRunningActivity(other);
1074             if (other == this) {
1075                 if (!adjacentTaskFragments.isEmpty() && !gotTranslucentAdjacent) {
1076                     // The z-order of this TaskFragment is in middle of two adjacent TaskFragments
1077                     // and it cannot be visible if the TaskFragment on top is not translucent and
1078                     // is occluding this one.
1079                     mTmpRect.set(getBounds());
1080                     for (int j = adjacentTaskFragments.size() - 1; j >= 0; --j) {
1081                         final TaskFragment taskFragment = adjacentTaskFragments.get(j);
1082                         final TaskFragment adjacentTaskFragment =
1083                                 taskFragment.mAdjacentTaskFragment;
1084                         if (adjacentTaskFragment == this) {
1085                             continue;
1086                         }
1087                         if (mTmpRect.intersect(taskFragment.getBounds())
1088                                 || mTmpRect.intersect(adjacentTaskFragment.getBounds())) {
1089                             return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
1090                         }
1091                     }
1092                 }
1093                 // Should be visible if there is no other fragment occluding it, unless it doesn't
1094                 // have any running activities, not starting one and not home stack.
1095                 shouldBeVisible = hasRunningActivities
1096                         || (starting != null && starting.isDescendantOf(this))
1097                         || isActivityTypeHome();
1098                 break;
1099             }
1100 
1101             if (!hasRunningActivities) {
1102                 continue;
1103             }
1104 
1105             final int otherWindowingMode = other.getWindowingMode();
1106             if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) {
1107                 if (isTranslucent(other, starting)) {
1108                     // Can be visible behind a translucent fullscreen TaskFragment.
1109                     gotTranslucentFullscreen = true;
1110                     continue;
1111                 }
1112                 return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
1113             } else if (otherWindowingMode == WINDOWING_MODE_MULTI_WINDOW
1114                     && other.matchParentBounds()) {
1115                 if (isTranslucent(other, starting)) {
1116                     // Can be visible behind a translucent TaskFragment.
1117                     gotTranslucentFullscreen = true;
1118                     continue;
1119                 }
1120                 // Multi-window TaskFragment that matches parent bounds would occlude other children
1121                 return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
1122             }
1123 
1124             final TaskFragment otherTaskFrag = other.asTaskFragment();
1125             if (otherTaskFrag != null && otherTaskFrag.mAdjacentTaskFragment != null) {
1126                 if (adjacentTaskFragments.contains(otherTaskFrag.mAdjacentTaskFragment)) {
1127                     if (otherTaskFrag.isTranslucent(starting)
1128                             || otherTaskFrag.mAdjacentTaskFragment.isTranslucent(starting)) {
1129                         // Can be visible behind a translucent adjacent TaskFragments.
1130                         gotTranslucentFullscreen = true;
1131                         gotTranslucentAdjacent = true;
1132                         continue;
1133                     }
1134                     // Can not be visible behind adjacent TaskFragments.
1135                     return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
1136                 } else {
1137                     adjacentTaskFragments.add(otherTaskFrag);
1138                 }
1139             }
1140 
1141         }
1142 
1143         if (!shouldBeVisible) {
1144             return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
1145         }
1146 
1147         // Lastly - check if there is a translucent fullscreen TaskFragment on top.
1148         return gotTranslucentFullscreen
1149                 ? TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT
1150                 : TASK_FRAGMENT_VISIBILITY_VISIBLE;
1151     }
1152 
hasRunningActivity(WindowContainer wc)1153     private static boolean hasRunningActivity(WindowContainer wc) {
1154         if (wc.asTaskFragment() != null) {
1155             return wc.asTaskFragment().topRunningActivity() != null;
1156         }
1157         return wc.asActivityRecord() != null && !wc.asActivityRecord().finishing;
1158     }
1159 
isTranslucent(WindowContainer wc, ActivityRecord starting)1160     private static boolean isTranslucent(WindowContainer wc, ActivityRecord starting) {
1161         if (wc.asTaskFragment() != null) {
1162             return wc.asTaskFragment().isTranslucent(starting);
1163         } else if (wc.asActivityRecord() != null) {
1164             return !wc.asActivityRecord().occludesParent();
1165         }
1166         return false;
1167     }
1168 
1169 
isTopActivityLaunchedBehind()1170     private boolean isTopActivityLaunchedBehind() {
1171         final ActivityRecord top = topRunningActivity();
1172         return top != null && top.mLaunchTaskBehind;
1173     }
1174 
updateActivityVisibilities(@ullable ActivityRecord starting, int configChanges, boolean preserveWindows, boolean notifyClients)1175     final void updateActivityVisibilities(@Nullable ActivityRecord starting, int configChanges,
1176             boolean preserveWindows, boolean notifyClients) {
1177         mTaskSupervisor.beginActivityVisibilityUpdate();
1178         try {
1179             mEnsureActivitiesVisibleHelper.process(
1180                     starting, configChanges, preserveWindows, notifyClients);
1181         } finally {
1182             mTaskSupervisor.endActivityVisibilityUpdate();
1183         }
1184     }
1185 
resumeTopActivity(ActivityRecord prev, ActivityOptions options, boolean skipPause)1186     final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,
1187             boolean skipPause) {
1188         ActivityRecord next = topRunningActivity(true /* focusableOnly */);
1189         if (next == null || !next.canResumeByCompat()) {
1190             return false;
1191         }
1192 
1193         next.delayedResume = false;
1194 
1195         if (!skipPause && !mRootWindowContainer.allPausedActivitiesComplete()) {
1196             // If we aren't skipping pause, then we have to wait for currently pausing activities.
1197             ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: some activity pausing.");
1198             return false;
1199         }
1200 
1201         final TaskDisplayArea taskDisplayArea = getDisplayArea();
1202         // If the top activity is the resumed one, nothing to do.
1203         if (mResumedActivity == next && next.isState(RESUMED)
1204                 && taskDisplayArea.allResumedActivitiesComplete()) {
1205             // Ensure the visibility gets updated before execute app transition.
1206             taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
1207                     false /* preserveWindows */, true /* notifyClients */);
1208             // Make sure we have executed any pending transitions, since there
1209             // should be nothing left to do at this point.
1210             executeAppTransition(options);
1211 
1212             // In a multi-resumed environment, like in a freeform device, the top
1213             // activity can be resumed, but it might not be the focused app.
1214             // Set focused app when top activity is resumed
1215             if (taskDisplayArea.inMultiWindowMode() && taskDisplayArea.mDisplayContent != null
1216                     && taskDisplayArea.mDisplayContent.mFocusedApp != next) {
1217                 taskDisplayArea.mDisplayContent.setFocusedApp(next);
1218             }
1219             ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity "
1220                     + "resumed %s", next);
1221             return false;
1222         }
1223 
1224         // If we are sleeping, and there is no resumed activity, and the top activity is paused,
1225         // well that is the state we want.
1226         if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) {
1227             // Make sure we have executed any pending transitions, since there
1228             // should be nothing left to do at this point.
1229             executeAppTransition(options);
1230             ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Going to sleep and"
1231                     + " all paused");
1232             return false;
1233         }
1234 
1235         // Make sure that the user who owns this activity is started.  If not,
1236         // we will just leave it as is because someone should be bringing
1237         // another user's activities to the top of the stack.
1238         if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) {
1239             Slog.w(TAG, "Skipping resume of top activity " + next
1240                     + ": user " + next.mUserId + " is stopped");
1241             return false;
1242         }
1243 
1244         // The activity may be waiting for stop, but that is no longer
1245         // appropriate for it.
1246         mTaskSupervisor.mStoppingActivities.remove(next);
1247 
1248         if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
1249 
1250         mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid);
1251 
1252         ActivityRecord lastResumed = null;
1253         final Task lastFocusedRootTask = taskDisplayArea.getLastFocusedRootTask();
1254         if (lastFocusedRootTask != null && lastFocusedRootTask != getRootTaskFragment().asTask()) {
1255             // So, why aren't we using prev here??? See the param comment on the method. prev
1256             // doesn't represent the last resumed activity. However, the last focus stack does if
1257             // it isn't null.
1258             lastResumed = lastFocusedRootTask.getTopResumedActivity();
1259         }
1260 
1261         boolean pausing = !skipPause && taskDisplayArea.pauseBackTasks(next);
1262         if (mResumedActivity != null) {
1263             ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Pausing %s", mResumedActivity);
1264             pausing |= startPausing(mTaskSupervisor.mUserLeaving, false /* uiSleeping */,
1265                     next, "resumeTopActivity");
1266         }
1267         if (pausing) {
1268             ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: need to"
1269                     + " start pausing");
1270             // At this point we want to put the upcoming activity's process
1271             // at the top of the LRU list, since we know we will be needing it
1272             // very soon and it would be a waste to let it get killed if it
1273             // happens to be sitting towards the end.
1274             if (next.attachedToProcess()) {
1275                 next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
1276                         true /* activityChange */, false /* updateOomAdj */,
1277                         false /* addPendingTopUid */);
1278             } else if (!next.isProcessRunning()) {
1279                 // Since the start-process is asynchronous, if we already know the process of next
1280                 // activity isn't running, we can start the process earlier to save the time to wait
1281                 // for the current activity to be paused.
1282                 final boolean isTop = this == taskDisplayArea.getFocusedRootTask();
1283                 mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
1284                         isTop ? HostingRecord.HOSTING_TYPE_NEXT_TOP_ACTIVITY
1285                                 : HostingRecord.HOSTING_TYPE_NEXT_ACTIVITY);
1286             }
1287             if (lastResumed != null) {
1288                 lastResumed.setWillCloseOrEnterPip(true);
1289             }
1290             return true;
1291         } else if (mResumedActivity == next && next.isState(RESUMED)
1292                 && taskDisplayArea.allResumedActivitiesComplete()) {
1293             // It is possible for the activity to be resumed when we paused back stacks above if the
1294             // next activity doesn't have to wait for pause to complete.
1295             // So, nothing else to-do except:
1296             // Make sure we have executed any pending transitions, since there
1297             // should be nothing left to do at this point.
1298             executeAppTransition(options);
1299             ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity resumed "
1300                     + "(dontWaitForPause) %s", next);
1301             return true;
1302         }
1303 
1304         // If the most recent activity was noHistory but was only stopped rather
1305         // than stopped+finished because the device went to sleep, we need to make
1306         // sure to finish it as we're making a new activity topmost.
1307         if (shouldSleepActivities()) {
1308             mTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next);
1309         }
1310 
1311         if (prev != null && prev != next && next.nowVisible) {
1312             // The next activity is already visible, so hide the previous
1313             // activity's windows right now so we can show the new one ASAP.
1314             // We only do this if the previous is finishing, which should mean
1315             // it is on top of the one being resumed so hiding it quickly
1316             // is good.  Otherwise, we want to do the normal route of allowing
1317             // the resumed activity to be shown so we can decide if the
1318             // previous should actually be hidden depending on whether the
1319             // new one is found to be full-screen or not.
1320             if (prev.finishing) {
1321                 prev.setVisibility(false);
1322                 if (DEBUG_SWITCH) {
1323                     Slog.v(TAG_SWITCH, "Not waiting for visible to hide: " + prev
1324                             + ", nowVisible=" + next.nowVisible);
1325                 }
1326             } else {
1327                 if (DEBUG_SWITCH) {
1328                     Slog.v(TAG_SWITCH, "Previous already visible but still waiting to hide: " + prev
1329                             + ", nowVisible=" + next.nowVisible);
1330                 }
1331             }
1332         }
1333 
1334         // Launching this app's activity, make sure the app is no longer
1335         // considered stopped.
1336         try {
1337             mTaskSupervisor.getActivityMetricsLogger()
1338                     .notifyBeforePackageUnstopped(next.packageName);
1339             mAtmService.getPackageManager().setPackageStoppedState(
1340                     next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */
1341         } catch (RemoteException e1) {
1342         } catch (IllegalArgumentException e) {
1343             Slog.w(TAG, "Failed trying to unstop package "
1344                     + next.packageName + ": " + e);
1345         }
1346 
1347         // We are starting up the next activity, so tell the window manager
1348         // that the previous one will be hidden soon.  This way it can know
1349         // to ignore it when computing the desired screen orientation.
1350         boolean anim = true;
1351         final DisplayContent dc = taskDisplayArea.mDisplayContent;
1352         if (prev != null) {
1353             if (prev.finishing) {
1354                 if (DEBUG_TRANSITION) {
1355                     Slog.v(TAG_TRANSITION, "Prepare close transition: prev=" + prev);
1356                 }
1357                 if (mTaskSupervisor.mNoAnimActivities.contains(prev)) {
1358                     anim = false;
1359                     dc.prepareAppTransition(TRANSIT_NONE);
1360                 } else {
1361                     dc.prepareAppTransition(TRANSIT_CLOSE);
1362                 }
1363                 prev.setVisibility(false);
1364             } else {
1365                 if (DEBUG_TRANSITION) {
1366                     Slog.v(TAG_TRANSITION, "Prepare open transition: prev=" + prev);
1367                 }
1368                 if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
1369                     anim = false;
1370                     dc.prepareAppTransition(TRANSIT_NONE);
1371                 } else {
1372                     dc.prepareAppTransition(TRANSIT_OPEN,
1373                             next.mLaunchTaskBehind ? TRANSIT_FLAG_OPEN_BEHIND : 0);
1374                 }
1375             }
1376         } else {
1377             if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
1378             if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
1379                 anim = false;
1380                 dc.prepareAppTransition(TRANSIT_NONE);
1381             } else {
1382                 dc.prepareAppTransition(TRANSIT_OPEN);
1383             }
1384         }
1385 
1386         if (anim) {
1387             next.applyOptionsAnimation();
1388         } else {
1389             next.abortAndClearOptionsAnimation();
1390         }
1391 
1392         mTaskSupervisor.mNoAnimActivities.clear();
1393 
1394         if (next.attachedToProcess()) {
1395             if (DEBUG_SWITCH) {
1396                 Slog.v(TAG_SWITCH, "Resume running: " + next + " stopped=" + next.mAppStopped
1397                         + " visibleRequested=" + next.isVisibleRequested());
1398             }
1399 
1400             // If the previous activity is translucent, force a visibility update of
1401             // the next activity, so that it's added to WM's opening app list, and
1402             // transition animation can be set up properly.
1403             // For example, pressing Home button with a translucent activity in focus.
1404             // Launcher is already visible in this case. If we don't add it to opening
1405             // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a
1406             // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation.
1407             final boolean lastActivityTranslucent = inMultiWindowMode()
1408                     || mLastPausedActivity != null && !mLastPausedActivity.occludesParent();
1409 
1410             // This activity is now becoming visible.
1411             if (!next.isVisibleRequested() || next.mAppStopped || lastActivityTranslucent) {
1412                 next.app.addToPendingTop();
1413                 next.setVisibility(true);
1414             }
1415 
1416             // schedule launch ticks to collect information about slow apps.
1417             next.startLaunchTickingLocked();
1418 
1419             ActivityRecord lastResumedActivity =
1420                     lastFocusedRootTask == null ? null
1421                             : lastFocusedRootTask.getTopResumedActivity();
1422             final ActivityRecord.State lastState = next.getState();
1423 
1424             mAtmService.updateCpuStats();
1425 
1426             ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (in existing)", next);
1427 
1428             next.setState(RESUMED, "resumeTopActivity");
1429 
1430             // Have the window manager re-evaluate the orientation of
1431             // the screen based on the new activity order.
1432             boolean notUpdated = true;
1433 
1434             // Activity should also be visible if set mLaunchTaskBehind to true (see
1435             // ActivityRecord#shouldBeVisibleIgnoringKeyguard()).
1436             if (shouldBeVisible(next)) {
1437                 // We have special rotation behavior when here is some active activity that
1438                 // requests specific orientation or Keyguard is locked. Make sure all activity
1439                 // visibilities are set correctly as well as the transition is updated if needed
1440                 // to get the correct rotation behavior. Otherwise the following call to update
1441                 // the orientation may cause incorrect configurations delivered to client as a
1442                 // result of invisible window resize.
1443                 // TODO: Remove this once visibilities are set correctly immediately when
1444                 // starting an activity.
1445                 notUpdated = !mRootWindowContainer.ensureVisibilityAndConfig(next, getDisplayId(),
1446                         true /* markFrozenIfConfigChanged */, false /* deferResume */);
1447             }
1448 
1449             if (notUpdated) {
1450                 // The configuration update wasn't able to keep the existing
1451                 // instance of the activity, and instead started a new one.
1452                 // We should be all done, but let's just make sure our activity
1453                 // is still at the top and schedule another run if something
1454                 // weird happened.
1455                 ActivityRecord nextNext = topRunningActivity();
1456                 ProtoLog.i(WM_DEBUG_STATES, "Activity config changed during resume: "
1457                         + "%s, new next: %s", next, nextNext);
1458                 if (nextNext != next) {
1459                     // Do over!
1460                     mTaskSupervisor.scheduleResumeTopActivities();
1461                 }
1462                 if (!next.isVisibleRequested() || next.mAppStopped) {
1463                     next.setVisibility(true);
1464                 }
1465                 next.completeResumeLocked();
1466                 return true;
1467             }
1468 
1469             try {
1470                 final ClientTransaction transaction =
1471                         ClientTransaction.obtain(next.app.getThread(), next.token);
1472                 // Deliver all pending results.
1473                 ArrayList<ResultInfo> a = next.results;
1474                 if (a != null) {
1475                     final int size = a.size();
1476                     if (!next.finishing && size > 0) {
1477                         if (DEBUG_RESULTS) {
1478                             Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a);
1479                         }
1480                         transaction.addCallback(ActivityResultItem.obtain(a));
1481                     }
1482                 }
1483 
1484                 if (next.newIntents != null) {
1485                     transaction.addCallback(
1486                             NewIntentItem.obtain(next.newIntents, true /* resume */));
1487                 }
1488 
1489                 // Well the app will no longer be stopped.
1490                 // Clear app token stopped state in window manager if needed.
1491                 next.notifyAppResumed();
1492 
1493                 EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),
1494                         next.getTask().mTaskId, next.shortComponentName);
1495 
1496                 mAtmService.getAppWarningsLocked().onResumeActivity(next);
1497                 next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState);
1498                 next.abortAndClearOptionsAnimation();
1499                 transaction.setLifecycleStateRequest(
1500                         ResumeActivityItem.obtain(next.app.getReportedProcState(),
1501                                 dc.isNextTransitionForward(), next.shouldSendCompatFakeFocus()));
1502                 mAtmService.getLifecycleManager().scheduleTransaction(transaction);
1503 
1504                 ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Resumed %s", next);
1505             } catch (Exception e) {
1506                 // Whoops, need to restart this activity!
1507                 ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: "
1508                         + "%s", lastState, next);
1509                 next.setState(lastState, "resumeTopActivityInnerLocked");
1510 
1511                 // lastResumedActivity being non-null implies there is a lastStack present.
1512                 if (lastResumedActivity != null) {
1513                     lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked");
1514                 }
1515 
1516                 Slog.i(TAG, "Restarting because process died: " + next);
1517                 if (!next.hasBeenLaunched) {
1518                     next.hasBeenLaunched = true;
1519                 } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null
1520                         && lastFocusedRootTask.isTopRootTaskInDisplayArea()) {
1521                     next.showStartingWindow(false /* taskSwitch */);
1522                 }
1523                 mTaskSupervisor.startSpecificActivity(next, true, false);
1524                 return true;
1525             }
1526 
1527             // From this point on, if something goes wrong there is no way
1528             // to recover the activity.
1529             try {
1530                 next.completeResumeLocked();
1531             } catch (Exception e) {
1532                 // If any exception gets thrown, toss away this
1533                 // activity and try the next one.
1534                 Slog.w(TAG, "Exception thrown during resume of " + next, e);
1535                 next.finishIfPossible("resume-exception", true /* oomAdj */);
1536                 return true;
1537             }
1538         } else {
1539             // Whoops, need to restart this activity!
1540             if (!next.hasBeenLaunched) {
1541                 next.hasBeenLaunched = true;
1542             } else {
1543                 if (SHOW_APP_STARTING_PREVIEW) {
1544                     next.showStartingWindow(false /* taskSwich */);
1545                 }
1546                 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
1547             }
1548             ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Restarting %s", next);
1549             mTaskSupervisor.startSpecificActivity(next, true, true);
1550         }
1551 
1552         return true;
1553     }
1554 
shouldSleepOrShutDownActivities()1555     boolean shouldSleepOrShutDownActivities() {
1556         return shouldSleepActivities() || mAtmService.mShuttingDown;
1557     }
1558 
1559     /**
1560      * Returns true if the TaskFragment should be visible.
1561      *
1562      * @param starting The currently starting activity or null if there is none.
1563      */
shouldBeVisible(ActivityRecord starting)1564     boolean shouldBeVisible(ActivityRecord starting) {
1565         return getVisibility(starting) != TASK_FRAGMENT_VISIBILITY_INVISIBLE;
1566     }
1567 
1568     /**
1569      * Returns {@code true} is the activity in this TaskFragment can be resumed.
1570      *
1571      * @param starting The currently starting activity or {@code null} if there is none.
1572      */
canBeResumed(@ullable ActivityRecord starting)1573     boolean canBeResumed(@Nullable ActivityRecord starting) {
1574         // No need to resume activity in TaskFragment that is not visible.
1575         return isTopActivityFocusable()
1576                 && getVisibility(starting) == TASK_FRAGMENT_VISIBILITY_VISIBLE;
1577     }
1578 
isFocusableAndVisible()1579     boolean isFocusableAndVisible() {
1580         return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
1581     }
1582 
startPausing(boolean uiSleeping, ActivityRecord resuming, String reason)1583     final boolean startPausing(boolean uiSleeping, ActivityRecord resuming, String reason) {
1584         return startPausing(mTaskSupervisor.mUserLeaving, uiSleeping, resuming, reason);
1585     }
1586 
1587     /**
1588      * Start pausing the currently resumed activity.  It is an error to call this if there
1589      * is already an activity being paused or there is no resumed activity.
1590      *
1591      * @param userLeaving True if this should result in an onUserLeaving to the current activity.
1592      * @param uiSleeping True if this is happening with the user interface going to sleep (the
1593      * screen turning off).
1594      * @param resuming The activity we are currently trying to resume or null if this is not being
1595      *                 called as part of resuming the top activity, so we shouldn't try to instigate
1596      *                 a resume here if not null.
1597      * @param reason The reason of pausing the activity.
1598      * @return Returns true if an activity now is in the PAUSING state, and we are waiting for
1599      * it to tell us when it is done.
1600      */
startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming, String reason)1601     boolean startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming,
1602             String reason) {
1603         if (!hasDirectChildActivities()) {
1604             return false;
1605         }
1606 
1607         ProtoLog.d(WM_DEBUG_STATES, "startPausing: taskFrag =%s " + "mResumedActivity=%s", this,
1608                 mResumedActivity);
1609 
1610         if (mPausingActivity != null) {
1611             Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
1612                     + " state=" + mPausingActivity.getState());
1613             if (!shouldSleepActivities()) {
1614                 // Avoid recursion among check for sleep and complete pause during sleeping.
1615                 // Because activity will be paused immediately after resume, just let pause
1616                 // be completed by the order of activity paused from clients.
1617                 completePause(false, resuming);
1618             }
1619         }
1620         ActivityRecord prev = mResumedActivity;
1621 
1622         if (prev == null) {
1623             if (resuming == null) {
1624                 Slog.wtf(TAG, "Trying to pause when nothing is resumed");
1625                 mRootWindowContainer.resumeFocusedTasksTopActivities();
1626             }
1627             return false;
1628         }
1629 
1630         if (prev == resuming) {
1631             Slog.wtf(TAG, "Trying to pause activity that is in process of being resumed");
1632             return false;
1633         }
1634 
1635         ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSING: %s", prev);
1636         mPausingActivity = prev;
1637         mLastPausedActivity = prev;
1638         if (!prev.finishing && prev.isNoHistory()
1639                 && !mTaskSupervisor.mNoHistoryActivities.contains(prev)) {
1640             mTaskSupervisor.mNoHistoryActivities.add(prev);
1641         }
1642         prev.setState(PAUSING, "startPausingLocked");
1643         prev.getTask().touchActiveTime();
1644 
1645         mAtmService.updateCpuStats();
1646 
1647         boolean pauseImmediately = false;
1648         boolean shouldAutoPip = false;
1649         if (resuming != null) {
1650             // We do not want to trigger auto-PiP upon launch of a translucent activity.
1651             final boolean resumingOccludesParent = resuming.occludesParent();
1652             // Resuming the new resume activity only if the previous activity can't go into Pip
1653             // since we want to give Pip activities a chance to enter Pip before resuming the
1654             // next activity.
1655             final boolean lastResumedCanPip = prev.checkEnterPictureInPictureState(
1656                     "shouldAutoPipWhilePausing", userLeaving);
1657             if (userLeaving && resumingOccludesParent && lastResumedCanPip
1658                     && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
1659                 shouldAutoPip = true;
1660             } else if (!lastResumedCanPip) {
1661                 // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
1662                 // activity to be paused.
1663                 pauseImmediately = (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
1664             } else {
1665                 // The previous activity may still enter PIP even though it did not allow auto-PIP.
1666             }
1667         }
1668 
1669         if (prev.attachedToProcess()) {
1670             if (shouldAutoPip) {
1671                 prev.mPauseSchedulePendingForPip = true;
1672                 boolean didAutoPip = mAtmService.enterPictureInPictureMode(
1673                         prev, prev.pictureInPictureArgs, false /* fromClient */);
1674                 ProtoLog.d(WM_DEBUG_STATES, "Auto-PIP allowed, entering PIP mode "
1675                         + "directly: %s, didAutoPip: %b", prev, didAutoPip);
1676             } else {
1677                 schedulePauseActivity(prev, userLeaving, pauseImmediately,
1678                         false /* autoEnteringPip */, reason);
1679             }
1680         } else {
1681             mPausingActivity = null;
1682             mLastPausedActivity = null;
1683             mTaskSupervisor.mNoHistoryActivities.remove(prev);
1684         }
1685 
1686         // If we are not going to sleep, we want to ensure the device is
1687         // awake until the next activity is started.
1688         if (!uiSleeping && !mAtmService.isSleepingOrShuttingDownLocked()) {
1689             mTaskSupervisor.acquireLaunchWakelock();
1690         }
1691 
1692         // If already entered PIP mode, no need to keep pausing.
1693         if (mPausingActivity != null) {
1694             // Have the window manager pause its key dispatching until the new
1695             // activity has started.  If we're pausing the activity just because
1696             // the screen is being turned off and the UI is sleeping, don't interrupt
1697             // key dispatch; the same activity will pick it up again on wakeup.
1698             if (!uiSleeping) {
1699                 prev.pauseKeyDispatchingLocked();
1700             } else {
1701                 ProtoLog.v(WM_DEBUG_STATES, "Key dispatch not paused for screen off");
1702             }
1703 
1704             if (pauseImmediately) {
1705                 // If the caller said they don't want to wait for the pause, then complete
1706                 // the pause now.
1707                 completePause(false, resuming);
1708                 return false;
1709 
1710             } else {
1711                 prev.schedulePauseTimeout();
1712                 // All activities will be stopped when sleeping, don't need to wait for pause.
1713                 if (!uiSleeping) {
1714                     // Unset readiness since we now need to wait until this pause is complete.
1715                     mTransitionController.setReady(this, false /* ready */);
1716                 }
1717                 return true;
1718             }
1719 
1720         } else {
1721             // This activity either failed to schedule the pause or it entered PIP mode,
1722             // so just treat it as being paused now.
1723             ProtoLog.v(WM_DEBUG_STATES, "Activity not running or entered PiP, resuming next.");
1724             if (resuming == null) {
1725                 mRootWindowContainer.resumeFocusedTasksTopActivities();
1726             }
1727             return false;
1728         }
1729     }
1730 
schedulePauseActivity(ActivityRecord prev, boolean userLeaving, boolean pauseImmediately, boolean autoEnteringPip, String reason)1731     void schedulePauseActivity(ActivityRecord prev, boolean userLeaving,
1732             boolean pauseImmediately, boolean autoEnteringPip, String reason) {
1733         ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev);
1734         try {
1735             prev.mPauseSchedulePendingForPip = false;
1736             EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
1737                     prev.shortComponentName, "userLeaving=" + userLeaving, reason);
1738 
1739             mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
1740                     prev.token, PauseActivityItem.obtain(prev.finishing, userLeaving,
1741                             prev.configChangeFlags, pauseImmediately, autoEnteringPip));
1742         } catch (Exception e) {
1743             // Ignore exception, if process died other code will cleanup.
1744             Slog.w(TAG, "Exception thrown during pause", e);
1745             mPausingActivity = null;
1746             mLastPausedActivity = null;
1747             mTaskSupervisor.mNoHistoryActivities.remove(prev);
1748         }
1749     }
1750 
1751     @VisibleForTesting
completePause(boolean resumeNext, ActivityRecord resuming)1752     void completePause(boolean resumeNext, ActivityRecord resuming) {
1753         // Complete the pausing process of a pausing activity, so it doesn't make sense to
1754         // operate on non-leaf tasks.
1755         // warnForNonLeafTask("completePauseLocked");
1756 
1757         ActivityRecord prev = mPausingActivity;
1758         ProtoLog.v(WM_DEBUG_STATES, "Complete pause: %s", prev);
1759 
1760         if (prev != null) {
1761             prev.setWillCloseOrEnterPip(false);
1762             final boolean wasStopping = prev.isState(STOPPING);
1763             prev.setState(PAUSED, "completePausedLocked");
1764             if (prev.finishing) {
1765                 // We will update the activity visibility later, no need to do in
1766                 // completeFinishing(). Updating visibility here might also making the next
1767                 // activities to be resumed, and could result in wrong app transition due to
1768                 // lack of previous activity information.
1769                 ProtoLog.v(WM_DEBUG_STATES, "Executing finish of activity: %s", prev);
1770                 prev = prev.completeFinishing(false /* updateVisibility */,
1771                         "completePausedLocked");
1772             } else if (prev.attachedToProcess()) {
1773                 ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s "
1774                                 + "wasStopping=%b visibleRequested=%b",  prev,  wasStopping,
1775                         prev.isVisibleRequested());
1776                 if (prev.deferRelaunchUntilPaused) {
1777                     // Complete the deferred relaunch that was waiting for pause to complete.
1778                     ProtoLog.v(WM_DEBUG_STATES, "Re-launching after pause: %s", prev);
1779                     prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch);
1780                 } else if (wasStopping) {
1781                     // We are also stopping, the stop request must have gone soon after the pause.
1782                     // We can't clobber it, because the stop confirmation will not be handled.
1783                     // We don't need to schedule another stop, we only need to let it happen.
1784                     prev.setState(STOPPING, "completePausedLocked");
1785                 } else if (!prev.isVisibleRequested() || shouldSleepOrShutDownActivities()) {
1786                     // Clear out any deferred client hide we might currently have.
1787                     prev.setDeferHidingClient(false);
1788                     // If we were visible then resumeTopActivities will release resources before
1789                     // stopping.
1790                     prev.addToStopping(true /* scheduleIdle */, false /* idleDelayed */,
1791                             "completePauseLocked");
1792                 }
1793             } else {
1794                 ProtoLog.v(WM_DEBUG_STATES, "App died during pause, not stopping: %s", prev);
1795                 prev = null;
1796             }
1797             // It is possible the activity was freezing the screen before it was paused.
1798             // In that case go ahead and remove the freeze this activity has on the screen
1799             // since it is no longer visible.
1800             if (prev != null) {
1801                 prev.stopFreezingScreenLocked(true /*force*/);
1802             }
1803             mPausingActivity = null;
1804         }
1805 
1806         if (resumeNext) {
1807             final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
1808             if (topRootTask != null && !topRootTask.shouldSleepOrShutDownActivities()) {
1809                 mRootWindowContainer.resumeFocusedTasksTopActivities(topRootTask, prev,
1810                         null /* targetOptions */);
1811             } else {
1812                 // checkReadyForSleep();
1813                 final ActivityRecord top =
1814                         topRootTask != null ? topRootTask.topRunningActivity() : null;
1815                 if (top == null || (prev != null && top != prev)) {
1816                     // If there are no more activities available to run, do resume anyway to start
1817                     // something. Also if the top activity on the root task is not the just paused
1818                     // activity, we need to go ahead and resume it to ensure we complete an
1819                     // in-flight app switch.
1820                     mRootWindowContainer.resumeFocusedTasksTopActivities();
1821                 }
1822             }
1823         }
1824 
1825         if (prev != null) {
1826             prev.resumeKeyDispatchingLocked();
1827         }
1828 
1829         mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
1830 
1831         // Notify when the task stack has changed, but only if visibilities changed (not just
1832         // focus). Also if there is an active root pinned task - we always want to notify it about
1833         // task stack changes, because its positioning may depend on it.
1834         if (mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause
1835                 || (getDisplayArea() != null && getDisplayArea().hasPinnedTask())) {
1836             mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
1837             mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
1838         }
1839     }
1840 
1841     @ActivityInfo.ScreenOrientation
1842     @Override
getOrientation(@ctivityInfo.ScreenOrientation int candidate)1843     int getOrientation(@ActivityInfo.ScreenOrientation int candidate) {
1844         if (shouldReportOrientationUnspecified()) {
1845             return SCREEN_ORIENTATION_UNSPECIFIED;
1846         }
1847         if (canSpecifyOrientation()) {
1848             return super.getOrientation(candidate);
1849         }
1850         return SCREEN_ORIENTATION_UNSET;
1851     }
1852 
1853     /**
1854      * Whether or not to allow this container to specify an app requested orientation.
1855      *
1856      * This is different from {@link #providesOrientation()} that
1857      * 1. The container may still provide an orientation even if it can't specify the app requested
1858      *    one, such as {@link #shouldReportOrientationUnspecified()}
1859      * 2. Even if the container can specify an app requested orientation, it may not be used by the
1860      *    parent container if it is {@link ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}.
1861      */
canSpecifyOrientation()1862     boolean canSpecifyOrientation() {
1863         final int windowingMode = getWindowingMode();
1864         final int activityType = getActivityType();
1865         return windowingMode == WINDOWING_MODE_FULLSCREEN
1866                 || activityType == ACTIVITY_TYPE_HOME
1867                 || activityType == ACTIVITY_TYPE_RECENTS
1868                 || activityType == ACTIVITY_TYPE_ASSISTANT;
1869     }
1870 
1871     /**
1872      * Whether or not the parent container should use the orientation provided by this container
1873      * even if it is {@link ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}.
1874      */
1875     @Override
providesOrientation()1876     boolean providesOrientation() {
1877         return super.providesOrientation() || shouldReportOrientationUnspecified();
1878     }
1879 
shouldReportOrientationUnspecified()1880     private boolean shouldReportOrientationUnspecified() {
1881         // Apps and their containers are not allowed to specify orientation from adjacent
1882         // TaskFragment.
1883         return getAdjacentTaskFragment() != null && isVisibleRequested();
1884     }
1885 
1886     @Override
forAllTaskFragments(Consumer<TaskFragment> callback, boolean traverseTopToBottom)1887     void forAllTaskFragments(Consumer<TaskFragment> callback, boolean traverseTopToBottom) {
1888         super.forAllTaskFragments(callback, traverseTopToBottom);
1889         callback.accept(this);
1890     }
1891 
1892     @Override
forAllLeafTaskFragments(Consumer<TaskFragment> callback, boolean traverseTopToBottom)1893     void forAllLeafTaskFragments(Consumer<TaskFragment> callback, boolean traverseTopToBottom) {
1894         final int count = mChildren.size();
1895         boolean isLeafTaskFrag = true;
1896         if (traverseTopToBottom) {
1897             for (int i = count - 1; i >= 0; --i) {
1898                 final TaskFragment child = mChildren.get(i).asTaskFragment();
1899                 if (child != null) {
1900                     isLeafTaskFrag = false;
1901                     child.forAllLeafTaskFragments(callback, traverseTopToBottom);
1902                 }
1903             }
1904         } else {
1905             for (int i = 0; i < count; i++) {
1906                 final TaskFragment child = mChildren.get(i).asTaskFragment();
1907                 if (child != null) {
1908                     isLeafTaskFrag = false;
1909                     child.forAllLeafTaskFragments(callback, traverseTopToBottom);
1910                 }
1911             }
1912         }
1913         if (isLeafTaskFrag) callback.accept(this);
1914     }
1915 
1916     @Override
forAllLeafTaskFragments(Predicate<TaskFragment> callback)1917     boolean forAllLeafTaskFragments(Predicate<TaskFragment> callback) {
1918         boolean isLeafTaskFrag = true;
1919         for (int i = mChildren.size() - 1; i >= 0; --i) {
1920             final TaskFragment child = mChildren.get(i).asTaskFragment();
1921             if (child != null) {
1922                 isLeafTaskFrag = false;
1923                 if (child.forAllLeafTaskFragments(callback)) {
1924                     return true;
1925                 }
1926             }
1927         }
1928         if (isLeafTaskFrag) {
1929             return callback.test(this);
1930         }
1931         return false;
1932     }
1933 
addChild(ActivityRecord r)1934     void addChild(ActivityRecord r) {
1935         addChild(r, POSITION_TOP);
1936     }
1937 
1938     @Override
addChild(WindowContainer child, int index)1939     void addChild(WindowContainer child, int index) {
1940         ActivityRecord r = topRunningActivity();
1941         mClearedTaskForReuse = false;
1942         mClearedTaskFragmentForPip = false;
1943         mClearedForReorderActivityToFront = false;
1944 
1945         final ActivityRecord addingActivity = child.asActivityRecord();
1946         final boolean isAddingActivity = addingActivity != null;
1947         final Task task = isAddingActivity ? getTask() : null;
1948 
1949         // If this task had any activity before we added this one.
1950         boolean taskHadActivity = task != null && task.getTopMostActivity() != null;
1951         // getActivityType() looks at the top child, so we need to read the type before adding
1952         // a new child in case the new child is on top and UNDEFINED.
1953         final int activityType = task != null ? task.getActivityType() : ACTIVITY_TYPE_UNDEFINED;
1954 
1955         super.addChild(child, index);
1956 
1957         if (isAddingActivity && task != null) {
1958             // TODO(b/207481538): temporary per-activity screenshoting
1959             if (r != null && BackNavigationController.isScreenshotEnabled()) {
1960                 ProtoLog.v(WM_DEBUG_BACK_PREVIEW, "Screenshotting Activity %s",
1961                         r.mActivityComponent.flattenToString());
1962                 Rect outBounds = r.getBounds();
1963                 ScreenCapture.ScreenshotHardwareBuffer backBuffer = ScreenCapture.captureLayers(
1964                         r.mSurfaceControl,
1965                         new Rect(0, 0, outBounds.width(), outBounds.height()),
1966                         1f);
1967                 mBackScreenshots.put(r.mActivityComponent.flattenToString(), backBuffer);
1968             }
1969             addingActivity.inHistory = true;
1970             task.onDescendantActivityAdded(taskHadActivity, activityType, addingActivity);
1971         }
1972 
1973         final WindowProcessController hostProcess = getOrganizerProcessIfDifferent(addingActivity);
1974         if (hostProcess != null) {
1975             hostProcess.addEmbeddedActivity(addingActivity);
1976         }
1977     }
1978 
1979     @Override
onChildPositionChanged(WindowContainer child)1980     void onChildPositionChanged(WindowContainer child) {
1981         super.onChildPositionChanged(child);
1982 
1983         sendTaskFragmentInfoChanged();
1984     }
1985 
executeAppTransition(ActivityOptions options)1986     void executeAppTransition(ActivityOptions options) {
1987         // No app transition applied to the task fragment.
1988     }
1989 
1990     @Override
createRemoteAnimationTarget( RemoteAnimationController.RemoteAnimationRecord record)1991     RemoteAnimationTarget createRemoteAnimationTarget(
1992             RemoteAnimationController.RemoteAnimationRecord record) {
1993         final ActivityRecord activity = record.getMode() == RemoteAnimationTarget.MODE_OPENING
1994                 // There may be a launching (e.g. trampoline or embedded) activity without a window
1995                 // on top of the existing task which is moving to front. Exclude finishing activity
1996                 // so the window of next activity can be chosen to create the animation target.
1997                 ? getActivity(r -> !r.finishing && r.hasChild())
1998                 : getTopMostActivity();
1999         return activity != null ? activity.createRemoteAnimationTarget(record) : null;
2000     }
2001 
2002     @Override
canCreateRemoteAnimationTarget()2003     boolean canCreateRemoteAnimationTarget() {
2004         return true;
2005     }
2006 
shouldSleepActivities()2007     boolean shouldSleepActivities() {
2008         final Task task = getRootTask();
2009         return task != null && task.shouldSleepActivities();
2010     }
2011 
2012     @Override
resolveOverrideConfiguration(Configuration newParentConfig)2013     void resolveOverrideConfiguration(Configuration newParentConfig) {
2014         mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
2015         super.resolveOverrideConfiguration(newParentConfig);
2016         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
2017 
2018         if (mRelativeEmbeddedBounds != null && !mRelativeEmbeddedBounds.isEmpty()) {
2019             // For embedded TaskFragment, make sure the bounds is set based on the relative bounds.
2020             resolvedConfig.windowConfiguration.setBounds(translateRelativeBoundsToAbsoluteBounds(
2021                     mRelativeEmbeddedBounds, newParentConfig.windowConfiguration.getBounds()));
2022         }
2023         int windowingMode = resolvedConfig.windowConfiguration.getWindowingMode();
2024         final int parentWindowingMode = newParentConfig.windowConfiguration.getWindowingMode();
2025 
2026         // Resolve override windowing mode to fullscreen for home task (even on freeform
2027         // display), or split-screen if in split-screen mode.
2028         if (getActivityType() == ACTIVITY_TYPE_HOME && windowingMode == WINDOWING_MODE_UNDEFINED) {
2029             windowingMode = WINDOWING_MODE_FULLSCREEN;
2030             resolvedConfig.windowConfiguration.setWindowingMode(windowingMode);
2031         }
2032 
2033         // Do not allow tasks not support multi window to be in a multi-window mode, unless it is in
2034         // pinned windowing mode.
2035         if (!supportsMultiWindow()) {
2036             final int candidateWindowingMode =
2037                     windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : parentWindowingMode;
2038             if (WindowConfiguration.inMultiWindowMode(candidateWindowingMode)
2039                     && candidateWindowingMode != WINDOWING_MODE_PINNED) {
2040                 resolvedConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
2041             }
2042         }
2043 
2044         final Task thisTask = asTask();
2045         if (thisTask != null) {
2046             thisTask.resolveLeafTaskOnlyOverrideConfigs(newParentConfig,
2047                     mTmpBounds /* previousBounds */);
2048         }
2049         computeConfigResourceOverrides(resolvedConfig, newParentConfig);
2050     }
2051 
supportsMultiWindow()2052     boolean supportsMultiWindow() {
2053         return supportsMultiWindowInDisplayArea(getDisplayArea());
2054     }
2055 
2056     /**
2057      * @return whether this task supports multi-window if it is in the given
2058      *         {@link TaskDisplayArea}.
2059      */
supportsMultiWindowInDisplayArea(@ullable TaskDisplayArea tda)2060     boolean supportsMultiWindowInDisplayArea(@Nullable TaskDisplayArea tda) {
2061         if (!mAtmService.mSupportsMultiWindow) {
2062             return false;
2063         }
2064         if (tda == null) {
2065             return false;
2066         }
2067         final Task task = getTask();
2068         if (task == null) {
2069             return false;
2070         }
2071         if (!task.isResizeable() && !tda.supportsNonResizableMultiWindow()) {
2072             // Not support non-resizable in multi window.
2073             return false;
2074         }
2075 
2076         final ActivityRecord rootActivity = task.getRootActivity();
2077         return tda.supportsActivityMinWidthHeightMultiWindow(mMinWidth, mMinHeight,
2078                 rootActivity != null ? rootActivity.info : null);
2079     }
2080 
getTaskId()2081     private int getTaskId() {
2082         return getTask() != null ? getTask().mTaskId : INVALID_TASK_ID;
2083     }
2084 
2085     /**
2086      * Ensures all visible activities at or below the input activity have the right configuration.
2087      */
ensureVisibleActivitiesConfiguration(ActivityRecord start, boolean preserveWindow)2088     void ensureVisibleActivitiesConfiguration(ActivityRecord start, boolean preserveWindow) {
2089         mEnsureVisibleActivitiesConfigHelper.process(start, preserveWindow);
2090     }
2091 
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig)2092     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
2093             @NonNull Configuration parentConfig) {
2094         computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
2095                 null /* compatInsets */);
2096     }
2097 
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo)2098     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
2099             @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) {
2100         if (overrideDisplayInfo != null) {
2101             // Make sure the screen related configs can be computed by the provided display info.
2102             inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
2103             invalidateAppBoundsConfig(inOutConfig);
2104         }
2105         computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
2106                 null /* compatInsets */);
2107     }
2108 
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)2109     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
2110             @NonNull Configuration parentConfig,
2111             @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
2112         if (compatInsets != null) {
2113             // Make sure the app bounds can be computed by the compat insets.
2114             invalidateAppBoundsConfig(inOutConfig);
2115         }
2116         computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
2117                 compatInsets);
2118     }
2119 
2120     /**
2121      * Forces the app bounds related configuration can be computed by
2122      * {@link #computeConfigResourceOverrides(Configuration, Configuration, DisplayInfo,
2123      * ActivityRecord.CompatDisplayInsets)}.
2124      */
invalidateAppBoundsConfig(@onNull Configuration inOutConfig)2125     private static void invalidateAppBoundsConfig(@NonNull Configuration inOutConfig) {
2126         final Rect appBounds = inOutConfig.windowConfiguration.getAppBounds();
2127         if (appBounds != null) {
2128             appBounds.setEmpty();
2129         }
2130         inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
2131         inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
2132     }
2133 
2134     /**
2135      * Calculates configuration values used by the client to get resources. This should be run
2136      * using app-facing bounds (bounds unmodified by animations or transient interactions).
2137      *
2138      * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely
2139      * configuring an "inherit-bounds" window which means that all configuration settings would
2140      * just be inherited from the parent configuration.
2141      **/
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)2142     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
2143             @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
2144             @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
2145         int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
2146         if (windowingMode == WINDOWING_MODE_UNDEFINED) {
2147             windowingMode = parentConfig.windowConfiguration.getWindowingMode();
2148         }
2149 
2150         float density = inOutConfig.densityDpi;
2151         if (density == Configuration.DENSITY_DPI_UNDEFINED) {
2152             density = parentConfig.densityDpi;
2153         }
2154         density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
2155 
2156         // The bounds may have been overridden at this level. If the parent cannot cover these
2157         // bounds, the configuration is still computed according to the override bounds.
2158         final boolean insideParentBounds;
2159 
2160         final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
2161         final Rect resolvedBounds = inOutConfig.windowConfiguration.getBounds();
2162         if (resolvedBounds.isEmpty()) {
2163             mTmpFullBounds.set(parentBounds);
2164             insideParentBounds = true;
2165         } else {
2166             mTmpFullBounds.set(resolvedBounds);
2167             insideParentBounds = parentBounds.contains(resolvedBounds);
2168         }
2169 
2170         // Non-null compatibility insets means the activity prefers to keep its original size, so
2171         // out bounds doesn't need to be restricted by the parent or current display
2172         final boolean customContainerPolicy = compatInsets != null;
2173 
2174         Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
2175         if (outAppBounds == null || outAppBounds.isEmpty()) {
2176             // App-bounds hasn't been overridden, so calculate a value for it.
2177             inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds);
2178             outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
2179 
2180             if (!customContainerPolicy && windowingMode != WINDOWING_MODE_FREEFORM) {
2181                 final Rect containingAppBounds;
2182                 if (insideParentBounds) {
2183                     containingAppBounds = parentConfig.windowConfiguration.getAppBounds();
2184                 } else {
2185                     // Restrict appBounds to display non-decor rather than parent because the
2186                     // override bounds are beyond the parent. Otherwise, it won't match the
2187                     // overridden bounds.
2188                     final TaskDisplayArea displayArea = getDisplayArea();
2189                     containingAppBounds = displayArea != null
2190                             ? displayArea.getWindowConfiguration().getAppBounds() : null;
2191                 }
2192                 if (containingAppBounds != null && !containingAppBounds.isEmpty()) {
2193                     outAppBounds.intersect(containingAppBounds);
2194                 }
2195             }
2196         }
2197 
2198         if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
2199                 || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
2200             if (!customContainerPolicy && WindowConfiguration.isFloating(windowingMode)) {
2201                 mTmpNonDecorBounds.set(mTmpFullBounds);
2202                 mTmpStableBounds.set(mTmpFullBounds);
2203             } else if (!customContainerPolicy
2204                     && (overrideDisplayInfo != null || getDisplayContent() != null)) {
2205                 final DisplayInfo di = overrideDisplayInfo != null
2206                         ? overrideDisplayInfo
2207                         : getDisplayContent().getDisplayInfo();
2208 
2209                 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
2210                 // area, i.e. the screen area without the system bars.
2211                 // The non decor inset are areas that could never be removed in Honeycomb. See
2212                 // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
2213                 calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di);
2214             } else {
2215                 // Apply the given non-decor and stable insets to calculate the corresponding bounds
2216                 // for screen size of configuration.
2217                 int rotation = inOutConfig.windowConfiguration.getRotation();
2218                 if (rotation == ROTATION_UNDEFINED) {
2219                     rotation = parentConfig.windowConfiguration.getRotation();
2220                 }
2221                 if (rotation != ROTATION_UNDEFINED && customContainerPolicy) {
2222                     mTmpNonDecorBounds.set(mTmpFullBounds);
2223                     mTmpStableBounds.set(mTmpFullBounds);
2224                     compatInsets.getBoundsByRotation(mTmpBounds, rotation);
2225                     intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
2226                             compatInsets.mNonDecorInsets[rotation]);
2227                     intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
2228                             compatInsets.mStableInsets[rotation]);
2229                     outAppBounds.set(mTmpNonDecorBounds);
2230                 } else {
2231                     // Set to app bounds because it excludes decor insets.
2232                     mTmpNonDecorBounds.set(outAppBounds);
2233                     mTmpStableBounds.set(outAppBounds);
2234                 }
2235             }
2236 
2237             if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
2238                 final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density + 0.5f);
2239                 inOutConfig.screenWidthDp = (insideParentBounds && !customContainerPolicy)
2240                         ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
2241                         : overrideScreenWidthDp;
2242             }
2243             if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
2244                 final int overrideScreenHeightDp =
2245                         (int) (mTmpStableBounds.height() / density + 0.5f);
2246                 inOutConfig.screenHeightDp = (insideParentBounds && !customContainerPolicy)
2247                         ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
2248                         : overrideScreenHeightDp;
2249             }
2250 
2251             // TODO(b/238331848): Consider simplifying logic that computes smallestScreenWidthDp.
2252             if (inOutConfig.smallestScreenWidthDp
2253                     == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
2254                 // When entering to or exiting from Pip, the PipTaskOrganizer will set the
2255                 // windowing mode of the activity in the task to WINDOWING_MODE_FULLSCREEN and
2256                 // temporarily set the bounds of the task to fullscreen size for transitioning.
2257                 // It will get the wrong value if the calculation is based on this temporary
2258                 // fullscreen bounds.
2259                 // We should just inherit the value from parent for this temporary state.
2260                 final boolean inPipTransition = windowingMode == WINDOWING_MODE_PINNED
2261                         && !mTmpFullBounds.isEmpty() && mTmpFullBounds.equals(parentBounds);
2262                 if (WindowConfiguration.isFloating(windowingMode) && !inPipTransition) {
2263                     // For floating tasks, calculate the smallest width from the bounds of the
2264                     // task, because they should not be affected by insets.
2265                     inOutConfig.smallestScreenWidthDp = (int) (0.5f
2266                             + Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
2267                 } else if (windowingMode == WINDOWING_MODE_MULTI_WINDOW && mIsEmbedded
2268                         && insideParentBounds && !resolvedBounds.equals(parentBounds)) {
2269                     // For embedded TFs, the smallest width should be updated. Otherwise, inherit
2270                     // from the parent task would result in applications loaded wrong resource.
2271                     inOutConfig.smallestScreenWidthDp =
2272                             Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp);
2273                 }
2274                 // otherwise, it will just inherit
2275             }
2276         }
2277 
2278         if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
2279             inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
2280                     ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
2281         }
2282         if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
2283             // For calculating screen layout, we need to use the non-decor inset screen area for the
2284             // calculation for compatibility reasons, i.e. screen area without system bars that
2285             // could never go away in Honeycomb.
2286             int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density + 0.5f);
2287             int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density + 0.5f);
2288             // Use overrides if provided. If both overrides are provided, mTmpNonDecorBounds is
2289             // undefined so it can't be used.
2290             if (inOutConfig.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
2291                 compatScreenWidthDp = inOutConfig.screenWidthDp;
2292             }
2293             if (inOutConfig.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
2294                 compatScreenHeightDp = inOutConfig.screenHeightDp;
2295             }
2296             // Reducing the screen layout starting from its parent config.
2297             inOutConfig.screenLayout = computeScreenLayout(parentConfig.screenLayout,
2298                     compatScreenWidthDp, compatScreenHeightDp);
2299         }
2300     }
2301 
2302     /**
2303      * Gets bounds with non-decor and stable insets applied respectively.
2304      *
2305      * If bounds overhangs the display, those edges will not get insets. See
2306      * {@link #intersectWithInsetsIfFits}
2307      *
2308      * @param outNonDecorBounds where to place bounds with non-decor insets applied.
2309      * @param outStableBounds where to place bounds with stable insets applied.
2310      * @param bounds the bounds to inset.
2311      */
calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, DisplayInfo displayInfo)2312     void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds,
2313             DisplayInfo displayInfo) {
2314         outNonDecorBounds.set(bounds);
2315         outStableBounds.set(bounds);
2316         if (mDisplayContent == null) {
2317             return;
2318         }
2319         mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
2320 
2321         final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
2322         final DisplayPolicy.DecorInsets.Info info = policy.getDecorInsetsInfo(
2323                 displayInfo.rotation, displayInfo.logicalWidth, displayInfo.logicalHeight);
2324         intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, info.mNonDecorInsets);
2325         intersectWithInsetsIfFits(outStableBounds, mTmpBounds, info.mConfigInsets);
2326     }
2327 
2328     /**
2329      * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
2330      * intersectBounds on a side, then the respective side will not be intersected.
2331      *
2332      * The assumption is that if inOutBounds is initially larger than intersectBounds, then the
2333      * inset on that side is no-longer applicable. This scenario happens when a task's minimal
2334      * bounds are larger than the provided parent/display bounds.
2335      *
2336      * @param inOutBounds the bounds to intersect.
2337      * @param intersectBounds the bounds to intersect with.
2338      * @param intersectInsets insets to apply to intersectBounds before intersecting.
2339      */
intersectWithInsetsIfFits( Rect inOutBounds, Rect intersectBounds, Rect intersectInsets)2340     static void intersectWithInsetsIfFits(
2341             Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) {
2342         if (inOutBounds.right <= intersectBounds.right) {
2343             inOutBounds.right =
2344                     Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right);
2345         }
2346         if (inOutBounds.bottom <= intersectBounds.bottom) {
2347             inOutBounds.bottom =
2348                     Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom);
2349         }
2350         if (inOutBounds.left >= intersectBounds.left) {
2351             inOutBounds.left =
2352                     Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left);
2353         }
2354         if (inOutBounds.top >= intersectBounds.top) {
2355             inOutBounds.top =
2356                     Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top);
2357         }
2358     }
2359 
2360     @Override
getActivityType()2361     public int getActivityType() {
2362         final int applicationType = super.getActivityType();
2363         if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
2364             return applicationType;
2365         }
2366         final ActivityRecord activity = getTopMostActivity();
2367         return activity != null ? activity.getActivityType() : getTopChild().getActivityType();
2368     }
2369 
2370     @Override
onConfigurationChanged(Configuration newParentConfig)2371     public void onConfigurationChanged(Configuration newParentConfig) {
2372         super.onConfigurationChanged(newParentConfig);
2373         updateOrganizedTaskFragmentSurface();
2374         sendTaskFragmentInfoChanged();
2375     }
2376 
deferOrganizedTaskFragmentSurfaceUpdate()2377     void deferOrganizedTaskFragmentSurfaceUpdate() {
2378         mDelayOrganizedTaskFragmentSurfaceUpdate = true;
2379     }
2380 
continueOrganizedTaskFragmentSurfaceUpdate()2381     void continueOrganizedTaskFragmentSurfaceUpdate() {
2382         mDelayOrganizedTaskFragmentSurfaceUpdate = false;
2383         updateOrganizedTaskFragmentSurface();
2384     }
2385 
2386     /**
2387      * TaskFragmentOrganizer doesn't have access to the surface for security reasons, so we need to
2388      * update its surface on the server side if it is not collected for Shell or in pending
2389      * animation.
2390      */
updateOrganizedTaskFragmentSurface()2391     void updateOrganizedTaskFragmentSurface() {
2392         if (mDelayOrganizedTaskFragmentSurfaceUpdate || mTaskFragmentOrganizer == null) {
2393             return;
2394         }
2395         if (mTransitionController.isShellTransitionsEnabled()
2396                 && !mTransitionController.isCollecting(this)) {
2397             // TaskFragmentOrganizer doesn't have access to the surface for security reasons, so
2398             // update the surface here if it is not collected by Shell transition.
2399             updateOrganizedTaskFragmentSurfaceUnchecked();
2400         } else if (!mTransitionController.isShellTransitionsEnabled() && !isAnimating()) {
2401             // Update the surface here instead of in the organizer so that we can make sure
2402             // it can be synced with the surface freezer for legacy app transition.
2403             updateOrganizedTaskFragmentSurfaceUnchecked();
2404         }
2405     }
2406 
updateOrganizedTaskFragmentSurfaceUnchecked()2407     private void updateOrganizedTaskFragmentSurfaceUnchecked() {
2408         final SurfaceControl.Transaction t = getSyncTransaction();
2409         updateSurfacePosition(t);
2410         updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */);
2411     }
2412 
2413     /** Updates the surface size so that the sub windows cannot be shown out of bounds. */
updateOrganizedTaskFragmentSurfaceSize(SurfaceControl.Transaction t, boolean forceUpdate)2414     private void updateOrganizedTaskFragmentSurfaceSize(SurfaceControl.Transaction t,
2415             boolean forceUpdate) {
2416         if (mTaskFragmentOrganizer == null) {
2417             // We only want to update for organized TaskFragment. Task will handle itself.
2418             return;
2419         }
2420         if (mSurfaceControl == null || mSurfaceAnimator.hasLeash() || mSurfaceFreezer.hasLeash()) {
2421             return;
2422         }
2423 
2424         // If this TaskFragment is closing while resizing, crop to the starting bounds instead.
2425         final Rect bounds = isClosingWhenResizing()
2426                 ? mDisplayContent.mClosingChangingContainers.get(this)
2427                 : getBounds();
2428         final int width = bounds.width();
2429         final int height = bounds.height();
2430         if (!forceUpdate && width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
2431             return;
2432         }
2433         t.setWindowCrop(mSurfaceControl, width, height);
2434         mLastSurfaceSize.set(width, height);
2435     }
2436 
2437     @Override
onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash)2438     public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) {
2439         super.onAnimationLeashCreated(t, leash);
2440         // Reset surface bounds for animation. It will be taken care by the animation leash, and
2441         // reset again onAnimationLeashLost.
2442         if (mTaskFragmentOrganizer != null
2443                 && (mLastSurfaceSize.x != 0 || mLastSurfaceSize.y != 0)) {
2444             t.setWindowCrop(mSurfaceControl, 0, 0);
2445             final SurfaceControl.Transaction syncTransaction = getSyncTransaction();
2446             if (t != syncTransaction) {
2447                 // Avoid restoring to old window crop if the sync transaction is applied later.
2448                 syncTransaction.setWindowCrop(mSurfaceControl, 0, 0);
2449             }
2450             mLastSurfaceSize.set(0, 0);
2451         }
2452     }
2453 
2454     @Override
onAnimationLeashLost(SurfaceControl.Transaction t)2455     public void onAnimationLeashLost(SurfaceControl.Transaction t) {
2456         super.onAnimationLeashLost(t);
2457         // Update the surface bounds after animation.
2458         if (mTaskFragmentOrganizer != null) {
2459             updateOrganizedTaskFragmentSurfaceSize(t, true /* forceUpdate */);
2460         }
2461     }
2462 
2463     /**
2464      * Gets the relative bounds of this embedded TaskFragment. This should only be called on
2465      * embedded TaskFragment.
2466      */
2467     @NonNull
getRelativeEmbeddedBounds()2468     Rect getRelativeEmbeddedBounds() {
2469         if (mRelativeEmbeddedBounds == null) {
2470             throw new IllegalStateException("The TaskFragment is not embedded");
2471         }
2472         return mRelativeEmbeddedBounds;
2473     }
2474 
2475     /**
2476      * Translates the given relative bounds to screen space based on the given parent bounds.
2477      * When the relative bounds is outside of the parent bounds, it will be adjusted to fit the Task
2478      * bounds.
2479      */
translateRelativeBoundsToAbsoluteBounds(@onNull Rect relativeBounds, @NonNull Rect parentBounds)2480     Rect translateRelativeBoundsToAbsoluteBounds(@NonNull Rect relativeBounds,
2481             @NonNull Rect parentBounds) {
2482         if (relativeBounds.isEmpty()) {
2483             mTmpAbsBounds.setEmpty();
2484             return mTmpAbsBounds;
2485         }
2486         // Translate the relative bounds to absolute bounds.
2487         mTmpAbsBounds.set(relativeBounds);
2488         mTmpAbsBounds.offset(parentBounds.left, parentBounds.top);
2489 
2490         if (!isAllowedToBeEmbeddedInTrustedMode() && !parentBounds.contains(mTmpAbsBounds)) {
2491             // For untrusted embedding, we want to make sure the embedded bounds will never go
2492             // outside of the Task bounds.
2493             // We expect the organizer to update the bounds after receiving the Task bounds changed,
2494             // so skip trusted embedding to avoid unnecessary configuration change before organizer
2495             // requests a new bounds.
2496             // When the requested TaskFragment bounds is outside of Task bounds, try use the
2497             // intersection.
2498             // This can happen when the Task resized before the TaskFragmentOrganizer request.
2499             if (!mTmpAbsBounds.intersect(parentBounds)) {
2500                 // Use empty bounds to fill Task if there is no intersection.
2501                 mTmpAbsBounds.setEmpty();
2502             }
2503         }
2504         return mTmpAbsBounds;
2505     }
2506 
recomputeConfiguration()2507     void recomputeConfiguration() {
2508         onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
2509     }
2510 
2511     /**
2512      * Sets the relative bounds in parent coordinate for this embedded TaskFragment.
2513      * This will not override the requested bounds, and the actual bounds will be calculated in
2514      * {@link #resolveOverrideConfiguration}, so that it makes sure to record and use the relative
2515      * bounds that is set by the organizer until the organizer requests a new relative bounds.
2516      */
setRelativeEmbeddedBounds(@onNull Rect relativeEmbeddedBounds)2517     void setRelativeEmbeddedBounds(@NonNull Rect relativeEmbeddedBounds) {
2518         if (mRelativeEmbeddedBounds == null) {
2519             throw new IllegalStateException("The TaskFragment is not embedded");
2520         }
2521         if (mRelativeEmbeddedBounds.equals(relativeEmbeddedBounds)) {
2522             return;
2523         }
2524         mRelativeEmbeddedBounds.set(relativeEmbeddedBounds);
2525     }
2526 
2527     /**
2528      * Updates the record of relative bounds of this embedded TaskFragment, and checks whether we
2529      * should prepare a transition for the bounds change.
2530      */
shouldStartChangeTransition(@onNull Rect absStartBounds, @NonNull Rect relStartBounds)2531     boolean shouldStartChangeTransition(@NonNull Rect absStartBounds,
2532             @NonNull Rect relStartBounds) {
2533         if (mTaskFragmentOrganizer == null || !canStartChangeTransition()) {
2534             return false;
2535         }
2536 
2537         if (mTransitionController.isShellTransitionsEnabled()) {
2538             // For Shell transition, the change will be collected anyway, so only take snapshot when
2539             // the bounds are resized.
2540             final Rect endBounds = getConfiguration().windowConfiguration.getBounds();
2541             return endBounds.width() != absStartBounds.width()
2542                     || endBounds.height() != absStartBounds.height();
2543         } else {
2544             // For legacy transition, we need to trigger a change transition as long as the bounds
2545             // is changed, even if it is not resized.
2546             return !relStartBounds.equals(mRelativeEmbeddedBounds);
2547         }
2548     }
2549 
2550     @Override
canStartChangeTransition()2551     boolean canStartChangeTransition() {
2552         final Task task = getTask();
2553         // Skip change transition when the Task is drag resizing.
2554         return task != null && !task.isDragResizing() && super.canStartChangeTransition();
2555     }
2556 
2557     /**
2558      * Returns {@code true} if the starting bounds of the closing organized TaskFragment is
2559      * recorded. Otherwise, return {@code false}.
2560      */
setClosingChangingStartBoundsIfNeeded()2561     boolean setClosingChangingStartBoundsIfNeeded() {
2562         if (isOrganizedTaskFragment() && mDisplayContent != null
2563                 && mDisplayContent.mChangingContainers.remove(this)) {
2564             mDisplayContent.mClosingChangingContainers.put(
2565                     this, new Rect(mSurfaceFreezer.mFreezeBounds));
2566             return true;
2567         }
2568         return false;
2569     }
2570 
2571     @Override
isSyncFinished(BLASTSyncEngine.SyncGroup group)2572     boolean isSyncFinished(BLASTSyncEngine.SyncGroup group) {
2573         return super.isSyncFinished(group) && isReadyToTransit();
2574     }
2575 
2576     @Override
setSurfaceControl(SurfaceControl sc)2577     void setSurfaceControl(SurfaceControl sc) {
2578         super.setSurfaceControl(sc);
2579         if (mTaskFragmentOrganizer != null) {
2580             updateOrganizedTaskFragmentSurfaceUnchecked();
2581             // If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to
2582             // emit the callbacks now.
2583             sendTaskFragmentAppeared();
2584         }
2585     }
2586 
sendTaskFragmentInfoChanged()2587     void sendTaskFragmentInfoChanged() {
2588         if (mTaskFragmentOrganizer != null) {
2589             mTaskFragmentOrganizerController
2590                     .onTaskFragmentInfoChanged(mTaskFragmentOrganizer, this);
2591         }
2592     }
2593 
sendTaskFragmentParentInfoChanged()2594     void sendTaskFragmentParentInfoChanged() {
2595         final Task parentTask = getParent().asTask();
2596         if (mTaskFragmentOrganizer != null && parentTask != null) {
2597             mTaskFragmentOrganizerController
2598                     .onTaskFragmentParentInfoChanged(mTaskFragmentOrganizer, parentTask);
2599         }
2600     }
2601 
sendTaskFragmentAppeared()2602     private void sendTaskFragmentAppeared() {
2603         if (mTaskFragmentOrganizer != null) {
2604             mTaskFragmentOrganizerController.onTaskFragmentAppeared(mTaskFragmentOrganizer, this);
2605         }
2606     }
2607 
sendTaskFragmentVanished()2608     private void sendTaskFragmentVanished() {
2609         if (mTaskFragmentOrganizer != null) {
2610             mTaskFragmentOrganizerController.onTaskFragmentVanished(mTaskFragmentOrganizer, this);
2611         }
2612     }
2613 
2614     /**
2615      * Returns a {@link TaskFragmentInfo} with information from this TaskFragment. Should not be
2616      * called from {@link Task}.
2617      */
getTaskFragmentInfo()2618     TaskFragmentInfo getTaskFragmentInfo() {
2619         List<IBinder> childActivities = new ArrayList<>();
2620         List<IBinder> inRequestedTaskFragmentActivities = new ArrayList<>();
2621         for (int i = 0; i < getChildCount(); i++) {
2622             final WindowContainer<?> wc = getChildAt(i);
2623             final ActivityRecord ar = wc.asActivityRecord();
2624             if (mTaskFragmentOrganizerUid != INVALID_UID && ar != null
2625                     && ar.info.processName.equals(mTaskFragmentOrganizerProcessName)
2626                     && ar.getUid() == mTaskFragmentOrganizerUid && !ar.finishing) {
2627                 // Only includes Activities that belong to the organizer process for security.
2628                 childActivities.add(ar.token);
2629                 if (ar.mRequestedLaunchingTaskFragmentToken == mFragmentToken) {
2630                     inRequestedTaskFragmentActivities.add(ar.token);
2631                 }
2632             }
2633         }
2634         final Point positionInParent = new Point();
2635         getRelativePosition(positionInParent);
2636         return new TaskFragmentInfo(
2637                 mFragmentToken,
2638                 mRemoteToken.toWindowContainerToken(),
2639                 getConfiguration(),
2640                 getNonFinishingActivityCount(),
2641                 shouldBeVisible(null /* starting */),
2642                 childActivities,
2643                 inRequestedTaskFragmentActivities,
2644                 positionInParent,
2645                 mClearedTaskForReuse,
2646                 mClearedTaskFragmentForPip,
2647                 mClearedForReorderActivityToFront,
2648                 calculateMinDimension());
2649     }
2650 
2651     /**
2652      * Calculates the minimum dimensions that this TaskFragment can be resized.
2653      * @see TaskFragmentInfo#getMinimumWidth()
2654      * @see TaskFragmentInfo#getMinimumHeight()
2655      */
calculateMinDimension()2656     Point calculateMinDimension() {
2657         final int[] maxMinWidth = new int[1];
2658         final int[] maxMinHeight = new int[1];
2659 
2660         forAllActivities(a -> {
2661             if (a.finishing) {
2662                 return;
2663             }
2664             final Point minDimensions = a.getMinDimensions();
2665             if (minDimensions == null) {
2666                 return;
2667             }
2668             maxMinWidth[0] = Math.max(maxMinWidth[0], minDimensions.x);
2669             maxMinHeight[0] = Math.max(maxMinHeight[0], minDimensions.y);
2670         });
2671         return new Point(maxMinWidth[0], maxMinHeight[0]);
2672     }
2673 
2674     @Nullable
getFragmentToken()2675     IBinder getFragmentToken() {
2676         return mFragmentToken;
2677     }
2678 
2679     @Nullable
getTaskFragmentOrganizer()2680     ITaskFragmentOrganizer getTaskFragmentOrganizer() {
2681         return mTaskFragmentOrganizer;
2682     }
2683 
2684     @Override
isOrganized()2685     boolean isOrganized() {
2686         return mTaskFragmentOrganizer != null;
2687     }
2688 
2689     /** Whether this is an organized {@link TaskFragment} and not a {@link Task}. */
isOrganizedTaskFragment()2690     final boolean isOrganizedTaskFragment() {
2691         return mTaskFragmentOrganizer != null;
2692     }
2693 
2694     /**
2695      * Whether this is an embedded {@link TaskFragment} that does not fill the parent {@link Task}.
2696      */
isEmbeddedWithBoundsOverride()2697     boolean isEmbeddedWithBoundsOverride() {
2698         if (!mIsEmbedded) {
2699             return false;
2700         }
2701         final Task task = getTask();
2702         if (task == null) {
2703             return false;
2704         }
2705         final Rect taskBounds = task.getBounds();
2706         final Rect taskFragBounds = getBounds();
2707         return !taskBounds.equals(taskFragBounds) && taskBounds.contains(taskFragBounds);
2708     }
2709 
2710     /** Whether the Task should be visible. */
isTaskVisibleRequested()2711     boolean isTaskVisibleRequested() {
2712         final Task task = getTask();
2713         return task != null && task.isVisibleRequested();
2714     }
2715 
isReadyToTransit()2716     boolean isReadyToTransit() {
2717         // We only wait when this is organized to give the organizer a chance to update.
2718         if (!isOrganizedTaskFragment()) {
2719             return true;
2720         }
2721         // We don't want to start the transition if the organized TaskFragment is empty, unless
2722         // it is requested to be removed.
2723         if (getTopNonFinishingActivity() != null || mIsRemovalRequested) {
2724             return true;
2725         }
2726         // Organizer shouldn't change embedded TaskFragment in PiP.
2727         if (isEmbeddedTaskFragmentInPip()) {
2728             return true;
2729         }
2730         // The TaskFragment becomes empty because the last running activity enters PiP when the Task
2731         // is minimized.
2732         if (mClearedTaskFragmentForPip && !isTaskVisibleRequested()) {
2733             return true;
2734         }
2735         return false;
2736     }
2737 
2738     @Override
canCustomizeAppTransition()2739     boolean canCustomizeAppTransition() {
2740         // This is only called when the app transition is going to be played by system server. In
2741         // this case, we should allow custom app transition for fullscreen embedded TaskFragment
2742         // just like Activity.
2743         return isEmbedded() && matchParentBounds();
2744     }
2745 
2746     /** Clear {@link #mLastPausedActivity} for all {@link TaskFragment} children */
clearLastPausedActivity()2747     void clearLastPausedActivity() {
2748         forAllTaskFragments(taskFragment -> taskFragment.mLastPausedActivity = null);
2749     }
2750 
2751     /**
2752      * Sets {@link #mMinWidth} and {@link #mMinWidth} to this TaskFragment.
2753      * It is usually set from the parent {@link Task} when adding the TaskFragment to the window
2754      * hierarchy.
2755      */
setMinDimensions(int minWidth, int minHeight)2756     void setMinDimensions(int minWidth, int minHeight) {
2757         if (asTask() != null) {
2758             throw new UnsupportedOperationException("This method must not be used to Task. The "
2759                     + " minimum dimension of Task should be passed from Task constructor.");
2760         }
2761         mMinWidth = minWidth;
2762         mMinHeight = minHeight;
2763     }
2764 
2765     /**
2766      * Whether this is an embedded TaskFragment in PIP Task. We don't allow any client config
2767      * override for such TaskFragment to prevent flight with PipTaskOrganizer.
2768      */
isEmbeddedTaskFragmentInPip()2769     boolean isEmbeddedTaskFragmentInPip() {
2770         return isOrganizedTaskFragment() && getTask() != null && getTask().inPinnedWindowingMode();
2771     }
2772 
shouldRemoveSelfOnLastChildRemoval()2773     boolean shouldRemoveSelfOnLastChildRemoval() {
2774         return !mCreatedByOrganizer || mIsRemovalRequested;
2775     }
2776 
2777     @Nullable
getSnapshotForActivityRecord(@ullable ActivityRecord r)2778     HardwareBuffer getSnapshotForActivityRecord(@Nullable ActivityRecord r) {
2779         if (!BackNavigationController.isScreenshotEnabled()) {
2780             return null;
2781         }
2782         if (r != null && r.mActivityComponent != null) {
2783             ScreenCapture.ScreenshotHardwareBuffer backBuffer =
2784                     mBackScreenshots.get(r.mActivityComponent.flattenToString());
2785             return backBuffer != null ? backBuffer.getHardwareBuffer() : null;
2786         }
2787         return null;
2788     }
2789 
2790     @Override
removeChild(WindowContainer child)2791     void removeChild(WindowContainer child) {
2792         removeChild(child, true /* removeSelfIfPossible */);
2793     }
2794 
removeChild(WindowContainer child, boolean removeSelfIfPossible)2795     void removeChild(WindowContainer child, boolean removeSelfIfPossible) {
2796         super.removeChild(child);
2797         final ActivityRecord r = child.asActivityRecord();
2798         if (BackNavigationController.isScreenshotEnabled()) {
2799             //TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is
2800             // implemented
2801             if (r != null) {
2802                 mBackScreenshots.remove(r.mActivityComponent.flattenToString());
2803             }
2804         }
2805         final WindowProcessController hostProcess = getOrganizerProcessIfDifferent(r);
2806         if (hostProcess != null) {
2807             hostProcess.removeEmbeddedActivity(r);
2808         }
2809         if (removeSelfIfPossible && shouldRemoveSelfOnLastChildRemoval() && !hasChild()) {
2810             removeImmediately("removeLastChild " + child);
2811         }
2812     }
2813 
2814     /**
2815      * Requests to remove this task fragment. If it doesn't have children, it is removed
2816      * immediately. Otherwise it will be removed until all activities are destroyed.
2817      *
2818      * @param withTransition Whether to use transition animation when removing activities. Set to
2819      *                       {@code false} if this is invisible to user, e.g. display removal.
2820      */
remove(boolean withTransition, String reason)2821     void remove(boolean withTransition, String reason) {
2822         if (!hasChild()) {
2823             removeImmediately(reason);
2824             return;
2825         }
2826         mIsRemovalRequested = true;
2827         // The task order may be changed by finishIfPossible() for adjusting focus if there are
2828         // nested tasks, so add all activities into a list to avoid missed removals.
2829         final ArrayList<ActivityRecord> removingActivities = new ArrayList<>();
2830         forAllActivities((Consumer<ActivityRecord>) removingActivities::add);
2831         for (int i = removingActivities.size() - 1; i >= 0; --i) {
2832             final ActivityRecord r = removingActivities.get(i);
2833             if (withTransition && r.isVisible()) {
2834                 r.finishIfPossible(reason, false /* oomAdj */);
2835             } else {
2836                 r.destroyIfPossible(reason);
2837             }
2838         }
2839     }
2840 
setDelayLastActivityRemoval(boolean delay)2841     void setDelayLastActivityRemoval(boolean delay) {
2842         if (!mIsEmbedded) {
2843             Slog.w(TAG, "Set delaying last activity removal on a non-embedded TF.");
2844         }
2845         mDelayLastActivityRemoval = delay;
2846     }
2847 
isDelayLastActivityRemoval()2848     boolean isDelayLastActivityRemoval() {
2849         return mDelayLastActivityRemoval;
2850     }
2851 
shouldDeferRemoval()2852     boolean shouldDeferRemoval() {
2853         if (!hasChild()) {
2854             return false;
2855         }
2856         return isExitAnimationRunningSelfOrChild();
2857     }
2858 
2859     @Override
handleCompleteDeferredRemoval()2860     boolean handleCompleteDeferredRemoval() {
2861         if (shouldDeferRemoval()) {
2862             return true;
2863         }
2864         return super.handleCompleteDeferredRemoval();
2865     }
2866 
2867     /** The overridden method must call {@link #removeImmediately()} instead of super. */
removeImmediately(String reason)2868     void removeImmediately(String reason) {
2869         Slog.d(TAG, "Remove task fragment: " + reason);
2870         removeImmediately();
2871     }
2872 
2873     @Override
removeImmediately()2874     void removeImmediately() {
2875         mIsRemovalRequested = false;
2876         resetAdjacentTaskFragment();
2877         cleanUpEmbeddedTaskFragment();
2878         final boolean shouldExecuteAppTransition =
2879                 mClearedTaskFragmentForPip && isTaskVisibleRequested();
2880         super.removeImmediately();
2881         sendTaskFragmentVanished();
2882         if (shouldExecuteAppTransition && mDisplayContent != null) {
2883             // When the Task is still visible, and the TaskFragment is removed because the last
2884             // running activity is reparenting to PiP, it is possible that no activity is getting
2885             // paused or resumed (having an embedded activity in split), thus we need to relayout
2886             // and execute it explicitly.
2887             mAtmService.addWindowLayoutReasons(
2888                     ActivityTaskManagerService.LAYOUT_REASON_VISIBILITY_CHANGED);
2889             mDisplayContent.executeAppTransition();
2890         }
2891     }
2892 
2893     /** Called on remove to cleanup. */
cleanUpEmbeddedTaskFragment()2894     private void cleanUpEmbeddedTaskFragment() {
2895         if (!mIsEmbedded) {
2896             return;
2897         }
2898         mAtmService.mWindowOrganizerController.cleanUpEmbeddedTaskFragment(this);
2899         final Task task = getTask();
2900         if (task == null) {
2901             return;
2902         }
2903         task.forAllLeafTaskFragments(taskFragment -> {
2904             if (taskFragment.getCompanionTaskFragment() == this) {
2905                 taskFragment.setCompanionTaskFragment(null /* companionTaskFragment */);
2906             }
2907         }, false /* traverseTopToBottom */);
2908     }
2909 
2910     @Override
getDimmer()2911     Dimmer getDimmer() {
2912         // If the window is in an embedded TaskFragment, we want to dim at the TaskFragment.
2913         if (asTask() == null) {
2914             return mDimmer;
2915         }
2916 
2917         return super.getDimmer();
2918     }
2919 
2920     @Override
prepareSurfaces()2921     void prepareSurfaces() {
2922         if (asTask() != null) {
2923             super.prepareSurfaces();
2924             return;
2925         }
2926 
2927         mDimmer.resetDimStates();
2928         super.prepareSurfaces();
2929 
2930         final Rect dimBounds = mDimmer.getDimBounds();
2931         if (dimBounds != null) {
2932             // Bounds need to be relative, as the dim layer is a child.
2933             dimBounds.offsetTo(0 /* newLeft */, 0 /* newTop */);
2934             if (mDimmer.updateDims(getSyncTransaction())) {
2935                 scheduleAnimation();
2936             }
2937         }
2938     }
2939 
2940     @Override
fillsParent()2941     boolean fillsParent() {
2942         // From the perspective of policy, we still want to report that this task fills parent
2943         // in fullscreen windowing mode even it doesn't match parent bounds because there will be
2944         // letterbox around its real content.
2945         return getWindowingMode() == WINDOWING_MODE_FULLSCREEN || matchParentBounds();
2946     }
2947 
2948     @Override
onChildVisibleRequestedChanged(@ullable WindowContainer child)2949     protected boolean onChildVisibleRequestedChanged(@Nullable WindowContainer child) {
2950         if (!super.onChildVisibleRequestedChanged(child)) return false;
2951         // Send the info changed to update the TaskFragment visibility.
2952         sendTaskFragmentInfoChanged();
2953         return true;
2954     }
2955 
2956     @Nullable
2957     @Override
getTaskFragment(Predicate<TaskFragment> callback)2958     TaskFragment getTaskFragment(Predicate<TaskFragment> callback) {
2959         final TaskFragment taskFragment = super.getTaskFragment(callback);
2960         if (taskFragment != null) {
2961             return taskFragment;
2962         }
2963         return callback.test(this) ? this : null;
2964     }
2965 
2966     /**
2967      * Moves the passed child to front
2968      * @return whether it was actually moved (vs already being top).
2969      */
moveChildToFront(WindowContainer newTop)2970     boolean moveChildToFront(WindowContainer newTop) {
2971         int origDist = getDistanceFromTop(newTop);
2972         positionChildAt(POSITION_TOP, newTop, false /* includeParents */);
2973         return getDistanceFromTop(newTop) != origDist;
2974     }
2975 
toFullString()2976     String toFullString() {
2977         final StringBuilder sb = new StringBuilder(128);
2978         sb.append(this);
2979         sb.setLength(sb.length() - 1); // Remove tail '}'.
2980         if (mTaskFragmentOrganizerUid != INVALID_UID) {
2981             sb.append(" organizerUid=");
2982             sb.append(mTaskFragmentOrganizerUid);
2983         }
2984         if (mTaskFragmentOrganizerProcessName != null) {
2985             sb.append(" organizerProc=");
2986             sb.append(mTaskFragmentOrganizerProcessName);
2987         }
2988         if (mAdjacentTaskFragment != null) {
2989             sb.append(" adjacent=");
2990             sb.append(mAdjacentTaskFragment);
2991         }
2992         sb.append('}');
2993         return sb.toString();
2994     }
2995 
2996     @Override
toString()2997     public String toString() {
2998         return "TaskFragment{" + Integer.toHexString(System.identityHashCode(this))
2999                 + " mode=" + WindowConfiguration.windowingModeToString(getWindowingMode()) + "}";
3000     }
3001 
dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, String dumpPackage, final boolean needSep, Runnable header)3002     boolean dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll,
3003             boolean dumpClient, String dumpPackage, final boolean needSep, Runnable header) {
3004         boolean printed = false;
3005         Runnable headerPrinter = () -> {
3006             if (needSep) {
3007                 pw.println();
3008             }
3009             if (header != null) {
3010                 header.run();
3011             }
3012 
3013             dumpInner(prefix, pw, dumpAll, dumpPackage);
3014         };
3015 
3016         if (dumpPackage == null) {
3017             // If we are not filtering by package, we want to print absolutely everything,
3018             // so always print the header even if there are no tasks/activities inside.
3019             headerPrinter.run();
3020             headerPrinter = null;
3021             printed = true;
3022         }
3023 
3024         for (int i = mChildren.size() - 1; i >= 0; --i) {
3025             WindowContainer child = mChildren.get(i);
3026             if (child.asTaskFragment() != null) {
3027                 printed |= child.asTaskFragment().dump(prefix + "  ", fd, pw, dumpAll,
3028                         dumpClient, dumpPackage, needSep, headerPrinter);
3029             } else if (child.asActivityRecord() != null) {
3030                 ActivityRecord.dumpActivity(fd, pw, i, child.asActivityRecord(), prefix + "  ",
3031                         "Hist ", true, !dumpAll, dumpClient, dumpPackage, false, headerPrinter,
3032                         getTask());
3033             }
3034         }
3035 
3036         return printed;
3037     }
3038 
dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage)3039     void dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage) {
3040         pw.print(prefix); pw.print("* "); pw.println(toFullString());
3041         final Rect bounds = getRequestedOverrideBounds();
3042         if (!bounds.isEmpty()) {
3043             pw.println(prefix + "  mBounds=" + bounds);
3044         }
3045         if (mIsRemovalRequested) {
3046             pw.println(prefix + "  mIsRemovalRequested=true");
3047         }
3048         if (dumpAll) {
3049             printThisActivity(pw, mLastPausedActivity, dumpPackage, false,
3050                     prefix + "  mLastPausedActivity: ", null);
3051         }
3052     }
3053 
3054     @Override
dump(PrintWriter pw, String prefix, boolean dumpAll)3055     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
3056         super.dump(pw, prefix, dumpAll);
3057         pw.println(prefix + "bounds=" + getBounds().toShortString()
3058                 + (mIsolatedNav ? ", isolatedNav" : ""));
3059         final String doublePrefix = prefix + "  ";
3060         for (int i = mChildren.size() - 1; i >= 0; i--) {
3061             final WindowContainer<?> child = mChildren.get(i);
3062             final TaskFragment tf = child.asTaskFragment();
3063             pw.println(prefix + "* " + (tf != null ? tf.toFullString() : child));
3064             // Only dump non-activity because full activity info is already printed by
3065             // RootWindowContainer#dumpActivities.
3066             if (tf != null) {
3067                 child.dump(pw, doublePrefix, dumpAll);
3068             }
3069         }
3070     }
3071 
3072     @Override
writeIdentifierToProto(ProtoOutputStream proto, long fieldId)3073     void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
3074         final long token = proto.start(fieldId);
3075         proto.write(HASH_CODE, System.identityHashCode(this));
3076         final ActivityRecord topActivity = topRunningActivity();
3077         proto.write(USER_ID, topActivity != null ? topActivity.mUserId : USER_NULL);
3078         proto.write(TITLE, topActivity != null ? topActivity.intent.getComponent()
3079                 .flattenToShortString() : "TaskFragment");
3080         proto.end(token);
3081     }
3082 
3083     @Override
getProtoFieldId()3084     long getProtoFieldId() {
3085         return TASK_FRAGMENT;
3086     }
3087 
3088     @Override
dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel)3089     public void dumpDebug(ProtoOutputStream proto, long fieldId,
3090             @WindowTraceLogLevel int logLevel) {
3091         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
3092             return;
3093         }
3094 
3095         final long token = proto.start(fieldId);
3096 
3097         super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
3098 
3099         proto.write(DISPLAY_ID, getDisplayId());
3100         proto.write(ACTIVITY_TYPE, getActivityType());
3101         proto.write(MIN_WIDTH, mMinWidth);
3102         proto.write(MIN_HEIGHT, mMinHeight);
3103 
3104         proto.end(token);
3105     }
3106 }
3107