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
17package com.android.server.wm;
18
19import static android.app.ActivityManager.StackId;
20import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
21import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
22import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
23import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
24import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
25import static android.view.Display.DEFAULT_DISPLAY;
26import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
27import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
28import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
29import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
30import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
31import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
32import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
33import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
34import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
35import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
36import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
37import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
38import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
39import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
40import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
41import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
42import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
43import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
44import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
45import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
46import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
47import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
48import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
49import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
50import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
51import static com.android.server.wm.WindowManagerService.logWithStack;
52
53import android.annotation.NonNull;
54import android.app.Activity;
55import android.content.res.Configuration;
56import android.graphics.Rect;
57import android.os.Binder;
58import android.os.Debug;
59import android.os.IBinder;
60import android.os.SystemClock;
61import android.util.Slog;
62import android.view.IApplicationToken;
63import android.view.SurfaceControl;
64import android.view.WindowManager;
65import android.view.WindowManagerPolicy.StartingSurface;
66
67import com.android.internal.util.ToBooleanFunction;
68import com.android.server.input.InputApplicationHandle;
69import com.android.server.wm.WindowManagerService.H;
70
71import java.io.PrintWriter;
72import java.util.ArrayDeque;
73import java.util.ArrayList;
74
75import static android.os.Build.VERSION_CODES.O;
76
77class 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 */
84class 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
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
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
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
244    void getBounds(Rect outBounds) {
245        outBounds.set(mBounds);
246    }
247
248    boolean hasBounds() {
249        return !mBounds.isEmpty();
250    }
251
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
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
328    boolean isClientHidden() {
329        return mClientHidden;
330    }
331
332    void setClientHidden(boolean hideClient) {
333        if (mClientHidden == hideClient || (hideClient && mDeferHidingClient)) {
334            return;
335        }
336        mClientHidden = hideClient;
337        sendAppVisibilityToClients();
338    }
339
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
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
484    boolean windowsAreFocusable() {
485        return StackId.canReceiveKeys(getTask().mStack.mStackId) || mAlwaysFocusable;
486    }
487
488    AppWindowContainerController getController() {
489        final WindowContainerController controller = super.getController();
490        return controller != null ? (AppWindowContainerController) controller : null;
491    }
492
493    @Override
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
501    void removeImmediately() {
502        onRemovedFromDisplay();
503        super.removeImmediately();
504    }
505
506    @Override
507    void removeIfPossible() {
508        mIsExiting = false;
509        removeAllWindowsIfPossible();
510        removeImmediately();
511    }
512
513    @Override
514    boolean checkCompleteDeferredRemoval() {
515        if (mIsExiting) {
516            removeIfPossible();
517        }
518        return super.checkCompleteDeferredRemoval();
519    }
520
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
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
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     */
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     */
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     */
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     */
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
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
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     */
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     */
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
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
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
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
756    void clearAllDrawn() {
757        allDrawn = false;
758        deferClearAllDrawn = false;
759        allDrawnExcludingSaved = false;
760    }
761
762    Task getTask() {
763        return (Task) getParent();
764    }
765
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
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
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
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
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
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
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
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
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
894    boolean isRelaunching() {
895        return mPendingRelaunchCount > 0;
896    }
897
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
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
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
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
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
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
998    void removeChild(WindowState child) {
999        super.removeChild(child);
1000        checkKeyguardFlagsChanged();
1001    }
1002
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
1013    void onWindowReplacementTimeout() {
1014        for (int i = mChildren.size() - 1; i >= 0; --i) {
1015            (mChildren.get(i)).onWindowReplacementTimeout();
1016        }
1017    }
1018
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     */
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     */
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
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
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
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
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
1162    public void onAppFreezeTimeout() {
1163        Slog.w(TAG_WM, "Force clearing freeze: " + this);
1164        stopFreezingScreen(true, true);
1165    }
1166
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
1259    boolean isLastWindow(WindowState win) {
1260        return mChildren.size() == 1 && mChildren.get(0) == win;
1261    }
1262
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
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
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. */
1312    int getOrientationIgnoreVisibility() {
1313        return mOrientation;
1314    }
1315
1316    @Override
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
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     */
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
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
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
1500    boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback,
1501            boolean traverseTopToBottom) {
1502        return super.forAllWindows(callback, traverseTopToBottom);
1503    }
1504
1505    @Override
1506    AppWindowToken asAppWindowToken() {
1507        // I am an app window token!
1508        return this;
1509    }
1510
1511    @Override
1512    boolean fillsParent() {
1513        return mFillsParent;
1514    }
1515
1516    void setFillsParent(boolean fillsParent) {
1517        mFillsParent = fillsParent;
1518    }
1519
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
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
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
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
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     */
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     */
1604    boolean shouldUseAppThemeSnapshot() {
1605        return mDisablePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0,
1606                true /* topToBottom */);
1607    }
1608
1609    @Override
1610    int getAnimLayerAdjustment() {
1611        return mAppAnimator.animLayerAdjustment;
1612    }
1613
1614    @Override
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
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