AppWindowToken.java revision 91b22809648a33d64c159e8496773b1b3b2ab6ca
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.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
21import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
22import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
23import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
24import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
25import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
26import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
27import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
28import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
29import static com.android.server.wm.WindowManagerService.WINDOW_REPLACEMENT_TIMEOUT_DURATION;
30import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
31
32import com.android.server.input.InputApplicationHandle;
33import com.android.server.wm.WindowManagerService.H;
34
35import android.annotation.NonNull;
36import android.content.pm.ActivityInfo;
37import android.content.res.Configuration;
38import android.graphics.Rect;
39import android.os.Message;
40import android.os.RemoteException;
41import android.util.Slog;
42import android.view.IApplicationToken;
43import android.view.View;
44import android.view.WindowManager;
45
46import java.io.PrintWriter;
47import java.util.ArrayDeque;
48import java.util.ArrayList;
49
50class AppTokenList extends ArrayList<AppWindowToken> {
51}
52
53/**
54 * Version of WindowToken that is specifically for a particular application (or
55 * really activity) that is displaying windows.
56 */
57class AppWindowToken extends WindowToken {
58    private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM;
59
60    // Non-null only for application tokens.
61    final IApplicationToken appToken;
62
63    // All of the windows and child windows that are included in this
64    // application token.  Note this list is NOT sorted!
65    final WindowList allAppWindows = new WindowList();
66    @NonNull final AppWindowAnimator mAppAnimator;
67
68    final boolean voiceInteraction;
69
70    Task mTask;
71    boolean appFullscreen;
72    int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
73    boolean layoutConfigChanges;
74    boolean showForAllUsers;
75    int targetSdk;
76
77    // The input dispatching timeout for this application token in nanoseconds.
78    long inputDispatchingTimeoutNanos;
79
80    // These are used for determining when all windows associated with
81    // an activity have been drawn, so they can be made visible together
82    // at the same time.
83    // initialize so that it doesn't match mTransactionSequence which is an int.
84    long lastTransactionSequence = Long.MIN_VALUE;
85    int numInterestingWindows;
86    int numDrawnWindows;
87    boolean inPendingTransaction;
88    boolean allDrawn;
89    // Set to true when this app creates a surface while in the middle of an animation. In that
90    // case do not clear allDrawn until the animation completes.
91    boolean deferClearAllDrawn;
92
93    // These are to track the app's real drawing status if there were no saved surfaces.
94    boolean allDrawnExcludingSaved;
95    int numInterestingWindowsExcludingSaved;
96    int numDrawnWindowsExclusingSaved;
97
98    // Is this window's surface needed?  This is almost like hidden, except
99    // it will sometimes be true a little earlier: when the token has
100    // been shown, but is still waiting for its app transition to execute
101    // before making its windows shown.
102    boolean hiddenRequested;
103
104    // Have we told the window clients to hide themselves?
105    boolean clientHidden;
106
107    // Last visibility state we reported to the app token.
108    boolean reportedVisible;
109
110    // Last drawn state we reported to the app token.
111    boolean reportedDrawn;
112
113    // Set to true when the token has been removed from the window mgr.
114    boolean removed;
115
116    // Information about an application starting window if displayed.
117    StartingData startingData;
118    WindowState startingWindow;
119    View startingView;
120    boolean startingDisplayed;
121    boolean startingMoved;
122    boolean firstWindowDrawn;
123
124    // Input application handle used by the input dispatcher.
125    final InputApplicationHandle mInputApplicationHandle;
126
127    boolean mIsExiting;
128
129    boolean mLaunchTaskBehind;
130    boolean mEnteringAnimation;
131
132    boolean mAlwaysFocusable;
133
134    boolean mAppStopped;
135    int mPendingRelaunchCount;
136
137    private ArrayList<WindowSurfaceController.SurfaceControlWithBackground> mSurfaceViewBackgrounds =
138        new ArrayList<WindowSurfaceController.SurfaceControlWithBackground>();
139
140    ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
141    ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
142
143    AppWindowToken(WindowManagerService _service, IApplicationToken _token,
144            boolean _voiceInteraction) {
145        super(_service, _token.asBinder(),
146                WindowManager.LayoutParams.TYPE_APPLICATION, true);
147        appWindowToken = this;
148        appToken = _token;
149        voiceInteraction = _voiceInteraction;
150        mInputApplicationHandle = new InputApplicationHandle(this);
151        mAppAnimator = new AppWindowAnimator(this);
152    }
153
154    void sendAppVisibilityToClients() {
155        final int N = allAppWindows.size();
156        for (int i=0; i<N; i++) {
157            WindowState win = allAppWindows.get(i);
158            if (win == startingWindow && clientHidden) {
159                // Don't hide the starting window.
160                continue;
161            }
162            try {
163                if (DEBUG_VISIBILITY) Slog.v(TAG,
164                        "Setting visibility of " + win + ": " + (!clientHidden));
165                win.mClient.dispatchAppVisibility(!clientHidden);
166            } catch (RemoteException e) {
167            }
168        }
169    }
170
171    void setVisibleBeforeClientHidden() {
172        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
173            final WindowState w = allAppWindows.get(i);
174            w.setVisibleBeforeClientHidden();
175        }
176    }
177
178    void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
179        firstWindowDrawn = true;
180
181        // We now have a good window to show, remove dead placeholders
182        removeAllDeadWindows();
183
184        if (startingData != null) {
185            if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
186                    + win.mToken + ": first real window is shown, no animation");
187            // If this initial window is animating, stop it -- we will do an animation to reveal
188            // it from behind the starting window, so there is no need for it to also be doing its
189            // own stuff.
190            winAnimator.clearAnimation();
191            winAnimator.mService.mFinishedStarting.add(this);
192            winAnimator.mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
193        }
194        updateReportedVisibilityLocked();
195    }
196
197    void updateReportedVisibilityLocked() {
198        if (appToken == null) {
199            return;
200        }
201
202        int numInteresting = 0;
203        int numVisible = 0;
204        int numDrawn = 0;
205        boolean nowGone = true;
206
207        if (DEBUG_VISIBILITY) Slog.v(TAG,
208                "Update reported visibility: " + this);
209        final int N = allAppWindows.size();
210        for (int i=0; i<N; i++) {
211            WindowState win = allAppWindows.get(i);
212            if (win == startingWindow || win.mAppFreezing
213                    || win.mViewVisibility != View.VISIBLE
214                    || win.mAttrs.type == TYPE_APPLICATION_STARTING
215                    || win.mDestroying) {
216                continue;
217            }
218            if (DEBUG_VISIBILITY) {
219                Slog.v(TAG, "Win " + win + ": isDrawn="
220                        + win.isDrawnLw()
221                        + ", isAnimationSet=" + win.mWinAnimator.isAnimationSet());
222                if (!win.isDrawnLw()) {
223                    Slog.v(TAG, "Not displayed: s=" +
224                            win.mWinAnimator.mSurfaceController
225                            + " pv=" + win.mPolicyVisibility
226                            + " mDrawState=" + win.mWinAnimator.mDrawState
227                            + " ah=" + win.mAttachedHidden
228                            + " th="
229                            + (win.mAppToken != null
230                                    ? win.mAppToken.hiddenRequested : false)
231                            + " a=" + win.mWinAnimator.mAnimating);
232                }
233            }
234            numInteresting++;
235            if (win.isDrawnLw()) {
236                numDrawn++;
237                if (!win.mWinAnimator.isAnimationSet()) {
238                    numVisible++;
239                }
240                nowGone = false;
241            } else if (win.mWinAnimator.isAnimationSet()) {
242                nowGone = false;
243            }
244        }
245
246        boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
247        boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
248        if (!nowGone) {
249            // If the app is not yet gone, then it can only become visible/drawn.
250            if (!nowDrawn) {
251                nowDrawn = reportedDrawn;
252            }
253            if (!nowVisible) {
254                nowVisible = reportedVisible;
255            }
256        }
257        if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
258                + numInteresting + " visible=" + numVisible);
259        if (nowDrawn != reportedDrawn) {
260            if (nowDrawn) {
261                Message m = service.mH.obtainMessage(
262                        H.REPORT_APPLICATION_TOKEN_DRAWN, this);
263                service.mH.sendMessage(m);
264            }
265            reportedDrawn = nowDrawn;
266        }
267        if (nowVisible != reportedVisible) {
268            if (DEBUG_VISIBILITY) Slog.v(
269                    TAG, "Visibility changed in " + this
270                    + ": vis=" + nowVisible);
271            reportedVisible = nowVisible;
272            Message m = service.mH.obtainMessage(
273                    H.REPORT_APPLICATION_TOKEN_WINDOWS,
274                    nowVisible ? 1 : 0,
275                    nowGone ? 1 : 0,
276                    this);
277            service.mH.sendMessage(m);
278        }
279    }
280
281    WindowState findMainWindow() {
282        WindowState candidate = null;
283        int j = windows.size();
284        while (j > 0) {
285            j--;
286            WindowState win = windows.get(j);
287            if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
288                    || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
289                // In cases where there are multiple windows, we prefer the non-exiting window. This
290                // happens for example when replacing windows during an activity relaunch. When
291                // constructing the animation, we want the new window, not the exiting one.
292                if (win.mAnimatingExit) {
293                    candidate = win;
294                } else {
295                    return win;
296                }
297            }
298        }
299        return candidate;
300    }
301
302    boolean windowsAreFocusable() {
303        return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable;
304    }
305
306    boolean isVisible() {
307        final int N = allAppWindows.size();
308        for (int i=0; i<N; i++) {
309            WindowState win = allAppWindows.get(i);
310            // If we're animating with a saved surface, we're already visible.
311            // Return true so that the alpha doesn't get cleared.
312            if (!win.mAppFreezing
313                    && (win.mViewVisibility == View.VISIBLE || win.isAnimatingWithSavedSurface()
314                            || (win.mWinAnimator.isAnimationSet()
315                                    && !service.mAppTransition.isTransitionSet()))
316                    && !win.mDestroying
317                    && win.isDrawnLw()) {
318                return true;
319            }
320        }
321        return false;
322    }
323
324    void removeAppFromTaskLocked() {
325        mIsExiting = false;
326        removeAllWindows();
327
328        // Use local variable because removeAppToken will null out mTask.
329        final Task task = mTask;
330        if (task != null) {
331            if (!task.removeAppToken(this)) {
332                Slog.e(TAG, "removeAppFromTaskLocked: token=" + this
333                        + " not found.");
334            }
335            task.mStack.mExitingAppTokens.remove(this);
336        }
337    }
338
339    // Here we destroy surfaces which have been marked as eligible by the animator, taking care
340    // to ensure the client has finished with them. If the client could still be using them
341    // we will skip destruction and try again when the client has stopped.
342    void destroySurfaces() {
343        final ArrayList<WindowState> allWindows = (ArrayList<WindowState>) allAppWindows.clone();
344        final DisplayContentList displayList = new DisplayContentList();
345        for (int i = allWindows.size() - 1; i >= 0; i--) {
346            final WindowState win = allWindows.get(i);
347
348            if (!(mAppStopped || win.mWindowRemovalAllowed)) {
349                continue;
350            }
351
352            win.mWinAnimator.destroyPreservedSurfaceLocked();
353
354            if (!win.mDestroying) {
355                continue;
356            }
357
358            if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + win
359                    + " destroySurfaces: mAppStopped=" + mAppStopped
360                    + " win.mWindowRemovalAllowed=" + win.mWindowRemovalAllowed
361                    + " win.mRemoveOnExit=" + win.mRemoveOnExit);
362
363            win.destroyOrSaveSurface();
364            if (win.mRemoveOnExit) {
365                service.removeWindowInnerLocked(win);
366            }
367            final DisplayContent displayContent = win.getDisplayContent();
368            if (displayContent != null && !displayList.contains(displayContent)) {
369                displayList.add(displayContent);
370            }
371            win.mDestroying = false;
372        }
373        for (int i = 0; i < displayList.size(); i++) {
374            final DisplayContent displayContent = displayList.get(i);
375            service.mLayersController.assignLayersLocked(displayContent.getWindowList());
376            displayContent.layoutNeeded = true;
377        }
378    }
379
380    /**
381     * If the application has stopped it is okay to destroy any surfaces which were keeping alive
382     * in case they were still being used.
383     */
384    void notifyAppStopped(boolean stopped) {
385        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: stopped=" + stopped + " " + this);
386        mAppStopped = stopped;
387
388        if (stopped) {
389            destroySurfaces();
390            // Remove any starting window that was added for this app if they are still around.
391            mTask.mService.scheduleRemoveStartingWindowLocked(this);
392        }
393    }
394
395    /**
396     * Checks whether we should save surfaces for this app.
397     *
398     * @return true if the surfaces should be saved, false otherwise.
399     */
400    boolean shouldSaveSurface() {
401        // We want to save surface if the app's windows are "allDrawn".
402        // (If we started entering animation early with saved surfaces, allDrawn
403        // should have been restored to true. So we'll save again in that case
404        // even if app didn't actually finish drawing.)
405        return allDrawn;
406    }
407
408    boolean canRestoreSurfaces() {
409        for (int i = allAppWindows.size() -1; i >= 0; i--) {
410            final WindowState w = allAppWindows.get(i);
411            if (w.canRestoreSurface()) {
412                return true;
413            }
414        }
415        return false;
416    }
417
418    void clearVisibleBeforeClientHidden() {
419        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
420            final WindowState w = allAppWindows.get(i);
421            w.clearVisibleBeforeClientHidden();
422        }
423    }
424
425    /**
426     * Whether the app has some window that is invisible in layout, but
427     * animating with saved surface.
428     */
429    boolean isAnimatingInvisibleWithSavedSurface() {
430        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
431            final WindowState w = allAppWindows.get(i);
432            if (w.isAnimatingInvisibleWithSavedSurface()) {
433                return true;
434            }
435        }
436        return false;
437    }
438
439    /**
440     * Hide all window surfaces that's still invisible in layout but animating
441     * with a saved surface, and mark them destroying.
442     */
443    void stopUsingSavedSurfaceLocked() {
444        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
445            final WindowState w = allAppWindows.get(i);
446            if (w.isAnimatingInvisibleWithSavedSurface()) {
447                if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
448                        "stopUsingSavedSurfaceLocked: " + w);
449                w.clearAnimatingWithSavedSurface();
450                w.mDestroying = true;
451                w.mWinAnimator.hide("stopUsingSavedSurfaceLocked");
452                w.mWinAnimator.mWallpaperControllerLocked.hideWallpapers(w);
453            }
454        }
455        destroySurfaces();
456    }
457
458    void markSavedSurfaceExiting() {
459        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
460            final WindowState w = allAppWindows.get(i);
461            if (w.isAnimatingInvisibleWithSavedSurface()) {
462                w.mAnimatingExit = true;
463                w.mWinAnimator.mAnimating = true;
464            }
465        }
466    }
467
468    void restoreSavedSurfaces() {
469        if (!canRestoreSurfaces()) {
470            clearVisibleBeforeClientHidden();
471            return;
472        }
473        // Check if we have enough drawn windows to mark allDrawn= true.
474        int numInteresting = 0;
475        int numDrawn = 0;
476        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
477            WindowState w = allAppWindows.get(i);
478            if (w != startingWindow && !w.mAppDied && w.wasVisibleBeforeClientHidden()
479                    && (!mAppAnimator.freezingScreen || !w.mAppFreezing)) {
480                numInteresting++;
481                if (w.hasSavedSurface()) {
482                    w.restoreSavedSurface();
483                }
484                if (w.isDrawnLw()) {
485                    numDrawn++;
486                }
487            }
488        }
489
490        if (!allDrawn) {
491            allDrawn = (numInteresting > 0) && (numInteresting == numDrawn);
492            if (allDrawn) {
493                service.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
494            }
495        }
496        clearVisibleBeforeClientHidden();
497
498        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
499                "restoreSavedSurfaces: " + appWindowToken + " allDrawn=" + allDrawn
500                + " numInteresting=" + numInteresting + " numDrawn=" + numDrawn);
501    }
502
503    void destroySavedSurfaces() {
504        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
505            WindowState win = allAppWindows.get(i);
506            win.destroySavedSurface();
507        }
508    }
509
510    void clearAllDrawn() {
511        allDrawn = false;
512        deferClearAllDrawn = false;
513        allDrawnExcludingSaved = false;
514    }
515
516    @Override
517    void removeAllWindows() {
518        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
519                // removeWindowLocked at bottom of loop may remove multiple entries from
520                // allAppWindows if the window to be removed has child windows. It also may
521                // not remove any windows from allAppWindows at all if win is exiting and
522                // currently animating away. This ensures that winNdx is monotonically decreasing
523                // and never beyond allAppWindows bounds.
524                winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
525            WindowState win = allAppWindows.get(winNdx);
526            if (DEBUG_WINDOW_MOVEMENT) {
527                Slog.w(TAG, "removeAllWindows: removing win=" + win);
528            }
529
530            service.removeWindowLocked(win);
531        }
532        allAppWindows.clear();
533        windows.clear();
534    }
535
536    void removeAllDeadWindows() {
537        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
538            // removeWindowLocked at bottom of loop may remove multiple entries from
539            // allAppWindows if the window to be removed has child windows. It also may
540            // not remove any windows from allAppWindows at all if win is exiting and
541            // currently animating away. This ensures that winNdx is monotonically decreasing
542            // and never beyond allAppWindows bounds.
543            winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
544            WindowState win = allAppWindows.get(winNdx);
545            if (win.mAppDied) {
546                if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
547                    Slog.w(TAG, "removeAllDeadWindows: " + win);
548                }
549                // Set mDestroying, we don't want any animation or delayed removal here.
550                win.mDestroying = true;
551                service.removeWindowLocked(win);
552            }
553        }
554    }
555
556    boolean hasWindowsAlive() {
557        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
558            if (!allAppWindows.get(i).mAppDied) {
559                return true;
560            }
561        }
562        return false;
563    }
564
565    void setReplacingWindows(boolean animate) {
566        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken
567                + " with replacing windows.");
568
569        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
570            final WindowState w = allAppWindows.get(i);
571            w.setReplacing(animate);
572        }
573        if (animate) {
574            // Set-up dummy animation so we can start treating windows associated with this
575            // token like they are in transition before the new app window is ready for us to
576            // run the real transition animation.
577            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
578                    "setReplacingWindow() Setting dummy animation on: " + this);
579            mAppAnimator.setDummyAnimation();
580        }
581    }
582
583    void setReplacingChildren() {
584        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken
585                + " with replacing child windows.");
586        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
587            final WindowState w = allAppWindows.get(i);
588            if (w.shouldBeReplacedWithChildren()) {
589                w.setReplacing(false /* animate */);
590            }
591        }
592    }
593
594    void resetReplacingWindows() {
595        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Resetting app token " + appWindowToken
596                + " of replacing window marks.");
597
598        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
599            final WindowState w = allAppWindows.get(i);
600            w.resetReplacing();
601        }
602    }
603
604    void requestUpdateWallpaperIfNeeded() {
605        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
606            final WindowState w = allAppWindows.get(i);
607            w.requestUpdateWallpaperIfNeeded();
608        }
609    }
610
611    boolean isRelaunching() {
612        return mPendingRelaunchCount > 0;
613    }
614
615    void startRelaunching() {
616        if (canFreezeBounds()) {
617            freezeBounds();
618        }
619        mPendingRelaunchCount++;
620    }
621
622    void finishRelaunching() {
623        if (canFreezeBounds()) {
624            unfreezeBounds();
625        }
626        if (mPendingRelaunchCount > 0) {
627            mPendingRelaunchCount--;
628        }
629    }
630
631    void addWindow(WindowState w) {
632        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
633            WindowState candidate = allAppWindows.get(i);
634            if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null &&
635                    candidate.getWindowTag().toString().equals(w.getWindowTag().toString())) {
636                candidate.mReplacingWindow = w;
637                w.mSkipEnterAnimationForSeamlessReplacement = !candidate.mAnimateReplacingWindow;
638
639                // if we got a replacement window, reset the timeout to give drawing more time
640                service.scheduleReplacingWindowTimeouts(this);
641            }
642        }
643        allAppWindows.add(w);
644    }
645
646    boolean waitingForReplacement() {
647        for (int i = allAppWindows.size() -1; i >= 0; i--) {
648            WindowState candidate = allAppWindows.get(i);
649            if (candidate.mWillReplaceWindow) {
650                return true;
651            }
652        }
653        return false;
654    }
655
656    void clearTimedoutReplacesLocked() {
657        for (int i = allAppWindows.size() - 1; i >= 0;
658             // removeWindowLocked at bottom of loop may remove multiple entries from
659             // allAppWindows if the window to be removed has child windows. It also may
660             // not remove any windows from allAppWindows at all if win is exiting and
661             // currently animating away. This ensures that winNdx is monotonically decreasing
662             // and never beyond allAppWindows bounds.
663             i = Math.min(i - 1, allAppWindows.size() - 1)) {
664            WindowState candidate = allAppWindows.get(i);
665            if (candidate.mWillReplaceWindow == false) {
666                continue;
667            }
668            candidate.mWillReplaceWindow = false;
669            if (candidate.mReplacingWindow != null) {
670                candidate.mReplacingWindow.mSkipEnterAnimationForSeamlessReplacement = false;
671            }
672            // Since the window already timed out, remove it immediately now.
673            // Use removeWindowInnerLocked() instead of removeWindowLocked(), as the latter
674            // delays removal on certain conditions, which will leave the stale window in the
675            // stack and marked mWillReplaceWindow=false, so the window will never be removed.
676            service.removeWindowInnerLocked(candidate);
677        }
678    }
679
680    private boolean canFreezeBounds() {
681        // For freeform windows, we can't freeze the bounds at the moment because this would make
682        // the resizing unresponsive.
683        return mTask != null && !mTask.inFreeformWorkspace();
684    }
685
686    /**
687     * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
688     * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
689     * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen
690     * with a queue.
691     */
692    private void freezeBounds() {
693        mFrozenBounds.offer(new Rect(mTask.mPreparedFrozenBounds));
694
695        if (mTask.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) {
696            // We didn't call prepareFreezingBounds on the task, so use the current value.
697            final Configuration config = new Configuration(service.mCurConfiguration);
698            config.updateFrom(mTask.mOverrideConfig);
699            mFrozenMergedConfig.offer(config);
700        } else {
701            mFrozenMergedConfig.offer(new Configuration(mTask.mPreparedFrozenMergedConfig));
702        }
703        mTask.mPreparedFrozenMergedConfig.setToDefaults();
704    }
705
706    /**
707     * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
708     */
709    private void unfreezeBounds() {
710        mFrozenBounds.remove();
711        mFrozenMergedConfig.remove();
712        for (int i = windows.size() - 1; i >= 0; i--) {
713            final WindowState win = windows.get(i);
714            if (!win.mHasSurface) {
715                continue;
716            }
717            win.mLayoutNeeded = true;
718            win.setDisplayLayoutNeeded();
719            if (!service.mResizingWindows.contains(win)) {
720                service.mResizingWindows.add(win);
721            }
722        }
723        service.mWindowPlacerLocked.performSurfacePlacement();
724    }
725
726    void addSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background) {
727        mSurfaceViewBackgrounds.add(background);
728    }
729
730    void removeSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background) {
731        mSurfaceViewBackgrounds.remove(background);
732        updateSurfaceViewBackgroundVisibilities();
733    }
734
735    // We use DimLayers behind SurfaceViews to prevent holes while resizing and creating.
736    // However, we need to ensure one SurfaceView doesn't cover another when they are both placed
737    // below the main app window (as traditionally a SurfaceView which is never drawn
738    // to is totally translucent). So we look at all our SurfaceView backgrounds and only enable
739    // the background for the SurfaceView with lowest Z order
740    void updateSurfaceViewBackgroundVisibilities() {
741        WindowSurfaceController.SurfaceControlWithBackground bottom = null;
742        int bottomLayer = Integer.MAX_VALUE;
743        for (int i = 0; i < mSurfaceViewBackgrounds.size(); i++) {
744            WindowSurfaceController.SurfaceControlWithBackground sc = mSurfaceViewBackgrounds.get(i);
745            if (sc.mVisible && sc.mLayer < bottomLayer) {
746                bottomLayer = sc.mLayer;
747                bottom = sc;
748            }
749        }
750        for (int i = 0; i < mSurfaceViewBackgrounds.size(); i++) {
751            WindowSurfaceController.SurfaceControlWithBackground sc = mSurfaceViewBackgrounds.get(i);
752            sc.updateBackgroundVisibility(sc != bottom);
753        }
754    }
755
756    @Override
757    void dump(PrintWriter pw, String prefix) {
758        super.dump(pw, prefix);
759        if (appToken != null) {
760            pw.print(prefix); pw.print("app=true voiceInteraction="); pw.println(voiceInteraction);
761        }
762        if (allAppWindows.size() > 0) {
763            pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
764        }
765        pw.print(prefix); pw.print("task="); pw.println(mTask);
766        pw.print(prefix); pw.print(" appFullscreen="); pw.print(appFullscreen);
767                pw.print(" requestedOrientation="); pw.println(requestedOrientation);
768        pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
769                pw.print(" clientHidden="); pw.print(clientHidden);
770                pw.print(" reportedDrawn="); pw.print(reportedDrawn);
771                pw.print(" reportedVisible="); pw.println(reportedVisible);
772        if (paused) {
773            pw.print(prefix); pw.print("paused="); pw.println(paused);
774        }
775        if (mAppStopped) {
776            pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped);
777        }
778        if (numInterestingWindows != 0 || numDrawnWindows != 0
779                || allDrawn || mAppAnimator.allDrawn) {
780            pw.print(prefix); pw.print("numInterestingWindows=");
781                    pw.print(numInterestingWindows);
782                    pw.print(" numDrawnWindows="); pw.print(numDrawnWindows);
783                    pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
784                    pw.print(" allDrawn="); pw.print(allDrawn);
785                    pw.print(" (animator="); pw.print(mAppAnimator.allDrawn);
786                    pw.println(")");
787        }
788        if (inPendingTransaction) {
789            pw.print(prefix); pw.print("inPendingTransaction=");
790                    pw.println(inPendingTransaction);
791        }
792        if (startingData != null || removed || firstWindowDrawn || mIsExiting) {
793            pw.print(prefix); pw.print("startingData="); pw.print(startingData);
794                    pw.print(" removed="); pw.print(removed);
795                    pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
796                    pw.print(" mIsExiting="); pw.println(mIsExiting);
797        }
798        if (startingWindow != null || startingView != null
799                || startingDisplayed || startingMoved) {
800            pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
801                    pw.print(" startingView="); pw.print(startingView);
802                    pw.print(" startingDisplayed="); pw.print(startingDisplayed);
803                    pw.print(" startingMoved="); pw.println(startingMoved);
804        }
805        if (!mFrozenBounds.isEmpty()) {
806            pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds);
807            pw.print(prefix); pw.print("mFrozenMergedConfig="); pw.println(mFrozenMergedConfig);
808        }
809        if (mPendingRelaunchCount != 0) {
810            pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
811        }
812    }
813
814    @Override
815    public String toString() {
816        if (stringName == null) {
817            StringBuilder sb = new StringBuilder();
818            sb.append("AppWindowToken{");
819            sb.append(Integer.toHexString(System.identityHashCode(this)));
820            sb.append(" token="); sb.append(token); sb.append('}');
821            stringName = sb.toString();
822        }
823        return stringName;
824    }
825}
826