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