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