1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wm;
18 
19 import static android.app.ActivityManager.StackId;
20 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
21 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
22 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
23 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
24 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
25 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
26 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
27 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
28 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
29 import static com.android.server.wm.WindowManagerService.WINDOW_REPLACEMENT_TIMEOUT_DURATION;
30 import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
31 
32 import com.android.server.input.InputApplicationHandle;
33 import com.android.server.wm.WindowManagerService.H;
34 
35 import android.annotation.NonNull;
36 import android.content.pm.ActivityInfo;
37 import android.content.res.Configuration;
38 import android.graphics.Rect;
39 import android.os.Message;
40 import android.os.RemoteException;
41 import android.util.Slog;
42 import android.view.IApplicationToken;
43 import android.view.View;
44 import android.view.WindowManager;
45 
46 import java.io.PrintWriter;
47 import java.util.ArrayDeque;
48 import java.util.ArrayList;
49 
50 class 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  */
57 class 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 
AppWindowToken(WindowManagerService _service, IApplicationToken _token, boolean _voiceInteraction)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 
sendAppVisibilityToClients()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 
setVisibleBeforeClientHidden()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 
onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator)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 
updateReportedVisibilityLocked()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 
findMainWindow()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 
windowsAreFocusable()302     boolean windowsAreFocusable() {
303         return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable;
304     }
305 
isVisible()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 
removeAppFromTaskLocked()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.
destroySurfaces()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      */
notifyAppStopped(boolean stopped)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      */
shouldSaveSurface()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 
canRestoreSurfaces()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 
clearVisibleBeforeClientHidden()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      */
isAnimatingInvisibleWithSavedSurface()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      */
stopUsingSavedSurfaceLocked()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 
markSavedSurfaceExiting()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 
restoreSavedSurfaces()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 
destroySavedSurfaces()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 
clearAllDrawn()510     void clearAllDrawn() {
511         allDrawn = false;
512         deferClearAllDrawn = false;
513         allDrawnExcludingSaved = false;
514     }
515 
516     @Override
removeAllWindows()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 
removeAllDeadWindows()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 
hasWindowsAlive()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 
setReplacingWindows(boolean animate)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 
setReplacingChildren()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 
resetReplacingWindows()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 
requestUpdateWallpaperIfNeeded()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 
isRelaunching()611     boolean isRelaunching() {
612         return mPendingRelaunchCount > 0;
613     }
614 
startRelaunching()615     void startRelaunching() {
616         if (canFreezeBounds()) {
617             freezeBounds();
618         }
619         mPendingRelaunchCount++;
620     }
621 
finishRelaunching()622     void finishRelaunching() {
623         if (canFreezeBounds()) {
624             unfreezeBounds();
625         }
626         if (mPendingRelaunchCount > 0) {
627             mPendingRelaunchCount--;
628         }
629     }
630 
addWindow(WindowState w)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 
waitingForReplacement()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 
clearTimedoutReplacesLocked()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 
canFreezeBounds()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      */
freezeBounds()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      */
unfreezeBounds()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 
addSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background)726     void addSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background) {
727         mSurfaceViewBackgrounds.add(background);
728     }
729 
removeSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background)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
updateSurfaceViewBackgroundVisibilities()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
dump(PrintWriter pw, String prefix)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
toString()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