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