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