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 WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens)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 removeAllWindowsIfPossible()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 setExiting()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 */ isFirstChildWindowGreaterThanSecond(WindowState newWindow, WindowState existingWindow)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 addWindow(final WindowState win)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. */ isEmpty()182 boolean isEmpty() { 183 return mChildren.isEmpty(); 184 } 185 186 // Used by AppWindowToken. getAnimLayerAdjustment()187 int getAnimLayerAdjustment() { 188 return 0; 189 } 190 getReplacingWindow()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. */ windowsCanBeWallpaperTarget()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 getHighestAnimLayer()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 asAppWindowToken()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 getDisplayContent()232 DisplayContent getDisplayContent() { 233 return mDisplayContent; 234 } 235 236 @Override removeImmediately()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 onDisplayChanged(DisplayContent dc)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 dump(PrintWriter pw, String prefix)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 toString()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 getName()288 String getName() { 289 return toString(); 290 } 291 } 292