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 java.util.Comparator;
     20 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
     21 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
     22 
     23 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
     24 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
     25 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
     26 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
     27 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     28 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
     29 
     30 import android.os.Debug;
     31 import android.os.IBinder;
     32 import android.util.Slog;
     33 import android.view.SurfaceControl;
     34 
     35 import java.io.PrintWriter;
     36 
     37 /**
     38  * Container of a set of related windows in the window manager. Often this is an AppWindowToken,
     39  * which is the handle for an Activity that it uses to display windows. For nested windows, there is
     40  * a WindowToken created for the parent window to manage its children.
     41  */
     42 class WindowToken extends WindowContainer<WindowState> {
     43     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowToken" : TAG_WM;
     44 
     45     // The window manager!
     46     protected final WindowManagerService mService;
     47 
     48     // The actual token.
     49     final IBinder token;
     50 
     51     // The type of window this token is for, as per WindowManager.LayoutParams.
     52     final int windowType;
     53 
     54     // Set if this token was explicitly added by a client, so should
     55     // persist (not be removed) when all windows are removed.
     56     boolean mPersistOnEmpty;
     57 
     58     // For printing.
     59     String stringName;
     60 
     61     // Is key dispatching paused for this token?
     62     boolean paused = false;
     63 
     64     // Should this token's windows be hidden?
     65     boolean hidden;
     66 
     67     // Temporary for finding which tokens no longer have visible windows.
     68     boolean hasVisible;
     69 
     70     // Set to true when this token is in a pending transaction where it
     71     // will be shown.
     72     boolean waitingToShow;
     73 
     74     // Set to true when this token is in a pending transaction where its
     75     // windows will be put to the bottom of the list.
     76     boolean sendingToBottom;
     77 
     78     // The display this token is on.
     79     protected DisplayContent mDisplayContent;
     80 
     81     /** The owner has {@link android.Manifest.permission#MANAGE_APP_TOKENS} */
     82     final boolean mOwnerCanManageAppTokens;
     83 
     84     /**
     85      * Compares two child window of this token and returns -1 if the first is lesser than the
     86      * second in terms of z-order and 1 otherwise.
     87      */
     88     private final Comparator<WindowState> mWindowComparator =
     89             (WindowState newWindow, WindowState existingWindow) -> {
     90         final WindowToken token = WindowToken.this;
     91         if (newWindow.mToken != token) {
     92             throw new IllegalArgumentException("newWindow=" + newWindow
     93                     + " is not a child of token=" + token);
     94         }
     95 
     96         if (existingWindow.mToken != token) {
     97             throw new IllegalArgumentException("existingWindow=" + existingWindow
     98                     + " is not a child of token=" + token);
     99         }
    100 
    101         return isFirstChildWindowGreaterThanSecond(newWindow, existingWindow) ? 1 : -1;
    102     };
    103 
    104     WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
    105             DisplayContent dc, boolean ownerCanManageAppTokens) {
    106         mService = service;
    107         token = _token;
    108         windowType = type;
    109         mPersistOnEmpty = persistOnEmpty;
    110         mOwnerCanManageAppTokens = ownerCanManageAppTokens;
    111         onDisplayChanged(dc);
    112     }
    113 
    114     void removeAllWindowsIfPossible() {
    115         for (int i = mChildren.size() - 1; i >= 0; --i) {
    116             final WindowState win = mChildren.get(i);
    117             if (DEBUG_WINDOW_MOVEMENT) Slog.w(TAG_WM,
    118                     "removeAllWindowsIfPossible: removing win=" + win);
    119             win.removeIfPossible();
    120         }
    121     }
    122 
    123     void setExiting() {
    124         // This token is exiting, so allow it to be removed when it no longer contains any windows.
    125         mPersistOnEmpty = false;
    126 
    127         if (hidden) {
    128             return;
    129         }
    130 
    131         final int count = mChildren.size();
    132         boolean changed = false;
    133         boolean delayed = false;
    134 
    135         for (int i = 0; i < count; i++) {
    136             final WindowState win = mChildren.get(i);
    137             if (win.mWinAnimator.isAnimationSet()) {
    138                 delayed = true;
    139             }
    140             changed |= win.onSetAppExiting();
    141         }
    142 
    143         hidden = true;
    144 
    145         if (changed) {
    146             mService.mWindowPlacerLocked.performSurfacePlacement();
    147             mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /*updateInputWindows*/);
    148         }
    149 
    150         if (delayed) {
    151             mDisplayContent.mExitingTokens.add(this);
    152         }
    153     }
    154 
    155     /**
    156      * Returns true if the new window is considered greater than the existing window in terms of
    157      * z-order.
    158      */
    159     protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
    160             WindowState existingWindow) {
    161         // New window is considered greater if it has a higher or equal base layer.
    162         return newWindow.mBaseLayer >= existingWindow.mBaseLayer;
    163     }
    164 
    165     void addWindow(final WindowState win) {
    166         if (DEBUG_FOCUS) Slog.d(TAG_WM,
    167                 "addWindow: win=" + win + " Callers=" + Debug.getCallers(5));
    168 
    169         if (win.isChildWindow()) {
    170             // Child windows are added to their parent windows.
    171             return;
    172         }
    173         if (!mChildren.contains(win)) {
    174             if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
    175             addChild(win, mWindowComparator);
    176             mService.mWindowsChanged = true;
    177             // TODO: Should we also be setting layout needed here and other places?
    178         }
    179     }
    180 
    181     /** Returns true if the token windows list is empty. */
    182     boolean isEmpty() {
    183         return mChildren.isEmpty();
    184     }
    185 
    186     // Used by AppWindowToken.
    187     int getAnimLayerAdjustment() {
    188         return 0;
    189     }
    190 
    191     WindowState getReplacingWindow() {
    192         for (int i = mChildren.size() - 1; i >= 0; i--) {
    193             final WindowState win = mChildren.get(i);
    194             final WindowState replacing = win.getReplacingWindow();
    195             if (replacing != null) {
    196                 return replacing;
    197             }
    198         }
    199         return null;
    200     }
    201 
    202     /** Return true if this token has a window that wants the wallpaper displayed behind it. */
    203     boolean windowsCanBeWallpaperTarget() {
    204         for (int j = mChildren.size() - 1; j >= 0; j--) {
    205             final WindowState w = mChildren.get(j);
    206             if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
    207                 return true;
    208             }
    209         }
    210 
    211         return false;
    212     }
    213 
    214     int getHighestAnimLayer() {
    215         int highest = -1;
    216         for (int j = 0; j < mChildren.size(); j++) {
    217             final WindowState w = mChildren.get(j);
    218             final int wLayer = w.getHighestAnimLayer();
    219             if (wLayer > highest) {
    220                 highest = wLayer;
    221             }
    222         }
    223         return highest;
    224     }
    225 
    226     AppWindowToken asAppWindowToken() {
    227         // TODO: Not sure if this is the best way to handle this vs. using instanceof and casting.
    228         // I am not an app window token!
    229         return null;
    230     }
    231 
    232     DisplayContent getDisplayContent() {
    233         return mDisplayContent;
    234     }
    235 
    236     @Override
    237     void removeImmediately() {
    238         if (mDisplayContent != null) {
    239             mDisplayContent.removeWindowToken(token);
    240         }
    241         // Needs to occur after the token is removed from the display above to avoid attempt at
    242         // duplicate removal of this window container from it's parent.
    243         super.removeImmediately();
    244     }
    245 
    246     void onDisplayChanged(DisplayContent dc) {
    247         dc.reParentWindowToken(this);
    248         mDisplayContent = dc;
    249 
    250         // TODO(b/36740756): One day this should perhaps be hooked
    251         // up with goodToGo, so we don't move a window
    252         // to another display before the window behind
    253         // it is ready.
    254         SurfaceControl.openTransaction();
    255         for (int i = mChildren.size() - 1; i >= 0; --i) {
    256             final WindowState win = mChildren.get(i);
    257             win.mWinAnimator.updateLayerStackInTransaction();
    258         }
    259         SurfaceControl.closeTransaction();
    260 
    261         super.onDisplayChanged(dc);
    262     }
    263 
    264     void dump(PrintWriter pw, String prefix) {
    265         pw.print(prefix); pw.print("windows="); pw.println(mChildren);
    266         pw.print(prefix); pw.print("windowType="); pw.print(windowType);
    267                 pw.print(" hidden="); pw.print(hidden);
    268                 pw.print(" hasVisible="); pw.println(hasVisible);
    269         if (waitingToShow || sendingToBottom) {
    270             pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow);
    271                     pw.print(" sendingToBottom="); pw.print(sendingToBottom);
    272         }
    273     }
    274 
    275     @Override
    276     public String toString() {
    277         if (stringName == null) {
    278             StringBuilder sb = new StringBuilder();
    279             sb.append("WindowToken{");
    280             sb.append(Integer.toHexString(System.identityHashCode(this)));
    281             sb.append(" "); sb.append(token); sb.append('}');
    282             stringName = sb.toString();
    283         }
    284         return stringName;
    285     }
    286 
    287     @Override
    288     String getName() {
    289         return toString();
    290     }
    291 
    292     boolean okToDisplay() {
    293         return mDisplayContent != null && mDisplayContent.okToDisplay();
    294     }
    295 
    296     boolean okToAnimate() {
    297         return mDisplayContent != null && mDisplayContent.okToAnimate();
    298     }
    299 }
    300