1 /*
2  * Copyright (C) 2011 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.ActivityManager.StackId;
20 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
21 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
22 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
23 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
24 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
25 import static android.view.Display.DEFAULT_DISPLAY;
26 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
27 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
28 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
29 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
30 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
31 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
32 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
33 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
34 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
35 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
36 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
37 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
38 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
39 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
40 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
41 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
42 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
43 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
44 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
45 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
46 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
47 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
48 import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
49 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
50 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
51 import static com.android.server.wm.WindowManagerService.logWithStack;
52 
53 import android.annotation.NonNull;
54 import android.app.Activity;
55 import android.content.res.Configuration;
56 import android.graphics.Rect;
57 import android.os.Binder;
58 import android.os.Debug;
59 import android.os.IBinder;
60 import android.os.SystemClock;
61 import android.util.Slog;
62 import android.view.IApplicationToken;
63 import android.view.SurfaceControl;
64 import android.view.WindowManager;
65 import android.view.WindowManagerPolicy.StartingSurface;
66 
67 import com.android.internal.util.ToBooleanFunction;
68 import com.android.server.input.InputApplicationHandle;
69 import com.android.server.wm.WindowManagerService.H;
70 
71 import java.io.PrintWriter;
72 import java.util.ArrayDeque;
73 import java.util.ArrayList;
74 
75 import static android.os.Build.VERSION_CODES.O;
76 
77 class AppTokenList extends ArrayList<AppWindowToken> {
78 }
79 
80 /**
81  * Version of WindowToken that is specifically for a particular application (or
82  * really activity) that is displaying windows.
83  */
84 class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener {
85     private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM;
86 
87     // Non-null only for application tokens.
88     final IApplicationToken appToken;
89 
90     @NonNull final AppWindowAnimator mAppAnimator;
91 
92     final boolean mVoiceInteraction;
93 
94     /** @see WindowContainer#fillsParent() */
95     private boolean mFillsParent;
96     boolean layoutConfigChanges;
97     boolean mShowForAllUsers;
98     int mTargetSdk;
99 
100     // Flag set while reparenting to prevent actions normally triggered by an individual parent
101     // change.
102     private boolean mReparenting;
103 
104     // True if we are current in the process of removing this app token from the display
105     private boolean mRemovingFromDisplay = false;
106 
107     // The input dispatching timeout for this application token in nanoseconds.
108     long mInputDispatchingTimeoutNanos;
109 
110     // These are used for determining when all windows associated with
111     // an activity have been drawn, so they can be made visible together
112     // at the same time.
113     // initialize so that it doesn't match mTransactionSequence which is an int.
114     private long mLastTransactionSequence = Long.MIN_VALUE;
115     private int mNumInterestingWindows;
116     private int mNumDrawnWindows;
117     boolean inPendingTransaction;
118     boolean allDrawn;
119     // Set to true when this app creates a surface while in the middle of an animation. In that
120     // case do not clear allDrawn until the animation completes.
121     boolean deferClearAllDrawn;
122 
123     /**
124      * These are to track the app's real drawing status if there were no saved surfaces.
125      * @see #updateDrawnWindowStates
126      */
127     boolean allDrawnExcludingSaved;
128     private int mNumInterestingWindowsExcludingSaved;
129     private int mNumDrawnWindowsExcludingSaved;
130 
131     // Is this window's surface needed?  This is almost like hidden, except
132     // it will sometimes be true a little earlier: when the token has
133     // been shown, but is still waiting for its app transition to execute
134     // before making its windows shown.
135     boolean hiddenRequested;
136 
137     // Have we told the window clients to hide themselves?
138     private boolean mClientHidden;
139 
140     // If true we will defer setting mClientHidden to true and reporting to the client that it is
141     // hidden.
142     boolean mDeferHidingClient;
143 
144     // Last visibility state we reported to the app token.
145     boolean reportedVisible;
146 
147     // Last drawn state we reported to the app token.
148     private boolean reportedDrawn;
149 
150     // Set to true when the token has been removed from the window mgr.
151     boolean removed;
152 
153     // Information about an application starting window if displayed.
154     StartingData startingData;
155     WindowState startingWindow;
156     StartingSurface startingSurface;
157     boolean startingDisplayed;
158     boolean startingMoved;
159     // True if the hidden state of this token was forced to false due to a transferred starting
160     // window.
161     private boolean mHiddenSetFromTransferredStartingWindow;
162     boolean firstWindowDrawn;
163     private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
164             new WindowState.UpdateReportedVisibilityResults();
165 
166     // Input application handle used by the input dispatcher.
167     final InputApplicationHandle mInputApplicationHandle;
168 
169     // TODO: Have a WindowContainer state for tracking exiting/deferred removal.
170     boolean mIsExiting;
171 
172     boolean mLaunchTaskBehind;
173     boolean mEnteringAnimation;
174 
175     private boolean mAlwaysFocusable;
176 
177     boolean mAppStopped;
178     int mRotationAnimationHint;
179     private int mPendingRelaunchCount;
180 
181     private boolean mLastContainsShowWhenLockedWindow;
182     private boolean mLastContainsDismissKeyguardWindow;
183 
184     // The bounds of this activity. Mainly used for aspect-ratio compatibility.
185     // TODO(b/36505427): Every level on WindowContainer now has bounds information, which directly
186     // affects the configuration. We should probably move this into that class.
187     private final Rect mBounds = new Rect();
188 
189     ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
190     ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
191 
192     private boolean mDisablePreviewScreenshots;
193 
194     Task mLastParent;
195 
AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, int configChanges, boolean launchTaskBehind, boolean alwaysFocusable, AppWindowContainerController controller, Configuration overrideConfig, Rect bounds)196     AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
197             DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen,
198             boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint,
199             int configChanges, boolean launchTaskBehind, boolean alwaysFocusable,
200             AppWindowContainerController controller, Configuration overrideConfig, Rect bounds) {
201         this(service, token, voiceInteraction, dc, fullscreen, overrideConfig, bounds);
202         setController(controller);
203         mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
204         mShowForAllUsers = showForAllUsers;
205         mTargetSdk = targetSdk;
206         mOrientation = orientation;
207         layoutConfigChanges = (configChanges & (CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION)) != 0;
208         mLaunchTaskBehind = launchTaskBehind;
209         mAlwaysFocusable = alwaysFocusable;
210         mRotationAnimationHint = rotationAnimationHint;
211 
212         // Application tokens start out hidden.
213         hidden = true;
214         hiddenRequested = true;
215     }
216 
AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, DisplayContent dc, boolean fillsParent, Configuration overrideConfig, Rect bounds)217     AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
218             DisplayContent dc, boolean fillsParent, Configuration overrideConfig, Rect bounds) {
219         super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc,
220                 false /* ownerCanManageAppTokens */);
221         appToken = token;
222         mVoiceInteraction = voiceInteraction;
223         mFillsParent = fillsParent;
224         mInputApplicationHandle = new InputApplicationHandle(this);
225         mAppAnimator = new AppWindowAnimator(this, service);
226         if (overrideConfig != null) {
227             onOverrideConfigurationChanged(overrideConfig);
228         }
229         if (bounds != null) {
230             mBounds.set(bounds);
231         }
232     }
233 
onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds)234     void onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds) {
235         onOverrideConfigurationChanged(overrideConfiguration);
236         if (mBounds.equals(bounds)) {
237             return;
238         }
239         // TODO(b/36505427): If bounds is in WC, then we can automatically call onResize() when set.
240         mBounds.set(bounds);
241         onResize();
242     }
243 
getBounds(Rect outBounds)244     void getBounds(Rect outBounds) {
245         outBounds.set(mBounds);
246     }
247 
hasBounds()248     boolean hasBounds() {
249         return !mBounds.isEmpty();
250     }
251 
onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator)252     void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
253         firstWindowDrawn = true;
254 
255         // We now have a good window to show, remove dead placeholders
256         removeDeadWindows();
257 
258         if (startingWindow != null) {
259             if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
260                     + win.mToken + ": first real window is shown, no animation");
261             // If this initial window is animating, stop it -- we will do an animation to reveal
262             // it from behind the starting window, so there is no need for it to also be doing its
263             // own stuff.
264             winAnimator.clearAnimation();
265             if (getController() != null) {
266                 getController().removeStartingWindow();
267             }
268         }
269         updateReportedVisibilityLocked();
270     }
271 
updateReportedVisibilityLocked()272     void updateReportedVisibilityLocked() {
273         if (appToken == null) {
274             return;
275         }
276 
277         if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this);
278         final int count = mChildren.size();
279 
280         mReportedVisibilityResults.reset();
281 
282         for (int i = 0; i < count; i++) {
283             final WindowState win = mChildren.get(i);
284             win.updateReportedVisibility(mReportedVisibilityResults);
285         }
286 
287         int numInteresting = mReportedVisibilityResults.numInteresting;
288         int numVisible = mReportedVisibilityResults.numVisible;
289         int numDrawn = mReportedVisibilityResults.numDrawn;
290         boolean nowGone = mReportedVisibilityResults.nowGone;
291 
292         boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
293         boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
294         if (!nowGone) {
295             // If the app is not yet gone, then it can only become visible/drawn.
296             if (!nowDrawn) {
297                 nowDrawn = reportedDrawn;
298             }
299             if (!nowVisible) {
300                 nowVisible = reportedVisible;
301             }
302         }
303         if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
304                 + numInteresting + " visible=" + numVisible);
305         final AppWindowContainerController controller = getController();
306         if (nowDrawn != reportedDrawn) {
307             if (nowDrawn) {
308                 if (controller != null) {
309                     controller.reportWindowsDrawn();
310                 }
311             }
312             reportedDrawn = nowDrawn;
313         }
314         if (nowVisible != reportedVisible) {
315             if (DEBUG_VISIBILITY) Slog.v(TAG,
316                     "Visibility changed in " + this + ": vis=" + nowVisible);
317             reportedVisible = nowVisible;
318             if (controller != null) {
319                 if (nowVisible) {
320                     controller.reportWindowsVisible();
321                 } else {
322                     controller.reportWindowsGone();
323                 }
324             }
325         }
326     }
327 
isClientHidden()328     boolean isClientHidden() {
329         return mClientHidden;
330     }
331 
setClientHidden(boolean hideClient)332     void setClientHidden(boolean hideClient) {
333         if (mClientHidden == hideClient || (hideClient && mDeferHidingClient)) {
334             return;
335         }
336         mClientHidden = hideClient;
337         sendAppVisibilityToClients();
338     }
339 
setVisibility(WindowManager.LayoutParams lp, boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction)340     boolean setVisibility(WindowManager.LayoutParams lp,
341             boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
342 
343         boolean delayed = false;
344         inPendingTransaction = false;
345         // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually
346         // been set by the app now.
347         mHiddenSetFromTransferredStartingWindow = false;
348         setClientHidden(!visible);
349 
350         // Allow for state changes and animation to be applied if:
351         // * token is transitioning visibility state
352         // * or the token was marked as hidden and is exiting before we had a chance to play the
353         // transition animation
354         // * or this is an opening app and windows are being replaced.
355         boolean visibilityChanged = false;
356         if (hidden == visible || (hidden && mIsExiting) || (visible && waitingForReplacement())) {
357             final AccessibilityController accessibilityController = mService.mAccessibilityController;
358             boolean changed = false;
359             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
360                     "Changing app " + this + " hidden=" + hidden + " performLayout=" + performLayout);
361 
362             boolean runningAppAnimation = false;
363 
364             if (transit != AppTransition.TRANSIT_UNSET) {
365                 if (mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
366                     mAppAnimator.setNullAnimation();
367                 }
368                 if (mService.applyAnimationLocked(this, lp, transit, visible, isVoiceInteraction)) {
369                     delayed = runningAppAnimation = true;
370                 }
371                 final WindowState window = findMainWindow();
372                 //TODO (multidisplay): Magnification is supported only for the default display.
373                 if (window != null && accessibilityController != null
374                         && getDisplayContent().getDisplayId() == DEFAULT_DISPLAY) {
375                     accessibilityController.onAppWindowTransitionLocked(window, transit);
376                 }
377                 changed = true;
378             }
379 
380             final int windowsCount = mChildren.size();
381             for (int i = 0; i < windowsCount; i++) {
382                 final WindowState win = mChildren.get(i);
383                 changed |= win.onAppVisibilityChanged(visible, runningAppAnimation);
384             }
385 
386             hidden = hiddenRequested = !visible;
387             visibilityChanged = true;
388             if (!visible) {
389                 stopFreezingScreen(true, true);
390             } else {
391                 // If we are being set visible, and the starting window is not yet displayed,
392                 // then make sure it doesn't get displayed.
393                 if (startingWindow != null && !startingWindow.isDrawnLw()) {
394                     startingWindow.mPolicyVisibility = false;
395                     startingWindow.mPolicyVisibilityAfterAnim = false;
396                 }
397 
398                 // We are becoming visible, so better freeze the screen with the windows that are
399                 // getting visible so we also wait for them.
400                 forAllWindows(mService::makeWindowFreezingScreenIfNeededLocked, true);
401             }
402 
403             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setVisibility: " + this
404                     + ": hidden=" + hidden + " hiddenRequested=" + hiddenRequested);
405 
406             if (changed) {
407                 mService.mInputMonitor.setUpdateInputWindowsNeededLw();
408                 if (performLayout) {
409                     mService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
410                             false /*updateInputWindows*/);
411                     mService.mWindowPlacerLocked.performSurfacePlacement();
412                 }
413                 mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
414             }
415         }
416 
417         if (mAppAnimator.animation != null) {
418             delayed = true;
419         }
420 
421         for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) {
422             if ((mChildren.get(i)).isWindowAnimationSet()) {
423                 delayed = true;
424             }
425         }
426 
427         if (visibilityChanged) {
428             if (visible && !delayed) {
429                 // The token was made immediately visible, there will be no entrance animation.
430                 // We need to inform the client the enter animation was finished.
431                 mEnteringAnimation = true;
432                 mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token);
433             }
434             // If we are hidden but there is no delay needed we immediately
435             // apply the Surface transaction so that the ActivityManager
436             // can have some guarantee on the Surface state
437             // following setting the visibility.
438             if (hidden && !delayed) {
439                 SurfaceControl.openTransaction();
440                 for (int i = mChildren.size() - 1; i >= 0; i--) {
441                     mChildren.get(i).mWinAnimator.hide("immediately hidden");
442                 }
443                 SurfaceControl.closeTransaction();
444             }
445 
446             if (!mService.mClosingApps.contains(this) && !mService.mOpeningApps.contains(this)) {
447                 // The token is not closing nor opening, so even if there is an animation set, that
448                 // doesn't mean that it goes through the normal app transition cycle so we have
449                 // to inform the docked controller about visibility change.
450                 // TODO(multi-display): notify docked divider on all displays where visibility was
451                 // affected.
452                 mService.getDefaultDisplayContentLocked().getDockedDividerController()
453                         .notifyAppVisibilityChanged();
454                 mService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible);
455             }
456         }
457 
458         return delayed;
459     }
460 
findMainWindow()461     WindowState findMainWindow() {
462         WindowState candidate = null;
463         int j = mChildren.size();
464         while (j > 0) {
465             j--;
466             final WindowState win = mChildren.get(j);
467             final int type = win.mAttrs.type;
468             // No need to loop through child window as base application and starting types can't be
469             // child windows.
470             if (type == TYPE_BASE_APPLICATION || type == TYPE_APPLICATION_STARTING) {
471                 // In cases where there are multiple windows, we prefer the non-exiting window. This
472                 // happens for example when replacing windows during an activity relaunch. When
473                 // constructing the animation, we want the new window, not the exiting one.
474                 if (win.mAnimatingExit) {
475                     candidate = win;
476                 } else {
477                     return win;
478                 }
479             }
480         }
481         return candidate;
482     }
483 
windowsAreFocusable()484     boolean windowsAreFocusable() {
485         return StackId.canReceiveKeys(getTask().mStack.mStackId) || mAlwaysFocusable;
486     }
487 
getController()488     AppWindowContainerController getController() {
489         final WindowContainerController controller = super.getController();
490         return controller != null ? (AppWindowContainerController) controller : null;
491     }
492 
493     @Override
isVisible()494     boolean isVisible() {
495         // If the app token isn't hidden then it is considered visible and there is no need to check
496         // its children windows to see if they are visible.
497         return !hidden;
498     }
499 
500     @Override
removeImmediately()501     void removeImmediately() {
502         onRemovedFromDisplay();
503         super.removeImmediately();
504     }
505 
506     @Override
removeIfPossible()507     void removeIfPossible() {
508         mIsExiting = false;
509         removeAllWindowsIfPossible();
510         removeImmediately();
511     }
512 
513     @Override
checkCompleteDeferredRemoval()514     boolean checkCompleteDeferredRemoval() {
515         if (mIsExiting) {
516             removeIfPossible();
517         }
518         return super.checkCompleteDeferredRemoval();
519     }
520 
onRemovedFromDisplay()521     void onRemovedFromDisplay() {
522         if (mRemovingFromDisplay) {
523             return;
524         }
525         mRemovingFromDisplay = true;
526 
527         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this);
528 
529         boolean delayed = setVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction);
530 
531         mService.mOpeningApps.remove(this);
532         mService.mUnknownAppVisibilityController.appRemovedOrHidden(this);
533         mService.mTaskSnapshotController.onAppRemoved(this);
534         waitingToShow = false;
535         if (mService.mClosingApps.contains(this)) {
536             delayed = true;
537         } else if (mService.mAppTransition.isTransitionSet()) {
538             mService.mClosingApps.add(this);
539             delayed = true;
540         }
541 
542         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app " + this + " delayed=" + delayed
543                 + " animation=" + mAppAnimator.animation + " animating=" + mAppAnimator.animating);
544 
545         if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: "
546                 + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
547 
548         if (startingData != null && getController() != null) {
549             getController().removeStartingWindow();
550         }
551 
552         // If this window was animating, then we need to ensure that the app transition notifies
553         // that animations have completed in WMS.handleAnimatingStoppedAndTransitionLocked(), so
554         // add to that list now
555         if (mAppAnimator.animating) {
556             mService.mNoAnimationNotifyOnTransitionFinished.add(token);
557         }
558 
559         final TaskStack stack = getStack();
560         if (delayed && !isEmpty()) {
561             // set the token aside because it has an active animation to be finished
562             if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM,
563                     "removeAppToken make exiting: " + this);
564             if (stack != null) {
565                 stack.mExitingAppTokens.add(this);
566             }
567             mIsExiting = true;
568         } else {
569             // Make sure there is no animation running on this token, so any windows associated
570             // with it will be removed as soon as their animations are complete
571             mAppAnimator.clearAnimation();
572             mAppAnimator.animating = false;
573             if (stack != null) {
574                 stack.mExitingAppTokens.remove(this);
575             }
576             removeIfPossible();
577         }
578 
579         removed = true;
580         stopFreezingScreen(true, true);
581 
582         if (mService.mFocusedApp == this) {
583             if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + this);
584             mService.mFocusedApp = null;
585             mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
586             mService.mInputMonitor.setFocusedAppLw(null);
587         }
588 
589         if (!delayed) {
590             updateReportedVisibilityLocked();
591         }
592 
593         mRemovingFromDisplay = false;
594     }
595 
clearAnimatingFlags()596     void clearAnimatingFlags() {
597         boolean wallpaperMightChange = false;
598         for (int i = mChildren.size() - 1; i >= 0; i--) {
599             final WindowState win = mChildren.get(i);
600             wallpaperMightChange |= win.clearAnimatingFlags();
601         }
602         if (wallpaperMightChange) {
603             requestUpdateWallpaperIfNeeded();
604         }
605     }
606 
destroySurfaces()607     void destroySurfaces() {
608         destroySurfaces(false /*cleanupOnResume*/);
609     }
610 
611     /**
612      * Destroy surfaces which have been marked as eligible by the animator, taking care to ensure
613      * the client has finished with them.
614      *
615      * @param cleanupOnResume whether this is done when app is resumed without fully stopped. If
616      * set to true, destroy only surfaces of removed windows, and clear relevant flags of the
617      * others so that they are ready to be reused. If set to false (common case), destroy all
618      * surfaces that's eligible, if the app is already stopped.
619      */
destroySurfaces(boolean cleanupOnResume)620     private void destroySurfaces(boolean cleanupOnResume) {
621         boolean destroyedSomething = false;
622         for (int i = mChildren.size() - 1; i >= 0; i--) {
623             final WindowState win = mChildren.get(i);
624             destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped);
625         }
626         if (destroyedSomething) {
627             final DisplayContent dc = getDisplayContent();
628             dc.assignWindowLayers(true /*setLayoutNeeded*/);
629         }
630     }
631 
632     /**
633      * Notify that the app is now resumed, and it was not stopped before, perform a clean
634      * up of the surfaces
635      */
notifyAppResumed(boolean wasStopped)636     void notifyAppResumed(boolean wasStopped) {
637         if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped
638                 + " " + this);
639         mAppStopped = false;
640         if (!wasStopped) {
641             destroySurfaces(true /*cleanupOnResume*/);
642         }
643     }
644 
645     /**
646      * Notify that the app has stopped, and it is okay to destroy any surfaces which were
647      * keeping alive in case they were still being used.
648      */
notifyAppStopped()649     void notifyAppStopped() {
650         if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this);
651         mAppStopped = true;
652         destroySurfaces();
653         // Remove any starting window that was added for this app if they are still around.
654         if (getController() != null) {
655             getController().removeStartingWindow();
656         }
657     }
658 
659     /**
660      * Checks whether we should save surfaces for this app.
661      *
662      * @return true if the surfaces should be saved, false otherwise.
663      */
shouldSaveSurface()664     boolean shouldSaveSurface() {
665         // We want to save surface if the app's windows are "allDrawn".
666         // (If we started entering animation early with saved surfaces, allDrawn
667         // should have been restored to true. So we'll save again in that case
668         // even if app didn't actually finish drawing.)
669         return allDrawn;
670     }
671 
canRestoreSurfaces()672     private boolean canRestoreSurfaces() {
673         for (int i = mChildren.size() -1; i >= 0; i--) {
674             final WindowState w = mChildren.get(i);
675             if (w.canRestoreSurface()) {
676                 return true;
677             }
678         }
679         return false;
680     }
681 
clearWasVisibleBeforeClientHidden()682     private void clearWasVisibleBeforeClientHidden() {
683         for (int i = mChildren.size() - 1; i >= 0; i--) {
684             final WindowState w = mChildren.get(i);
685             w.clearWasVisibleBeforeClientHidden();
686         }
687     }
688 
689     /**
690      * Whether the app has some window that is invisible in layout, but
691      * animating with saved surface.
692      */
isAnimatingInvisibleWithSavedSurface()693     boolean isAnimatingInvisibleWithSavedSurface() {
694         for (int i = mChildren.size() - 1; i >= 0; i--) {
695             final WindowState w = mChildren.get(i);
696             if (w.isAnimatingInvisibleWithSavedSurface()) {
697                 return true;
698             }
699         }
700         return false;
701     }
702 
703     /**
704      * Hide all window surfaces that's still invisible in layout but animating
705      * with a saved surface, and mark them destroying.
706      */
stopUsingSavedSurfaceLocked()707     void stopUsingSavedSurfaceLocked() {
708         for (int i = mChildren.size() - 1; i >= 0; i--) {
709             final WindowState w = mChildren.get(i);
710             w.stopUsingSavedSurface();
711         }
712         destroySurfaces();
713     }
714 
markSavedSurfaceExiting()715     void markSavedSurfaceExiting() {
716         for (int i = mChildren.size() - 1; i >= 0; i--) {
717             final WindowState w = mChildren.get(i);
718             w.markSavedSurfaceExiting();
719         }
720     }
721 
restoreSavedSurfaceForInterestingWindows()722     void restoreSavedSurfaceForInterestingWindows() {
723         if (!canRestoreSurfaces()) {
724             clearWasVisibleBeforeClientHidden();
725             return;
726         }
727 
728         // Check if all interesting windows are drawn and we can mark allDrawn=true.
729         int interestingNotDrawn = -1;
730 
731         for (int i = mChildren.size() - 1; i >= 0; i--) {
732             final WindowState w = mChildren.get(i);
733             interestingNotDrawn = w.restoreSavedSurfaceForInterestingWindow();
734         }
735 
736         if (!allDrawn) {
737             allDrawn = (interestingNotDrawn == 0);
738             if (allDrawn) {
739                 mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
740             }
741         }
742         clearWasVisibleBeforeClientHidden();
743 
744         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
745                 "restoreSavedSurfaceForInterestingWindows: " + this + " allDrawn=" + allDrawn
746                 + " interestingNotDrawn=" + interestingNotDrawn);
747     }
748 
destroySavedSurfaces()749     void destroySavedSurfaces() {
750         for (int i = mChildren.size() - 1; i >= 0; i--) {
751             final WindowState win = mChildren.get(i);
752             win.destroySavedSurface();
753         }
754     }
755 
clearAllDrawn()756     void clearAllDrawn() {
757         allDrawn = false;
758         deferClearAllDrawn = false;
759         allDrawnExcludingSaved = false;
760     }
761 
getTask()762     Task getTask() {
763         return (Task) getParent();
764     }
765 
getStack()766     TaskStack getStack() {
767         final Task task = getTask();
768         if (task != null) {
769             return task.mStack;
770         } else {
771             return null;
772         }
773     }
774 
775     @Override
onParentSet()776     void onParentSet() {
777         super.onParentSet();
778 
779         final Task task = getTask();
780 
781         // When the associated task is {@code null}, the {@link AppWindowToken} can no longer
782         // access visual elements like the {@link DisplayContent}. We must remove any associations
783         // such as animations.
784         if (!mReparenting) {
785             if (task == null) {
786                 // It is possible we have been marked as a closing app earlier. We must remove ourselves
787                 // from this list so we do not participate in any future animations.
788                 mService.mClosingApps.remove(this);
789             } else if (mLastParent != null && mLastParent.mStack != null) {
790                 task.mStack.mExitingAppTokens.remove(this);
791             }
792         }
793         mLastParent = task;
794     }
795 
postWindowRemoveStartingWindowCleanup(WindowState win)796     void postWindowRemoveStartingWindowCleanup(WindowState win) {
797         // TODO: Something smells about the code below...Is there a better way?
798         if (startingWindow == win) {
799             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win);
800             if (getController() != null) {
801                 getController().removeStartingWindow();
802             }
803         } else if (mChildren.size() == 0) {
804             // If this is the last window and we had requested a starting transition window,
805             // well there is no point now.
806             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingData");
807             startingData = null;
808             if (mHiddenSetFromTransferredStartingWindow) {
809                 // We set the hidden state to false for the token from a transferred starting window.
810                 // We now reset it back to true since the starting window was the last window in the
811                 // token.
812                 hidden = true;
813             }
814         } else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) {
815             // If this is the last window except for a starting transition window,
816             // we need to get rid of the starting transition.
817             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Last window, removing starting window "
818                     + win);
819             if (getController() != null) {
820                 getController().removeStartingWindow();
821             }
822         }
823     }
824 
removeDeadWindows()825     void removeDeadWindows() {
826         for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) {
827             WindowState win = mChildren.get(winNdx);
828             if (win.mAppDied) {
829                 if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.w(TAG,
830                         "removeDeadWindows: " + win);
831                 // Set mDestroying, we don't want any animation or delayed removal here.
832                 win.mDestroying = true;
833                 // Also removes child windows.
834                 win.removeIfPossible();
835             }
836         }
837     }
838 
hasWindowsAlive()839     boolean hasWindowsAlive() {
840         for (int i = mChildren.size() - 1; i >= 0; i--) {
841             // No need to loop through child windows as the answer should be the same as that of the
842             // parent window.
843             if (!(mChildren.get(i)).mAppDied) {
844                 return true;
845             }
846         }
847         return false;
848     }
849 
setWillReplaceWindows(boolean animate)850     void setWillReplaceWindows(boolean animate) {
851         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
852                 "Marking app token " + this + " with replacing windows.");
853 
854         for (int i = mChildren.size() - 1; i >= 0; i--) {
855             final WindowState w = mChildren.get(i);
856             w.setWillReplaceWindow(animate);
857         }
858         if (animate) {
859             // Set-up dummy animation so we can start treating windows associated with this
860             // token like they are in transition before the new app window is ready for us to
861             // run the real transition animation.
862             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
863                     "setWillReplaceWindow() Setting dummy animation on: " + this);
864             mAppAnimator.setDummyAnimation();
865         }
866     }
867 
setWillReplaceChildWindows()868     void setWillReplaceChildWindows() {
869         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + this
870                 + " with replacing child windows.");
871         for (int i = mChildren.size() - 1; i >= 0; i--) {
872             final WindowState w = mChildren.get(i);
873             w.setWillReplaceChildWindows();
874         }
875     }
876 
clearWillReplaceWindows()877     void clearWillReplaceWindows() {
878         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
879                 "Resetting app token " + this + " of replacing window marks.");
880 
881         for (int i = mChildren.size() - 1; i >= 0; i--) {
882             final WindowState w = mChildren.get(i);
883             w.clearWillReplaceWindow();
884         }
885     }
886 
requestUpdateWallpaperIfNeeded()887     void requestUpdateWallpaperIfNeeded() {
888         for (int i = mChildren.size() - 1; i >= 0; i--) {
889             final WindowState w = mChildren.get(i);
890             w.requestUpdateWallpaperIfNeeded();
891         }
892     }
893 
isRelaunching()894     boolean isRelaunching() {
895         return mPendingRelaunchCount > 0;
896     }
897 
shouldFreezeBounds()898     boolean shouldFreezeBounds() {
899         final Task task = getTask();
900 
901         // For freeform windows, we can't freeze the bounds at the moment because this would make
902         // the resizing unresponsive.
903         if (task == null || task.inFreeformWorkspace()) {
904             return false;
905         }
906 
907         // We freeze the bounds while drag resizing to deal with the time between
908         // the divider/drag handle being released, and the handling it's new
909         // configuration. If we are relaunched outside of the drag resizing state,
910         // we need to be careful not to do this.
911         return getTask().isDragResizing();
912     }
913 
startRelaunching()914     void startRelaunching() {
915         if (shouldFreezeBounds()) {
916             freezeBounds();
917         }
918 
919         // In the process of tearing down before relaunching, the app will
920         // try and clean up it's child surfaces. We need to prevent this from
921         // happening, so we sever the children, transfering their ownership
922         // from the client it-self to the parent surface (owned by us).
923         for (int i = mChildren.size() - 1; i >= 0; i--) {
924             final WindowState w = mChildren.get(i);
925             w.mWinAnimator.detachChildren();
926         }
927 
928         mPendingRelaunchCount++;
929     }
930 
finishRelaunching()931     void finishRelaunching() {
932         unfreezeBounds();
933 
934         if (mPendingRelaunchCount > 0) {
935             mPendingRelaunchCount--;
936         } else {
937             // Update keyguard flags upon finishing relaunch.
938             checkKeyguardFlagsChanged();
939         }
940 
941         updateAllDrawn();
942     }
943 
clearRelaunching()944     void clearRelaunching() {
945         if (mPendingRelaunchCount == 0) {
946             return;
947         }
948         unfreezeBounds();
949         mPendingRelaunchCount = 0;
950     }
951 
952     /**
953      * Returns true if the new child window we are adding to this token is considered greater than
954      * the existing child window in this token in terms of z-order.
955      */
956     @Override
isFirstChildWindowGreaterThanSecond(WindowState newWindow, WindowState existingWindow)957     protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
958             WindowState existingWindow) {
959         final int type1 = newWindow.mAttrs.type;
960         final int type2 = existingWindow.mAttrs.type;
961 
962         // Base application windows should be z-ordered BELOW all other windows in the app token.
963         if (type1 == TYPE_BASE_APPLICATION && type2 != TYPE_BASE_APPLICATION) {
964             return false;
965         } else if (type1 != TYPE_BASE_APPLICATION && type2 == TYPE_BASE_APPLICATION) {
966             return true;
967         }
968 
969         // Starting windows should be z-ordered ABOVE all other windows in the app token.
970         if (type1 == TYPE_APPLICATION_STARTING && type2 != TYPE_APPLICATION_STARTING) {
971             return true;
972         } else if (type1 != TYPE_APPLICATION_STARTING && type2 == TYPE_APPLICATION_STARTING) {
973             return false;
974         }
975 
976         // Otherwise the new window is greater than the existing window.
977         return true;
978     }
979 
980     @Override
addWindow(WindowState w)981     void addWindow(WindowState w) {
982         super.addWindow(w);
983 
984         boolean gotReplacementWindow = false;
985         for (int i = mChildren.size() - 1; i >= 0; i--) {
986             final WindowState candidate = mChildren.get(i);
987             gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w);
988         }
989 
990         // if we got a replacement window, reset the timeout to give drawing more time
991         if (gotReplacementWindow) {
992             mService.scheduleWindowReplacementTimeouts(this);
993         }
994         checkKeyguardFlagsChanged();
995     }
996 
997     @Override
removeChild(WindowState child)998     void removeChild(WindowState child) {
999         super.removeChild(child);
1000         checkKeyguardFlagsChanged();
1001     }
1002 
waitingForReplacement()1003     private boolean waitingForReplacement() {
1004         for (int i = mChildren.size() - 1; i >= 0; i--) {
1005             final WindowState candidate = mChildren.get(i);
1006             if (candidate.waitingForReplacement()) {
1007                 return true;
1008             }
1009         }
1010         return false;
1011     }
1012 
onWindowReplacementTimeout()1013     void onWindowReplacementTimeout() {
1014         for (int i = mChildren.size() - 1; i >= 0; --i) {
1015             (mChildren.get(i)).onWindowReplacementTimeout();
1016         }
1017     }
1018 
reparent(Task task, int position)1019     void reparent(Task task, int position) {
1020         final Task currentTask = getTask();
1021         if (task == currentTask) {
1022             throw new IllegalArgumentException(
1023                     "window token=" + this + " already child of task=" + currentTask);
1024         }
1025 
1026         if (currentTask.mStack != task.mStack) {
1027             throw new IllegalArgumentException(
1028                     "window token=" + this + " current task=" + currentTask
1029                         + " belongs to a different stack than " + task);
1030         }
1031 
1032         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "reParentWindowToken: removing window token=" + this
1033                 + " from task=" + currentTask);
1034         final DisplayContent prevDisplayContent = getDisplayContent();
1035 
1036         mReparenting = true;
1037 
1038         getParent().removeChild(this);
1039         task.addChild(this, position);
1040 
1041         mReparenting = false;
1042 
1043         // Relayout display(s).
1044         final DisplayContent displayContent = task.getDisplayContent();
1045         displayContent.setLayoutNeeded();
1046         if (prevDisplayContent != displayContent) {
1047             onDisplayChanged(displayContent);
1048             prevDisplayContent.setLayoutNeeded();
1049         }
1050     }
1051 
1052     /**
1053      * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
1054      * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
1055      * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen
1056      * with a queue.
1057      */
freezeBounds()1058     private void freezeBounds() {
1059         final Task task = getTask();
1060         mFrozenBounds.offer(new Rect(task.mPreparedFrozenBounds));
1061 
1062         if (task.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) {
1063             // We didn't call prepareFreezingBounds on the task, so use the current value.
1064             mFrozenMergedConfig.offer(new Configuration(task.getConfiguration()));
1065         } else {
1066             mFrozenMergedConfig.offer(new Configuration(task.mPreparedFrozenMergedConfig));
1067         }
1068         // Calling unset() to make it equal to Configuration.EMPTY.
1069         task.mPreparedFrozenMergedConfig.unset();
1070     }
1071 
1072     /**
1073      * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
1074      */
unfreezeBounds()1075     private void unfreezeBounds() {
1076         if (mFrozenBounds.isEmpty()) {
1077             return;
1078         }
1079         mFrozenBounds.remove();
1080         if (!mFrozenMergedConfig.isEmpty()) {
1081             mFrozenMergedConfig.remove();
1082         }
1083         for (int i = mChildren.size() - 1; i >= 0; i--) {
1084             final WindowState win = mChildren.get(i);
1085             win.onUnfreezeBounds();
1086         }
1087         mService.mWindowPlacerLocked.performSurfacePlacement();
1088     }
1089 
setAppLayoutChanges(int changes, String reason)1090     void setAppLayoutChanges(int changes, String reason) {
1091         if (!mChildren.isEmpty()) {
1092             final DisplayContent dc = getDisplayContent();
1093             dc.pendingLayoutChanges |= changes;
1094             if (DEBUG_LAYOUT_REPEATS) {
1095                 mService.mWindowPlacerLocked.debugLayoutRepeats(reason, dc.pendingLayoutChanges);
1096             }
1097         }
1098     }
1099 
removeReplacedWindowIfNeeded(WindowState replacement)1100     void removeReplacedWindowIfNeeded(WindowState replacement) {
1101         for (int i = mChildren.size() - 1; i >= 0; i--) {
1102             final WindowState win = mChildren.get(i);
1103             if (win.removeReplacedWindowIfNeeded(replacement)) {
1104                 return;
1105             }
1106         }
1107     }
1108 
startFreezingScreen()1109     void startFreezingScreen() {
1110         if (DEBUG_ORIENTATION) logWithStack(TAG, "Set freezing of " + appToken + ": hidden="
1111                 + hidden + " freezing=" + mAppAnimator.freezingScreen + " hiddenRequested="
1112                 + hiddenRequested);
1113         if (!hiddenRequested) {
1114             if (!mAppAnimator.freezingScreen) {
1115                 mAppAnimator.freezingScreen = true;
1116                 mService.registerAppFreezeListener(this);
1117                 mAppAnimator.lastFreezeDuration = 0;
1118                 mService.mAppsFreezingScreen++;
1119                 if (mService.mAppsFreezingScreen == 1) {
1120                     mService.startFreezingDisplayLocked(false, 0, 0, getDisplayContent());
1121                     mService.mH.removeMessages(H.APP_FREEZE_TIMEOUT);
1122                     mService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
1123                 }
1124             }
1125             final int count = mChildren.size();
1126             for (int i = 0; i < count; i++) {
1127                 final WindowState w = mChildren.get(i);
1128                 w.onStartFreezingScreen();
1129             }
1130         }
1131     }
1132 
stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force)1133     void stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force) {
1134         if (!mAppAnimator.freezingScreen) {
1135             return;
1136         }
1137         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + this + " force=" + force);
1138         final int count = mChildren.size();
1139         boolean unfrozeWindows = false;
1140         for (int i = 0; i < count; i++) {
1141             final WindowState w = mChildren.get(i);
1142             unfrozeWindows |= w.onStopFreezingScreen();
1143         }
1144         if (force || unfrozeWindows) {
1145             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "No longer freezing: " + this);
1146             mAppAnimator.freezingScreen = false;
1147             mService.unregisterAppFreezeListener(this);
1148             mAppAnimator.lastFreezeDuration =
1149                     (int)(SystemClock.elapsedRealtime() - mService.mDisplayFreezeTime);
1150             mService.mAppsFreezingScreen--;
1151             mService.mLastFinishedFreezeSource = this;
1152         }
1153         if (unfreezeSurfaceNow) {
1154             if (unfrozeWindows) {
1155                 mService.mWindowPlacerLocked.performSurfacePlacement();
1156             }
1157             mService.stopFreezingDisplayLocked();
1158         }
1159     }
1160 
1161     @Override
onAppFreezeTimeout()1162     public void onAppFreezeTimeout() {
1163         Slog.w(TAG_WM, "Force clearing freeze: " + this);
1164         stopFreezingScreen(true, true);
1165     }
1166 
transferStartingWindow(IBinder transferFrom)1167     boolean transferStartingWindow(IBinder transferFrom) {
1168         final AppWindowToken fromToken = getDisplayContent().getAppWindowToken(transferFrom);
1169         if (fromToken == null) {
1170             return false;
1171         }
1172 
1173         final WindowState tStartingWindow = fromToken.startingWindow;
1174         if (tStartingWindow != null && fromToken.startingSurface != null) {
1175             // In this case, the starting icon has already been displayed, so start
1176             // letting windows get shown immediately without any more transitions.
1177             mService.mSkipAppTransitionAnimation = true;
1178 
1179             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Moving existing starting " + tStartingWindow
1180                     + " from " + fromToken + " to " + this);
1181 
1182             final long origId = Binder.clearCallingIdentity();
1183 
1184             // Transfer the starting window over to the new token.
1185             startingData = fromToken.startingData;
1186             startingSurface = fromToken.startingSurface;
1187             startingDisplayed = fromToken.startingDisplayed;
1188             fromToken.startingDisplayed = false;
1189             startingWindow = tStartingWindow;
1190             reportedVisible = fromToken.reportedVisible;
1191             fromToken.startingData = null;
1192             fromToken.startingSurface = null;
1193             fromToken.startingWindow = null;
1194             fromToken.startingMoved = true;
1195             tStartingWindow.mToken = this;
1196             tStartingWindow.mAppToken = this;
1197 
1198             if (DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
1199                     "Removing starting " + tStartingWindow + " from " + fromToken);
1200             fromToken.removeChild(tStartingWindow);
1201             fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow);
1202             fromToken.mHiddenSetFromTransferredStartingWindow = false;
1203             addWindow(tStartingWindow);
1204 
1205             // Propagate other interesting state between the tokens. If the old token is displayed,
1206             // we should immediately force the new one to be displayed. If it is animating, we need
1207             // to move that animation to the new one.
1208             if (fromToken.allDrawn) {
1209                 allDrawn = true;
1210                 deferClearAllDrawn = fromToken.deferClearAllDrawn;
1211             }
1212             if (fromToken.firstWindowDrawn) {
1213                 firstWindowDrawn = true;
1214             }
1215             if (!fromToken.hidden) {
1216                 hidden = false;
1217                 hiddenRequested = false;
1218                 mHiddenSetFromTransferredStartingWindow = true;
1219             }
1220             setClientHidden(fromToken.mClientHidden);
1221             fromToken.mAppAnimator.transferCurrentAnimation(
1222                     mAppAnimator, tStartingWindow.mWinAnimator);
1223 
1224             mService.updateFocusedWindowLocked(
1225                     UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
1226             getDisplayContent().setLayoutNeeded();
1227             mService.mWindowPlacerLocked.performSurfacePlacement();
1228             Binder.restoreCallingIdentity(origId);
1229             return true;
1230         } else if (fromToken.startingData != null) {
1231             // The previous app was getting ready to show a
1232             // starting window, but hasn't yet done so.  Steal it!
1233             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
1234                     "Moving pending starting from " + fromToken + " to " + this);
1235             startingData = fromToken.startingData;
1236             fromToken.startingData = null;
1237             fromToken.startingMoved = true;
1238             if (getController() != null) {
1239                 getController().scheduleAddStartingWindow();
1240             }
1241             return true;
1242         }
1243 
1244         final AppWindowAnimator tAppAnimator = fromToken.mAppAnimator;
1245         final AppWindowAnimator wAppAnimator = mAppAnimator;
1246         if (tAppAnimator.thumbnail != null) {
1247             // The old token is animating with a thumbnail, transfer that to the new token.
1248             if (wAppAnimator.thumbnail != null) {
1249                 wAppAnimator.thumbnail.destroy();
1250             }
1251             wAppAnimator.thumbnail = tAppAnimator.thumbnail;
1252             wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer;
1253             wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation;
1254             tAppAnimator.thumbnail = null;
1255         }
1256         return false;
1257     }
1258 
isLastWindow(WindowState win)1259     boolean isLastWindow(WindowState win) {
1260         return mChildren.size() == 1 && mChildren.get(0) == win;
1261     }
1262 
setAllAppWinAnimators()1263     void setAllAppWinAnimators() {
1264         final ArrayList<WindowStateAnimator> allAppWinAnimators = mAppAnimator.mAllAppWinAnimators;
1265         allAppWinAnimators.clear();
1266 
1267         final int windowsCount = mChildren.size();
1268         for (int j = 0; j < windowsCount; j++) {
1269             (mChildren.get(j)).addWinAnimatorToList(allAppWinAnimators);
1270         }
1271     }
1272 
1273     @Override
onAppTransitionDone()1274     void onAppTransitionDone() {
1275         sendingToBottom = false;
1276     }
1277 
1278     /**
1279      * We override because this class doesn't want its children affecting its reported orientation
1280      * in anyway.
1281      */
1282     @Override
getOrientation(int candidate)1283     int getOrientation(int candidate) {
1284         // We do not allow non-fullscreen apps to influence orientation beyond O. While we do
1285         // throw an exception in {@link Activity#onCreate} and
1286         // {@link Activity#setRequestedOrientation}, we also ignore the orientation here so that
1287         // other calculations aren't affected.
1288         if (!fillsParent() && mTargetSdk > O) {
1289             // Can't specify orientation if app doesn't fill parent.
1290             return SCREEN_ORIENTATION_UNSET;
1291         }
1292 
1293         if (candidate == SCREEN_ORIENTATION_BEHIND) {
1294             // Allow app to specify orientation regardless of its visibility state if the current
1295             // candidate want us to use orientation behind. I.e. the visible app on-top of this one
1296             // wants us to use the orientation of the app behind it.
1297             return mOrientation;
1298         }
1299 
1300         // The {@link AppWindowToken} should only specify an orientation when it is not closing or
1301         // going to the bottom. Allowing closing {@link AppWindowToken} to participate can lead to
1302         // an Activity in another task being started in the wrong orientation during the transition.
1303         if (!(sendingToBottom || mService.mClosingApps.contains(this))
1304                 && (isVisible() || mService.mOpeningApps.contains(this))) {
1305             return mOrientation;
1306         }
1307 
1308         return SCREEN_ORIENTATION_UNSET;
1309     }
1310 
1311     /** Returns the app's preferred orientation regardless of its currently visibility state. */
getOrientationIgnoreVisibility()1312     int getOrientationIgnoreVisibility() {
1313         return mOrientation;
1314     }
1315 
1316     @Override
checkAppWindowsReadyToShow()1317     void checkAppWindowsReadyToShow() {
1318         if (allDrawn == mAppAnimator.allDrawn) {
1319             return;
1320         }
1321 
1322         mAppAnimator.allDrawn = allDrawn;
1323         if (!allDrawn) {
1324             return;
1325         }
1326 
1327         // The token has now changed state to having all windows shown...  what to do, what to do?
1328         if (mAppAnimator.freezingScreen) {
1329             mAppAnimator.showAllWindowsLocked();
1330             stopFreezingScreen(false, true);
1331             if (DEBUG_ORIENTATION) Slog.i(TAG,
1332                     "Setting mOrientationChangeComplete=true because wtoken " + this
1333                     + " numInteresting=" + mNumInterestingWindows + " numDrawn=" + mNumDrawnWindows);
1334             // This will set mOrientationChangeComplete and cause a pass through layout.
1335             setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER,
1336                     "checkAppWindowsReadyToShow: freezingScreen");
1337         } else {
1338             setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow");
1339 
1340             // We can now show all of the drawn windows!
1341             if (!mService.mOpeningApps.contains(this)) {
1342                 mService.mAnimator.orAnimating(mAppAnimator.showAllWindowsLocked());
1343             }
1344         }
1345     }
1346 
updateAllDrawn()1347     void updateAllDrawn() {
1348         if (!allDrawn) {
1349             // Number of drawn windows can be less when a window is being relaunched, wait for
1350             // all windows to be launched and drawn for this token be considered all drawn
1351             final int numInteresting = mNumInterestingWindows;
1352             if (numInteresting > 0 && mNumDrawnWindows >= numInteresting && !isRelaunching()) {
1353                 if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawn: " + this
1354                         + " interesting=" + numInteresting + " drawn=" + mNumDrawnWindows);
1355                 allDrawn = true;
1356                 // Force an additional layout pass where
1357                 // WindowStateAnimator#commitFinishDrawingLocked() will call performShowLocked().
1358                 if (mDisplayContent != null) {
1359                     mDisplayContent.setLayoutNeeded();
1360                 }
1361                 mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
1362 
1363                 // Notify the pinned stack upon all windows drawn. If there was an animation in
1364                 // progress then this signal will resume that animation.
1365                 final TaskStack pinnedStack = mDisplayContent.getStackById(PINNED_STACK_ID);
1366                 if (pinnedStack != null) {
1367                     pinnedStack.onAllWindowsDrawn();
1368                 }
1369             }
1370         }
1371 
1372         if (!allDrawnExcludingSaved) {
1373             int numInteresting = mNumInterestingWindowsExcludingSaved;
1374             if (numInteresting > 0 && mNumDrawnWindowsExcludingSaved >= numInteresting) {
1375                 if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawnExcludingSaved: " + this
1376                         + " interesting=" + numInteresting
1377                         + " drawn=" + mNumDrawnWindowsExcludingSaved);
1378                 allDrawnExcludingSaved = true;
1379                 if (mDisplayContent != null) {
1380                     mDisplayContent.setLayoutNeeded();
1381                 }
1382                 if (isAnimatingInvisibleWithSavedSurface()
1383                         && !mService.mFinishedEarlyAnim.contains(this)) {
1384                     mService.mFinishedEarlyAnim.add(this);
1385                 }
1386             }
1387         }
1388     }
1389 
1390     /**
1391      * Updated this app token tracking states for interesting and drawn windows based on the window.
1392      *
1393      * @return Returns true if the input window is considered interesting and drawn while all the
1394      *         windows in this app token where not considered drawn as of the last pass.
1395      */
updateDrawnWindowStates(WindowState w)1396     boolean updateDrawnWindowStates(WindowState w) {
1397         if (DEBUG_STARTING_WINDOW_VERBOSE && w == startingWindow) {
1398             Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen()
1399                     + " allDrawn=" + allDrawn + " freezingScreen=" + mAppAnimator.freezingScreen);
1400         }
1401 
1402         if (allDrawn && allDrawnExcludingSaved && !mAppAnimator.freezingScreen) {
1403             return false;
1404         }
1405 
1406         if (mLastTransactionSequence != mService.mTransactionSequence) {
1407             mLastTransactionSequence = mService.mTransactionSequence;
1408             mNumInterestingWindows = mNumDrawnWindows = 0;
1409             mNumInterestingWindowsExcludingSaved = 0;
1410             mNumDrawnWindowsExcludingSaved = 0;
1411             startingDisplayed = false;
1412         }
1413 
1414         final WindowStateAnimator winAnimator = w.mWinAnimator;
1415 
1416         boolean isInterestingAndDrawn = false;
1417 
1418         if (!allDrawn && w.mightAffectAllDrawn(false /* visibleOnly */)) {
1419             if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
1420                 Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
1421                         + ", isAnimationSet=" + winAnimator.isAnimationSet());
1422                 if (!w.isDrawnLw()) {
1423                     Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
1424                             + " pv=" + w.mPolicyVisibility
1425                             + " mDrawState=" + winAnimator.drawStateToString()
1426                             + " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested
1427                             + " a=" + winAnimator.mAnimating);
1428                 }
1429             }
1430 
1431             if (w != startingWindow) {
1432                 if (w.isInteresting()) {
1433                     mNumInterestingWindows++;
1434                     if (w.isDrawnLw()) {
1435                         mNumDrawnWindows++;
1436 
1437                         if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, "tokenMayBeDrawn: "
1438                                 + this + " w=" + w + " numInteresting=" + mNumInterestingWindows
1439                                 + " freezingScreen=" + mAppAnimator.freezingScreen
1440                                 + " mAppFreezing=" + w.mAppFreezing);
1441 
1442                         isInterestingAndDrawn = true;
1443                     }
1444                 }
1445             } else if (w.isDrawnLw()) {
1446                 if (getController() != null) {
1447                     getController().reportStartingWindowDrawn();
1448                 }
1449                 startingDisplayed = true;
1450             }
1451         }
1452 
1453         if (!allDrawnExcludingSaved && w.mightAffectAllDrawn(true /* visibleOnly */)) {
1454             if (w != startingWindow && w.isInteresting()) {
1455                 mNumInterestingWindowsExcludingSaved++;
1456                 if (w.isDrawnLw() && !w.isAnimatingWithSavedSurface()) {
1457                     mNumDrawnWindowsExcludingSaved++;
1458 
1459                     if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
1460                             "tokenMayBeDrawnExcludingSaved: " + this + " w=" + w
1461                             + " numInteresting=" + mNumInterestingWindowsExcludingSaved
1462                             + " freezingScreen=" + mAppAnimator.freezingScreen
1463                             + " mAppFreezing=" + w.mAppFreezing);
1464 
1465                     isInterestingAndDrawn = true;
1466                 }
1467             }
1468         }
1469 
1470         return isInterestingAndDrawn;
1471     }
1472 
1473     @Override
stepAppWindowsAnimation(long currentTime)1474     void stepAppWindowsAnimation(long currentTime) {
1475         mAppAnimator.wasAnimating = mAppAnimator.animating;
1476         if (mAppAnimator.stepAnimationLocked(currentTime)) {
1477             mAppAnimator.animating = true;
1478             mService.mAnimator.setAnimating(true);
1479             mService.mAnimator.mAppWindowAnimating = true;
1480         } else if (mAppAnimator.wasAnimating) {
1481             // stopped animating, do one more pass through the layout
1482             setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER,
1483                     DEBUG_LAYOUT_REPEATS ? "appToken " + this + " done" : null);
1484             if (DEBUG_ANIM) Slog.v(TAG, "updateWindowsApps...: done animating " + this);
1485         }
1486     }
1487 
1488     @Override
forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom)1489     boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
1490         // For legacy reasons we process the TaskStack.mExitingAppTokens first in DisplayContent
1491         // before the non-exiting app tokens. So, we skip the exiting app tokens here.
1492         // TODO: Investigate if we need to continue to do this or if we can just process them
1493         // in-order.
1494         if (mIsExiting && !waitingForReplacement()) {
1495             return false;
1496         }
1497         return forAllWindowsUnchecked(callback, traverseTopToBottom);
1498     }
1499 
forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom)1500     boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback,
1501             boolean traverseTopToBottom) {
1502         return super.forAllWindows(callback, traverseTopToBottom);
1503     }
1504 
1505     @Override
asAppWindowToken()1506     AppWindowToken asAppWindowToken() {
1507         // I am an app window token!
1508         return this;
1509     }
1510 
1511     @Override
fillsParent()1512     boolean fillsParent() {
1513         return mFillsParent;
1514     }
1515 
setFillsParent(boolean fillsParent)1516     void setFillsParent(boolean fillsParent) {
1517         mFillsParent = fillsParent;
1518     }
1519 
containsDismissKeyguardWindow()1520     boolean containsDismissKeyguardWindow() {
1521         // Window state is transient during relaunch. We are not guaranteed to be frozen during the
1522         // entirety of the relaunch.
1523         if (isRelaunching()) {
1524             return mLastContainsDismissKeyguardWindow;
1525         }
1526 
1527         for (int i = mChildren.size() - 1; i >= 0; i--) {
1528             if ((mChildren.get(i).mAttrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
1529                 return true;
1530             }
1531         }
1532         return false;
1533     }
1534 
containsShowWhenLockedWindow()1535     boolean containsShowWhenLockedWindow() {
1536         // When we are relaunching, it is possible for us to be unfrozen before our previous
1537         // windows have been added back. Using the cached value ensures that our previous
1538         // showWhenLocked preference is honored until relaunching is complete.
1539         if (isRelaunching()) {
1540             return mLastContainsShowWhenLockedWindow;
1541         }
1542 
1543         for (int i = mChildren.size() - 1; i >= 0; i--) {
1544             if ((mChildren.get(i).mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
1545                 return true;
1546             }
1547         }
1548 
1549         return false;
1550     }
1551 
checkKeyguardFlagsChanged()1552     void checkKeyguardFlagsChanged() {
1553         final boolean containsDismissKeyguard = containsDismissKeyguardWindow();
1554         final boolean containsShowWhenLocked = containsShowWhenLockedWindow();
1555         if (containsDismissKeyguard != mLastContainsDismissKeyguardWindow
1556                 || containsShowWhenLocked != mLastContainsShowWhenLockedWindow) {
1557             mService.notifyKeyguardFlagsChanged(null /* callback */);
1558         }
1559         mLastContainsDismissKeyguardWindow = containsDismissKeyguard;
1560         mLastContainsShowWhenLockedWindow = containsShowWhenLocked;
1561     }
1562 
getImeTargetBelowWindow(WindowState w)1563     WindowState getImeTargetBelowWindow(WindowState w) {
1564         final int index = mChildren.indexOf(w);
1565         if (index > 0) {
1566             final WindowState target = mChildren.get(index - 1);
1567             if (target.canBeImeTarget()) {
1568                 return target;
1569             }
1570         }
1571         return null;
1572     }
1573 
getHighestAnimLayerWindow(WindowState currentTarget)1574     WindowState getHighestAnimLayerWindow(WindowState currentTarget) {
1575         WindowState candidate = null;
1576         for (int i = mChildren.indexOf(currentTarget); i >= 0; i--) {
1577             final WindowState w = mChildren.get(i);
1578             if (w.mRemoved) {
1579                 continue;
1580             }
1581             if (candidate == null || w.mWinAnimator.mAnimLayer >
1582                     candidate.mWinAnimator.mAnimLayer) {
1583                 candidate = w;
1584             }
1585         }
1586         return candidate;
1587     }
1588 
1589     /**
1590      * See {@link Activity#setDisablePreviewScreenshots}.
1591      */
setDisablePreviewScreenshots(boolean disable)1592     void setDisablePreviewScreenshots(boolean disable) {
1593         mDisablePreviewScreenshots = disable;
1594     }
1595 
1596     /**
1597      * Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is
1598      * the case when preview screenshots are disabled {@link #setDisablePreviewScreenshots} or when
1599      * we can't take a snapshot for other reasons, for example, if we have a secure window.
1600      *
1601      * @return True if we need to generate an app theme snapshot, false if we'd like to take a real
1602      *         screenshot.
1603      */
shouldUseAppThemeSnapshot()1604     boolean shouldUseAppThemeSnapshot() {
1605         return mDisablePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0,
1606                 true /* topToBottom */);
1607     }
1608 
1609     @Override
getAnimLayerAdjustment()1610     int getAnimLayerAdjustment() {
1611         return mAppAnimator.animLayerAdjustment;
1612     }
1613 
1614     @Override
dump(PrintWriter pw, String prefix)1615     void dump(PrintWriter pw, String prefix) {
1616         super.dump(pw, prefix);
1617         if (appToken != null) {
1618             pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction);
1619         }
1620         pw.print(prefix); pw.print("task="); pw.println(getTask());
1621         pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent);
1622                 pw.print(" mOrientation="); pw.println(mOrientation);
1623         pw.println(prefix + "hiddenRequested=" + hiddenRequested + " mClientHidden=" + mClientHidden
1624             + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
1625             + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible);
1626         if (paused) {
1627             pw.print(prefix); pw.print("paused="); pw.println(paused);
1628         }
1629         if (mAppStopped) {
1630             pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped);
1631         }
1632         if (mNumInterestingWindows != 0 || mNumDrawnWindows != 0
1633                 || allDrawn || mAppAnimator.allDrawn) {
1634             pw.print(prefix); pw.print("mNumInterestingWindows=");
1635                     pw.print(mNumInterestingWindows);
1636                     pw.print(" mNumDrawnWindows="); pw.print(mNumDrawnWindows);
1637                     pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
1638                     pw.print(" allDrawn="); pw.print(allDrawn);
1639                     pw.print(" (animator="); pw.print(mAppAnimator.allDrawn);
1640                     pw.println(")");
1641         }
1642         if (inPendingTransaction) {
1643             pw.print(prefix); pw.print("inPendingTransaction=");
1644                     pw.println(inPendingTransaction);
1645         }
1646         if (startingData != null || removed || firstWindowDrawn || mIsExiting) {
1647             pw.print(prefix); pw.print("startingData="); pw.print(startingData);
1648                     pw.print(" removed="); pw.print(removed);
1649                     pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
1650                     pw.print(" mIsExiting="); pw.println(mIsExiting);
1651         }
1652         if (startingWindow != null || startingSurface != null
1653                 || startingDisplayed || startingMoved || mHiddenSetFromTransferredStartingWindow) {
1654             pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
1655                     pw.print(" startingSurface="); pw.print(startingSurface);
1656                     pw.print(" startingDisplayed="); pw.print(startingDisplayed);
1657                     pw.print(" startingMoved="); pw.print(startingMoved);
1658                     pw.println(" mHiddenSetFromTransferredStartingWindow="
1659                             + mHiddenSetFromTransferredStartingWindow);
1660         }
1661         if (!mFrozenBounds.isEmpty()) {
1662             pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds);
1663             pw.print(prefix); pw.print("mFrozenMergedConfig="); pw.println(mFrozenMergedConfig);
1664         }
1665         if (mPendingRelaunchCount != 0) {
1666             pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
1667         }
1668         if (getController() != null) {
1669             pw.print(prefix); pw.print("controller="); pw.println(getController());
1670         }
1671         if (mRemovingFromDisplay) {
1672             pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay);
1673         }
1674     }
1675 
1676     @Override
toString()1677     public String toString() {
1678         if (stringName == null) {
1679             StringBuilder sb = new StringBuilder();
1680             sb.append("AppWindowToken{");
1681             sb.append(Integer.toHexString(System.identityHashCode(this)));
1682             sb.append(" token="); sb.append(token); sb.append('}');
1683             stringName = sb.toString();
1684         }
1685         return stringName + ((mIsExiting) ? " mIsExiting=" : "");
1686     }
1687 }
1688