Home | History | Annotate | Download | only in wm
      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 
    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