DisplayContent.java revision ae9adbfb758712caaf11b4ba5c5fd15848dcc3c5
1/* 2 * Copyright (C) 2012 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 17package com.android.server.wm; 18 19import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; 20import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; 21import static android.app.ActivityManager.StackId.HOME_STACK_ID; 22import static android.app.ActivityManager.StackId.PINNED_STACK_ID; 23import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; 24import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 25import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 26import static android.view.Display.DEFAULT_DISPLAY; 27import static android.view.Display.FLAG_PRIVATE; 28import static android.view.Surface.ROTATION_0; 29import static android.view.Surface.ROTATION_180; 30import static android.view.Surface.ROTATION_270; 31import static android.view.Surface.ROTATION_90; 32import static android.view.WindowManager.DOCKED_BOTTOM; 33import static android.view.WindowManager.DOCKED_INVALID; 34import static android.view.WindowManager.DOCKED_TOP; 35import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; 36import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 37import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 38import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 39import static android.view.WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE; 40import static android.view.WindowManager.LayoutParams.NEEDS_MENU_UNSET; 41import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 42import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 43import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; 44import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 45import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 46import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; 47import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY; 48import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS; 49import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; 50import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD; 51import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS; 52import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; 53import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; 54import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; 55import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; 56import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS; 57import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 58import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT; 59import static com.android.server.wm.WindowManagerService.dipToPixel; 60import static com.android.server.wm.WindowManagerService.localLOGV; 61import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP; 62 63import android.annotation.NonNull; 64import android.app.ActivityManager.StackId; 65import android.content.res.Configuration; 66import android.graphics.Matrix; 67import android.graphics.Rect; 68import android.graphics.RectF; 69import android.graphics.Region; 70import android.graphics.Region.Op; 71import android.hardware.display.DisplayManagerInternal; 72import android.os.Debug; 73import android.os.Handler; 74import android.os.IBinder; 75import android.util.DisplayMetrics; 76import android.util.Slog; 77import android.view.Display; 78import android.view.DisplayInfo; 79import android.view.IWindow; 80import android.view.WindowManager; 81import android.view.WindowManagerPolicy; 82 83import com.android.internal.util.FastPrintWriter; 84 85import java.io.FileDescriptor; 86import java.io.PrintWriter; 87import java.io.StringWriter; 88import java.util.ArrayList; 89import java.util.Arrays; 90import java.util.Comparator; 91import java.util.HashMap; 92import java.util.Iterator; 93import java.util.List; 94 95/** 96 * Utility class for keeping track of the WindowStates and other pertinent contents of a 97 * particular Display. 98 * 99 * IMPORTANT: No method from this class should ever be used without holding 100 * WindowManagerService.mWindowMap. 101 */ 102class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer> { 103 104 /** Unique identifier of this stack. */ 105 private final int mDisplayId; 106 107 // The display only has 2 child window containers. mTaskStackContainers which contains all 108 // window containers that are related to apps (Activities) and mNonAppWindowContainers which 109 // contains all window containers not related to apps (e.g. Status bar). 110 private final TaskStackContainers mTaskStackContainers = new TaskStackContainers(); 111 private final NonAppWindowContainers mNonAppWindowContainers = new NonAppWindowContainers(); 112 113 /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element 114 * from mDisplayWindows; */ 115 private final WindowList mWindows = new WindowList(); 116 117 // Mapping from a token IBinder to a WindowToken object on this display. 118 private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap(); 119 120 int mInitialDisplayWidth = 0; 121 int mInitialDisplayHeight = 0; 122 int mInitialDisplayDensity = 0; 123 int mBaseDisplayWidth = 0; 124 int mBaseDisplayHeight = 0; 125 int mBaseDisplayDensity = 0; 126 boolean mDisplayScalingDisabled; 127 private final DisplayInfo mDisplayInfo = new DisplayInfo(); 128 private final Display mDisplay; 129 private final DisplayMetrics mDisplayMetrics = new DisplayMetrics(); 130 131 Rect mBaseDisplayRect = new Rect(); 132 private Rect mContentRect = new Rect(); 133 134 // Accessed directly by all users. 135 private boolean mLayoutNeeded; 136 int pendingLayoutChanges; 137 final boolean isDefaultDisplay; 138 139 /** Window tokens that are in the process of exiting, but still on screen for animations. */ 140 final ArrayList<WindowToken> mExitingTokens = new ArrayList<>(); 141 142 /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack 143 * (except a future lockscreen TaskStack) moves to the top. */ 144 private TaskStack mHomeStack = null; 145 146 /** Detect user tapping outside of current focused task bounds .*/ 147 TaskTapPointerEventListener mTapDetector; 148 149 /** Detect user tapping outside of current focused stack bounds .*/ 150 private Region mTouchExcludeRegion = new Region(); 151 152 /** Save allocating when calculating rects */ 153 private final Rect mTmpRect = new Rect(); 154 private final Rect mTmpRect2 = new Rect(); 155 private final RectF mTmpRectF = new RectF(); 156 private final Matrix mTmpMatrix = new Matrix(); 157 private final Region mTmpRegion = new Region(); 158 159 final WindowManagerService mService; 160 161 /** Remove this display when animation on it has completed. */ 162 private boolean mDeferredRemoval; 163 164 final DockedStackDividerController mDividerControllerLocked; 165 166 final DimLayerController mDimLayerController; 167 168 final ArrayList<WindowState> mTapExcludedWindows = new ArrayList<>(); 169 170 /** Used when rebuilding window list to keep track of windows that have been removed. */ 171 private WindowState[] mRebuildTmp = new WindowState[20]; 172 173 private final TaskForResizePointSearchResult mTmpTaskForResizePointSearchResult = 174 new TaskForResizePointSearchResult(); 175 private final GetWindowOnDisplaySearchResult mTmpGetWindowOnDisplaySearchResult = 176 new GetWindowOnDisplaySearchResult(); 177 178 // True if this display is in the process of being removed. Used to determine if the removal of 179 // the display's direct children should be allowed. 180 private boolean mRemovingDisplay = false; 181 182 private final WindowLayersController mLayersController; 183 int mInputMethodAnimLayerAdjustment; 184 185 /** 186 * @param display May not be null. 187 * @param service You know. 188 * @param layersController window layer controller used to assign layer to the windows on this 189 * display. 190 */ 191 DisplayContent(Display display, WindowManagerService service, 192 WindowLayersController layersController) { 193 mDisplay = display; 194 mDisplayId = display.getDisplayId(); 195 mLayersController = layersController; 196 display.getDisplayInfo(mDisplayInfo); 197 display.getMetrics(mDisplayMetrics); 198 isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY; 199 mService = service; 200 initializeDisplayBaseInfo(); 201 mDividerControllerLocked = new DockedStackDividerController(service, this); 202 mDimLayerController = new DimLayerController(this); 203 204 // These are the only direct children we should ever have and they are permanent. 205 super.addChild(mTaskStackContainers, null); 206 super.addChild(mNonAppWindowContainers, null); 207 } 208 209 int getDisplayId() { 210 return mDisplayId; 211 } 212 213 WindowList getWindowList() { 214 return mWindows; 215 } 216 217 WindowToken getWindowToken(IBinder binder) { 218 return mTokenMap.get(binder); 219 } 220 221 AppWindowToken getAppWindowToken(IBinder binder) { 222 final WindowToken token = getWindowToken(binder); 223 if (token == null) { 224 return null; 225 } 226 return token.asAppWindowToken(); 227 } 228 229 void setWindowToken(IBinder binder, WindowToken token) { 230 final DisplayContent dc = mService.mRoot.getWindowTokenDisplay(token); 231 if (dc != null) { 232 // We currently don't support adding a window token to the display if the display 233 // already has the binder mapped to another token. If there is a use case for supporting 234 // this moving forward we will either need to merge the WindowTokens some how or have 235 // the binder map to a list of window tokens. 236 throw new IllegalArgumentException("Can't map token=" + token + " to display=" + this 237 + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap); 238 } 239 mTokenMap.put(binder, token); 240 241 if (token.asAppWindowToken() == null) { 242 // Add non-app token to container hierarchy on the display. App tokens are added through 243 // the parent container managing them (e.g. Tasks). 244 mNonAppWindowContainers.addChild(token, null); 245 } 246 } 247 248 WindowToken removeWindowToken(IBinder binder) { 249 final WindowToken token = mTokenMap.remove(binder); 250 if (token != null && token.asAppWindowToken() == null) { 251 mNonAppWindowContainers.removeChild(token); 252 } 253 return token; 254 } 255 256 Display getDisplay() { 257 return mDisplay; 258 } 259 260 DisplayInfo getDisplayInfo() { 261 return mDisplayInfo; 262 } 263 264 DisplayMetrics getDisplayMetrics() { 265 return mDisplayMetrics; 266 } 267 268 DockedStackDividerController getDockedDividerController() { 269 return mDividerControllerLocked; 270 } 271 272 /** 273 * Returns true if the specified UID has access to this display. 274 */ 275 boolean hasAccess(int uid) { 276 return mDisplay.hasAccess(uid); 277 } 278 279 boolean isPrivate() { 280 return (mDisplay.getFlags() & FLAG_PRIVATE) != 0; 281 } 282 283 TaskStack getHomeStack() { 284 if (mHomeStack == null && mDisplayId == DEFAULT_DISPLAY) { 285 Slog.e(TAG_WM, "getHomeStack: Returning null from this=" + this); 286 } 287 return mHomeStack; 288 } 289 290 TaskStack getStackById(int stackId) { 291 for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { 292 final TaskStack stack = mTaskStackContainers.get(i); 293 if (stack.mStackId == stackId) { 294 return stack; 295 } 296 } 297 return null; 298 } 299 300 @Override 301 void onConfigurationChanged(Configuration newParentConfig) { 302 super.onConfigurationChanged(newParentConfig); 303 304 // The display size information is heavily dependent on the resources in the current 305 // configuration, so we need to reconfigure it every time the configuration changes. 306 // See {@link PhoneWindowManager#setInitialDisplaySize}...sigh... 307 mService.reconfigureDisplayLocked(this); 308 309 getDockedDividerController().onConfigurationChanged(); 310 } 311 312 /** 313 * Callback used to trigger bounds update after configuration change and get ids of stacks whose 314 * bounds were updated. 315 */ 316 void updateStackBoundsAfterConfigChange(@NonNull List<Integer> changedStackList) { 317 for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { 318 final TaskStack stack = mTaskStackContainers.get(i); 319 if (stack.updateBoundsAfterConfigChange()) { 320 changedStackList.add(stack.mStackId); 321 } 322 } 323 } 324 325 @Override 326 boolean fillsParent() { 327 return true; 328 } 329 330 @Override 331 boolean isVisible() { 332 return true; 333 } 334 335 @Override 336 void onAppTransitionDone() { 337 super.onAppTransitionDone(); 338 rebuildAppWindowList(); 339 } 340 341 @Override 342 int getOrientation() { 343 if (mService.isStackVisibleLocked(DOCKED_STACK_ID) 344 || mService.isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) { 345 // Apps and their containers are not allowed to specify an orientation while the docked 346 // or freeform stack is visible...except for the home stack/task if the docked stack is 347 // minimized and it actually set something. 348 if (mHomeStack != null && mHomeStack.isVisible() 349 && mDividerControllerLocked.isMinimizedDock()) { 350 final int orientation = mHomeStack.getOrientation(); 351 if (orientation != SCREEN_ORIENTATION_UNSET) { 352 return orientation; 353 } 354 } 355 return SCREEN_ORIENTATION_UNSPECIFIED; 356 } 357 358 final int orientation = super.getOrientation(); 359 if (orientation != SCREEN_ORIENTATION_UNSET && orientation != SCREEN_ORIENTATION_BEHIND) { 360 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, 361 "App is requesting an orientation, return " + orientation); 362 return orientation; 363 } 364 365 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, 366 "No app is requesting an orientation, return " + mService.mLastOrientation); 367 // The next app has not been requested to be visible, so we keep the current orientation 368 // to prevent freezing/unfreezing the display too early. 369 return mService.mLastOrientation; 370 } 371 372 void updateDisplayInfo() { 373 mDisplay.getDisplayInfo(mDisplayInfo); 374 mDisplay.getMetrics(mDisplayMetrics); 375 for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { 376 mTaskStackContainers.get(i).updateDisplayInfo(null); 377 } 378 } 379 380 void initializeDisplayBaseInfo() { 381 final DisplayManagerInternal displayManagerInternal = mService.mDisplayManagerInternal; 382 if (displayManagerInternal != null) { 383 // Bootstrap the default logical display from the display manager. 384 final DisplayInfo newDisplayInfo = displayManagerInternal.getDisplayInfo(mDisplayId); 385 if (newDisplayInfo != null) { 386 mDisplayInfo.copyFrom(newDisplayInfo); 387 } 388 } 389 390 mBaseDisplayWidth = mInitialDisplayWidth = mDisplayInfo.logicalWidth; 391 mBaseDisplayHeight = mInitialDisplayHeight = mDisplayInfo.logicalHeight; 392 mBaseDisplayDensity = mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi; 393 mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight); 394 } 395 396 void getLogicalDisplayRect(Rect out) { 397 // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked. 398 final int orientation = mDisplayInfo.rotation; 399 boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270); 400 final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth; 401 final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight; 402 int width = mDisplayInfo.logicalWidth; 403 int left = (physWidth - width) / 2; 404 int height = mDisplayInfo.logicalHeight; 405 int top = (physHeight - height) / 2; 406 out.set(left, top, left + width, top + height); 407 } 408 409 private void getLogicalDisplayRect(Rect out, int orientation) { 410 getLogicalDisplayRect(out); 411 412 // Rotate the Rect if needed. 413 final int currentRotation = mDisplayInfo.rotation; 414 final int rotationDelta = deltaRotation(currentRotation, orientation); 415 if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) { 416 createRotationMatrix(rotationDelta, mBaseDisplayWidth, mBaseDisplayHeight, mTmpMatrix); 417 mTmpRectF.set(out); 418 mTmpMatrix.mapRect(mTmpRectF); 419 mTmpRectF.round(out); 420 } 421 } 422 423 void getContentRect(Rect out) { 424 out.set(mContentRect); 425 } 426 427 /** Refer to {@link WindowManagerService#attachStack(int, int, boolean)} */ 428 void attachStack(TaskStack stack, boolean onTop) { 429 mTaskStackContainers.attachStack(stack, onTop); 430 } 431 432 void moveStack(TaskStack stack, boolean toTop) { 433 mTaskStackContainers.moveStack(stack, toTop); 434 } 435 436 @Override 437 protected void addChild(DisplayChildWindowContainer child, 438 Comparator<DisplayChildWindowContainer> comparator) { 439 throw new UnsupportedOperationException("See DisplayChildWindowContainer"); 440 } 441 442 @Override 443 protected void addChild(DisplayChildWindowContainer child, int index) { 444 throw new UnsupportedOperationException("See DisplayChildWindowContainer"); 445 } 446 447 @Override 448 protected void removeChild(DisplayChildWindowContainer child) { 449 // Only allow removal of direct children from this display if the display is in the process 450 // of been removed. 451 if (mRemovingDisplay) { 452 super.removeChild(child); 453 return; 454 } 455 throw new UnsupportedOperationException("See DisplayChildWindowContainer"); 456 } 457 458 /** 459 * Propagate the new bounds to all child stacks. 460 * @param contentRect The bounds to apply at the top level. 461 */ 462 void resize(Rect contentRect) { 463 mContentRect.set(contentRect); 464 } 465 466 int taskIdFromPoint(int x, int y) { 467 for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { 468 final TaskStack stack = mTaskStackContainers.get(stackNdx); 469 final int taskId = stack.taskIdFromPoint(x, y); 470 if (taskId != -1) { 471 return taskId; 472 } 473 } 474 return -1; 475 } 476 477 /** 478 * Find the task whose outside touch area (for resizing) (x, y) falls within. 479 * Returns null if the touch doesn't fall into a resizing area. 480 */ 481 Task findTaskForResizePoint(int x, int y) { 482 final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics); 483 mTmpTaskForResizePointSearchResult.reset(); 484 for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { 485 final TaskStack stack = mTaskStackContainers.get(stackNdx); 486 if (!StackId.isTaskResizeAllowed(stack.mStackId)) { 487 return null; 488 } 489 490 stack.findTaskForResizePoint(x, y, delta, mTmpTaskForResizePointSearchResult); 491 if (mTmpTaskForResizePointSearchResult.searchDone) { 492 return mTmpTaskForResizePointSearchResult.taskForResize; 493 } 494 } 495 return null; 496 } 497 498 void setTouchExcludeRegion(Task focusedTask) { 499 mTouchExcludeRegion.set(mBaseDisplayRect); 500 final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics); 501 mTmpRect2.setEmpty(); 502 for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { 503 final TaskStack stack = mTaskStackContainers.get(stackNdx); 504 stack.setTouchExcludeRegion( 505 focusedTask, delta, mTouchExcludeRegion, mContentRect, mTmpRect2); 506 } 507 // If we removed the focused task above, add it back and only leave its 508 // outside touch area in the exclusion. TapDectector is not interested in 509 // any touch inside the focused task itself. 510 if (!mTmpRect2.isEmpty()) { 511 mTouchExcludeRegion.op(mTmpRect2, Region.Op.UNION); 512 } 513 final WindowState inputMethod = mService.mInputMethodWindow; 514 if (inputMethod != null && inputMethod.isVisibleLw()) { 515 // If the input method is visible and the user is typing, we don't want these touch 516 // events to be intercepted and used to change focus. This would likely cause a 517 // disappearance of the input method. 518 inputMethod.getTouchableRegion(mTmpRegion); 519 mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION); 520 } 521 for (int i = mTapExcludedWindows.size() - 1; i >= 0; i--) { 522 WindowState win = mTapExcludedWindows.get(i); 523 win.getTouchableRegion(mTmpRegion); 524 mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION); 525 } 526 if (getDockedStackVisibleForUserLocked() != null) { 527 mDividerControllerLocked.getTouchRegion(mTmpRect); 528 mTmpRegion.set(mTmpRect); 529 mTouchExcludeRegion.op(mTmpRegion, Op.UNION); 530 } 531 if (mTapDetector != null) { 532 mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion); 533 } 534 } 535 536 void switchUser() { 537 final WindowList windows = getWindowList(); 538 for (int i = 0; i < windows.size(); i++) { 539 final WindowState win = windows.get(i); 540 if (win.isHiddenFromUserLocked()) { 541 if (DEBUG_VISIBILITY) Slog.w(TAG_WM, "user changing, hiding " + win 542 + ", attrs=" + win.mAttrs.type + ", belonging to " + win.mOwnerUid); 543 win.hideLw(false); 544 } 545 } 546 547 for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { 548 mTaskStackContainers.get(stackNdx).switchUser(); 549 } 550 551 rebuildAppWindowList(); 552 } 553 554 void resetAnimationBackgroundAnimator() { 555 for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { 556 mTaskStackContainers.get(stackNdx).resetAnimationBackgroundAnimator(); 557 } 558 } 559 560 boolean animateDimLayers() { 561 return mDimLayerController.animateDimLayers(); 562 } 563 564 void resetDimming() { 565 mDimLayerController.resetDimming(); 566 } 567 568 boolean isDimming() { 569 return mDimLayerController.isDimming(); 570 } 571 572 void stopDimmingIfNeeded() { 573 mDimLayerController.stopDimmingIfNeeded(); 574 } 575 576 @Override 577 void removeIfPossible() { 578 if (isAnimating()) { 579 mDeferredRemoval = true; 580 return; 581 } 582 removeImmediately(); 583 } 584 585 @Override 586 void removeImmediately() { 587 mRemovingDisplay = true; 588 try { 589 super.removeImmediately(); 590 if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this); 591 mDimLayerController.close(); 592 if (mDisplayId == DEFAULT_DISPLAY) { 593 mService.unregisterPointerEventListener(mTapDetector); 594 mService.unregisterPointerEventListener(mService.mMousePositionTracker); 595 } 596 } finally { 597 mRemovingDisplay = false; 598 } 599 } 600 601 /** Returns true if a removal action is still being deferred. */ 602 @Override 603 boolean checkCompleteDeferredRemoval() { 604 final boolean stillDeferringRemoval = super.checkCompleteDeferredRemoval(); 605 606 if (!stillDeferringRemoval && mDeferredRemoval) { 607 removeImmediately(); 608 mService.onDisplayRemoved(mDisplayId); 609 return false; 610 } 611 return true; 612 } 613 614 boolean animateForIme(float interpolatedValue, float animationTarget, 615 float dividerAnimationTarget) { 616 boolean updated = false; 617 618 for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { 619 final TaskStack stack = mTaskStackContainers.get(i); 620 if (stack == null || !stack.isAdjustedForIme()) { 621 continue; 622 } 623 624 if (interpolatedValue >= 1f && animationTarget == 0f && dividerAnimationTarget == 0f) { 625 stack.resetAdjustedForIme(true /* adjustBoundsNow */); 626 updated = true; 627 } else { 628 mDividerControllerLocked.mLastAnimationProgress = 629 mDividerControllerLocked.getInterpolatedAnimationValue(interpolatedValue); 630 mDividerControllerLocked.mLastDividerProgress = 631 mDividerControllerLocked.getInterpolatedDividerValue(interpolatedValue); 632 updated |= stack.updateAdjustForIme( 633 mDividerControllerLocked.mLastAnimationProgress, 634 mDividerControllerLocked.mLastDividerProgress, 635 false /* force */); 636 } 637 if (interpolatedValue >= 1f) { 638 stack.endImeAdjustAnimation(); 639 } 640 } 641 642 return updated; 643 } 644 645 boolean clearImeAdjustAnimation() { 646 boolean changed = false; 647 for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { 648 final TaskStack stack = mTaskStackContainers.get(i); 649 if (stack != null && stack.isAdjustedForIme()) { 650 stack.resetAdjustedForIme(true /* adjustBoundsNow */); 651 changed = true; 652 } 653 } 654 return changed; 655 } 656 657 void beginImeAdjustAnimation() { 658 for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { 659 final TaskStack stack = mTaskStackContainers.get(i); 660 if (stack.isVisible() && stack.isAdjustedForIme()) { 661 stack.beginImeAdjustAnimation(); 662 } 663 } 664 } 665 666 void adjustForImeIfNeeded() { 667 final WindowState imeWin = mService.mInputMethodWindow; 668 final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw() 669 && !mDividerControllerLocked.isImeHideRequested(); 670 final boolean dockVisible = mService.isStackVisibleLocked(DOCKED_STACK_ID); 671 final TaskStack imeTargetStack = mService.getImeFocusStackLocked(); 672 final int imeDockSide = (dockVisible && imeTargetStack != null) ? 673 imeTargetStack.getDockSide() : DOCKED_INVALID; 674 final boolean imeOnTop = (imeDockSide == DOCKED_TOP); 675 final boolean imeOnBottom = (imeDockSide == DOCKED_BOTTOM); 676 final boolean dockMinimized = mDividerControllerLocked.isMinimizedDock(); 677 final int imeHeight = mService.mPolicy.getInputMethodWindowVisibleHeightLw(); 678 final boolean imeHeightChanged = imeVisible && 679 imeHeight != mDividerControllerLocked.getImeHeightAdjustedFor(); 680 681 // The divider could be adjusted for IME position, or be thinner than usual, 682 // or both. There are three possible cases: 683 // - If IME is visible, and focus is on top, divider is not moved for IME but thinner. 684 // - If IME is visible, and focus is on bottom, divider is moved for IME and thinner. 685 // - If IME is not visible, divider is not moved and is normal width. 686 687 if (imeVisible && dockVisible && (imeOnTop || imeOnBottom) && !dockMinimized) { 688 for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { 689 final TaskStack stack = mTaskStackContainers.get(i); 690 final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM; 691 if (stack.isVisible() && (imeOnBottom || isDockedOnBottom)) { 692 stack.setAdjustedForIme(imeWin, imeOnBottom && imeHeightChanged); 693 } else { 694 stack.resetAdjustedForIme(false); 695 } 696 } 697 mDividerControllerLocked.setAdjustedForIme( 698 imeOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin, imeHeight); 699 } else { 700 for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { 701 final TaskStack stack = mTaskStackContainers.get(i); 702 stack.resetAdjustedForIme(!dockVisible); 703 } 704 mDividerControllerLocked.setAdjustedForIme( 705 false /*ime*/, false /*divider*/, dockVisible /*animate*/, imeWin, imeHeight); 706 } 707 } 708 709 void setInputMethodAnimLayerAdjustment(int adj) { 710 if (DEBUG_LAYERS) Slog.v(TAG_WM, "Setting im layer adj to " + adj); 711 mInputMethodAnimLayerAdjustment = adj; 712 final WindowState imw = mService.mInputMethodWindow; 713 if (imw != null) { 714 imw.adjustAnimLayer(adj); 715 } 716 for (int i = mService.mInputMethodDialogs.size() - 1; i >= 0; i--) { 717 final WindowState dialog = mService.mInputMethodDialogs.get(i); 718 // TODO: This and other places setting mAnimLayer can probably use WS.adjustAnimLayer, 719 // but need to make sure we are not setting things twice for child windows that are 720 // already in the list. 721 dialog.mWinAnimator.mAnimLayer = dialog.mLayer + adj; 722 if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + imw 723 + " anim layer: " + dialog.mWinAnimator.mAnimLayer); 724 } 725 } 726 727 /** 728 * If a window that has an animation specifying a colored background and the current wallpaper 729 * is visible, then the color goes *below* the wallpaper so we don't cause the wallpaper to 730 * suddenly disappear. 731 */ 732 int getLayerForAnimationBackground(WindowStateAnimator winAnimator) { 733 for (int i = mWindows.size() - 1; i >= 0; --i) { 734 final WindowState win = mWindows.get(i); 735 if (win.mIsWallpaper && win.isVisibleNow()) { 736 return win.mWinAnimator.mAnimLayer; 737 } 738 } 739 return winAnimator.mAnimLayer; 740 } 741 742 void prepareFreezingTaskBounds() { 743 for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { 744 final TaskStack stack = mTaskStackContainers.get(stackNdx); 745 stack.prepareFreezingTaskBounds(); 746 } 747 } 748 749 void rotateBounds(int oldRotation, int newRotation, Rect bounds) { 750 getLogicalDisplayRect(mTmpRect, newRotation); 751 752 // Compute a transform matrix to undo the coordinate space transformation, 753 // and present the window at the same physical position it previously occupied. 754 final int deltaRotation = deltaRotation(newRotation, oldRotation); 755 createRotationMatrix(deltaRotation, mTmpRect.width(), mTmpRect.height(), mTmpMatrix); 756 757 mTmpRectF.set(bounds); 758 mTmpMatrix.mapRect(mTmpRectF); 759 mTmpRectF.round(bounds); 760 } 761 762 static int deltaRotation(int oldRotation, int newRotation) { 763 int delta = newRotation - oldRotation; 764 if (delta < 0) delta += 4; 765 return delta; 766 } 767 768 private static void createRotationMatrix(int rotation, float displayWidth, float displayHeight, 769 Matrix outMatrix) { 770 // For rotations without Z-ordering we don't need the target rectangle's position. 771 createRotationMatrix(rotation, 0 /* rectLeft */, 0 /* rectTop */, displayWidth, 772 displayHeight, outMatrix); 773 } 774 775 static void createRotationMatrix(int rotation, float rectLeft, float rectTop, 776 float displayWidth, float displayHeight, Matrix outMatrix) { 777 switch (rotation) { 778 case ROTATION_0: 779 outMatrix.reset(); 780 break; 781 case ROTATION_270: 782 outMatrix.setRotate(270, 0, 0); 783 outMatrix.postTranslate(0, displayHeight); 784 outMatrix.postTranslate(rectTop, 0); 785 break; 786 case ROTATION_180: 787 outMatrix.reset(); 788 break; 789 case ROTATION_90: 790 outMatrix.setRotate(90, 0, 0); 791 outMatrix.postTranslate(displayWidth, 0); 792 outMatrix.postTranslate(-rectTop, rectLeft); 793 break; 794 } 795 } 796 797 public void dump(String prefix, PrintWriter pw) { 798 pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId); 799 final String subPrefix = " " + prefix; 800 pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x"); 801 pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity); 802 pw.print("dpi"); 803 if (mInitialDisplayWidth != mBaseDisplayWidth 804 || mInitialDisplayHeight != mBaseDisplayHeight 805 || mInitialDisplayDensity != mBaseDisplayDensity) { 806 pw.print(" base="); 807 pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight); 808 pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi"); 809 } 810 if (mDisplayScalingDisabled) { 811 pw.println(" noscale"); 812 } 813 pw.print(" cur="); 814 pw.print(mDisplayInfo.logicalWidth); 815 pw.print("x"); pw.print(mDisplayInfo.logicalHeight); 816 pw.print(" app="); 817 pw.print(mDisplayInfo.appWidth); 818 pw.print("x"); pw.print(mDisplayInfo.appHeight); 819 pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth); 820 pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight); 821 pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth); 822 pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight); 823 pw.println(subPrefix + "deferred=" + mDeferredRemoval 824 + " mLayoutNeeded=" + mLayoutNeeded); 825 826 pw.println(); 827 pw.println(" Application tokens in top down Z order:"); 828 for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { 829 final TaskStack stack = mTaskStackContainers.get(stackNdx); 830 stack.dump(prefix + " ", pw); 831 } 832 833 pw.println(); 834 if (!mExitingTokens.isEmpty()) { 835 pw.println(); 836 pw.println(" Exiting tokens:"); 837 for (int i = mExitingTokens.size() - 1; i >= 0; i--) { 838 final WindowToken token = mExitingTokens.get(i); 839 pw.print(" Exiting #"); pw.print(i); 840 pw.print(' '); pw.print(token); 841 pw.println(':'); 842 token.dump(pw, " "); 843 } 844 } 845 pw.println(); 846 mDimLayerController.dump(prefix + " ", pw); 847 pw.println(); 848 mDividerControllerLocked.dump(prefix + " ", pw); 849 850 if (mInputMethodAnimLayerAdjustment != 0) { 851 pw.println(subPrefix 852 + "mInputMethodAnimLayerAdjustment=" + mInputMethodAnimLayerAdjustment); 853 } 854 } 855 856 @Override 857 public String toString() { 858 return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mChildren; 859 } 860 861 String getName() { 862 return "Display " + mDisplayId + " name=\"" + mDisplayInfo.name + "\""; 863 } 864 865 /** 866 * @return The docked stack, but only if it is visible, and {@code null} otherwise. 867 */ 868 TaskStack getDockedStackLocked() { 869 final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID); 870 return (stack != null && stack.isVisible()) ? stack : null; 871 } 872 873 /** 874 * Like {@link #getDockedStackLocked}, but also returns the docked stack if it's currently not 875 * visible, as long as it's not hidden because the current user doesn't have any tasks there. 876 */ 877 TaskStack getDockedStackVisibleForUserLocked() { 878 final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID); 879 return (stack != null && stack.isVisible(true /* ignoreKeyguard */)) ? stack : null; 880 } 881 882 /** Find the visible, touch-deliverable window under the given point */ 883 WindowState getTouchableWinAtPointLocked(float xf, float yf) { 884 WindowState touchedWin = null; 885 final int x = (int) xf; 886 final int y = (int) yf; 887 888 for (int i = mWindows.size() - 1; i >= 0; i--) { 889 WindowState window = mWindows.get(i); 890 final int flags = window.mAttrs.flags; 891 if (!window.isVisibleLw()) { 892 continue; 893 } 894 if ((flags & FLAG_NOT_TOUCHABLE) != 0) { 895 continue; 896 } 897 898 window.getVisibleBounds(mTmpRect); 899 if (!mTmpRect.contains(x, y)) { 900 continue; 901 } 902 903 window.getTouchableRegion(mTmpRegion); 904 905 final int touchFlags = flags & (FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL); 906 if (mTmpRegion.contains(x, y) || touchFlags == 0) { 907 touchedWin = window; 908 break; 909 } 910 } 911 912 return touchedWin; 913 } 914 915 boolean canAddToastWindowForUid(int uid) { 916 // We allow one toast window per UID being shown at a time. 917 WindowList windows = getWindowList(); 918 final int windowCount = windows.size(); 919 for (int i = 0; i < windowCount; i++) { 920 WindowState window = windows.get(i); 921 if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == uid 922 && !window.mPermanentlyHidden && !window.mAnimatingExit 923 && !window.mRemoveOnExit) { 924 return false; 925 } 926 } 927 return true; 928 } 929 930 void scheduleToastWindowsTimeoutIfNeededLocked(WindowState oldFocus, WindowState newFocus) { 931 if (oldFocus == null || (newFocus != null && newFocus.mOwnerUid == oldFocus.mOwnerUid)) { 932 return; 933 } 934 final int lostFocusUid = oldFocus.mOwnerUid; 935 final WindowList windows = getWindowList(); 936 final int windowCount = windows.size(); 937 final Handler handler = mService.mH; 938 for (int i = 0; i < windowCount; i++) { 939 final WindowState window = windows.get(i); 940 if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == lostFocusUid) { 941 if (!handler.hasMessages(WINDOW_HIDE_TIMEOUT, window)) { 942 handler.sendMessageDelayed(handler.obtainMessage(WINDOW_HIDE_TIMEOUT, window), 943 window.mAttrs.hideTimeoutMilliseconds); 944 } 945 } 946 } 947 } 948 949 WindowState findFocusedWindow() { 950 final AppWindowToken focusedApp = mService.mFocusedApp; 951 952 for (int i = mWindows.size() - 1; i >= 0; i--) { 953 final WindowState win = mWindows.get(i); 954 955 if (DEBUG_FOCUS) Slog.v(TAG_WM, "Looking for focus: " + i + " = " + win 956 + ", flags=" + win.mAttrs.flags + ", canReceive=" + win.canReceiveKeys()); 957 958 if (!win.canReceiveKeys()) { 959 continue; 960 } 961 962 final AppWindowToken wtoken = win.mAppToken; 963 964 // If this window's application has been removed, just skip it. 965 if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) { 966 if (DEBUG_FOCUS) Slog.v(TAG_WM, "Skipping " + wtoken + " because " 967 + (wtoken.removed ? "removed" : "sendingToBottom")); 968 continue; 969 } 970 971 if (focusedApp == null) { 972 if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp=null" 973 + " using new focus @ " + i + " = " + win); 974 return win; 975 } 976 977 if (!focusedApp.windowsAreFocusable()) { 978 // Current focused app windows aren't focusable... 979 if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp windows not" 980 + " focusable using new focus @ " + i + " = " + win); 981 return win; 982 } 983 984 // Descend through all of the app tokens and find the first that either matches 985 // win.mAppToken (return win) or mFocusedApp (return null). 986 if (wtoken != null && win.mAttrs.type != TYPE_APPLICATION_STARTING) { 987 if (focusedApp.compareTo(wtoken) > 0) { 988 // App stack below focused app stack. No focus for you!!! 989 if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, 990 "findFocusedWindow: Reached focused app=" + focusedApp); 991 return null; 992 } 993 } 994 995 if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: Found new focus @ " 996 + i + " = " + win); 997 return win; 998 } 999 1000 if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: No focusable windows."); 1001 return null; 1002 } 1003 1004 int addAppWindowToWindowList(final WindowState win) { 1005 final IWindow client = win.mClient; 1006 1007 WindowList tokenWindowList = getTokenWindowsOnDisplay(win.mToken); 1008 if (!tokenWindowList.isEmpty()) { 1009 return addAppWindowExisting(win, tokenWindowList); 1010 } 1011 1012 // No windows from this token on this display 1013 if (localLOGV) Slog.v(TAG_WM, "Figuring out where to add app window " 1014 + client.asBinder() + " (token=" + this + ")"); 1015 1016 final WindowToken wToken = win.mToken; 1017 1018 // Figure out where the window should go, based on the order of applications. 1019 mTmpGetWindowOnDisplaySearchResult.reset(); 1020 for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { 1021 final TaskStack stack = mTaskStackContainers.get(i); 1022 stack.getWindowOnDisplayBeforeToken(this, wToken, mTmpGetWindowOnDisplaySearchResult); 1023 if (mTmpGetWindowOnDisplaySearchResult.reachedToken) { 1024 // We have reach the token we are interested in. End search. 1025 break; 1026 } 1027 } 1028 1029 WindowState pos = mTmpGetWindowOnDisplaySearchResult.foundWindow; 1030 1031 // We now know the index into the apps. If we found an app window above, that gives us the 1032 // position; else we need to look some more. 1033 if (pos != null) { 1034 // Move behind any windows attached to this one. 1035 final WindowToken atoken = getWindowToken(pos.mClient.asBinder()); 1036 if (atoken != null) { 1037 tokenWindowList = getTokenWindowsOnDisplay(atoken); 1038 final int NC = tokenWindowList.size(); 1039 if (NC > 0) { 1040 WindowState bottom = tokenWindowList.get(0); 1041 if (bottom.mSubLayer < 0) { 1042 pos = bottom; 1043 } 1044 } 1045 } 1046 addWindowToListBefore(win, pos); 1047 return 0; 1048 } 1049 1050 // Continue looking down until we find the first token that has windows on this display. 1051 mTmpGetWindowOnDisplaySearchResult.reset(); 1052 for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) { 1053 final TaskStack stack = mTaskStackContainers.get(i); 1054 stack.getWindowOnDisplayAfterToken(this, wToken, mTmpGetWindowOnDisplaySearchResult); 1055 if (mTmpGetWindowOnDisplaySearchResult.foundWindow != null) { 1056 // We have found a window after the token. End search. 1057 break; 1058 } 1059 } 1060 1061 pos = mTmpGetWindowOnDisplaySearchResult.foundWindow; 1062 1063 if (pos != null) { 1064 // Move in front of any windows attached to this one. 1065 final WindowToken atoken = getWindowToken(pos.mClient.asBinder()); 1066 if (atoken != null) { 1067 final WindowState top = atoken.getTopWindow(); 1068 if (top != null && top.mSubLayer >= 0) { 1069 pos = top; 1070 } 1071 } 1072 addWindowToListAfter(win, pos); 1073 return 0; 1074 } 1075 1076 // Just search for the start of this layer. 1077 final int myLayer = win.mBaseLayer; 1078 int i; 1079 for (i = mWindows.size() - 1; i >= 0; --i) { 1080 final WindowState w = mWindows.get(i); 1081 // Dock divider shares the base layer with application windows, but we want to always 1082 // keep it above the application windows. The sharing of the base layer is intended 1083 // for window animations, which need to be above the dock divider for the duration 1084 // of the animation. 1085 if (w.mBaseLayer <= myLayer && w.mAttrs.type != TYPE_DOCK_DIVIDER) { 1086 break; 1087 } 1088 } 1089 if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, 1090 "Based on layer: Adding window " + win + " at " + (i + 1) + " of " 1091 + mWindows.size()); 1092 mWindows.add(i + 1, win); 1093 mService.mWindowsChanged = true; 1094 return 0; 1095 } 1096 1097 /** Adds this non-app window to the window list. */ 1098 void addNonAppWindowToWindowList(WindowState win) { 1099 // Figure out where window should go, based on layer. 1100 int i; 1101 for (i = mWindows.size() - 1; i >= 0; i--) { 1102 final WindowState otherWin = mWindows.get(i); 1103 if (otherWin.getBaseType() != TYPE_WALLPAPER && otherWin.mBaseLayer <= win.mBaseLayer) { 1104 // Wallpaper wanders through the window list, for example to position itself 1105 // directly behind keyguard. Because of this it will break the ordering based on 1106 // WindowState.mBaseLayer. There might windows with higher mBaseLayer behind it and 1107 // we don't want the new window to appear above them. An example of this is adding 1108 // of the docked stack divider. Consider a scenario with the following ordering (top 1109 // to bottom): keyguard, wallpaper, assist preview, apps. We want the dock divider 1110 // to land below the assist preview, so the dock divider must ignore the wallpaper, 1111 // with which it shares the base layer. 1112 break; 1113 } 1114 } 1115 1116 i++; 1117 if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, 1118 "Free window: Adding window " + this + " at " + i + " of " + mWindows.size()); 1119 mWindows.add(i, win); 1120 mService.mWindowsChanged = true; 1121 } 1122 1123 void addToWindowList(WindowState win, int index) { 1124 mWindows.add(index, win); 1125 } 1126 1127 boolean removeFromWindowList(WindowState win) { 1128 return mWindows.remove(win); 1129 } 1130 1131 private int removeWindowAndChildrenFromWindowList(WindowState win, int interestingPos) { 1132 final WindowList windows = getWindowList(); 1133 int wpos = windows.indexOf(win); 1134 if (wpos < 0) { 1135 return interestingPos; 1136 } 1137 1138 if (wpos < interestingPos) interestingPos--; 1139 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Temp removing at " + wpos + ": " + this); 1140 windows.remove(wpos); 1141 mService.mWindowsChanged = true; 1142 int childWinCount = win.mChildren.size(); 1143 while (childWinCount > 0) { 1144 childWinCount--; 1145 final WindowState cw = win.mChildren.get(childWinCount); 1146 int cpos = windows.indexOf(cw); 1147 if (cpos >= 0) { 1148 if (cpos < interestingPos) interestingPos--; 1149 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, 1150 "Temp removing child at " + cpos + ": " + cw); 1151 windows.remove(cpos); 1152 } 1153 } 1154 return interestingPos; 1155 } 1156 1157 void addChildWindowToWindowList(WindowState win) { 1158 final WindowState parentWindow = win.getParentWindow(); 1159 1160 WindowList windowsOnSameDisplay = getTokenWindowsOnDisplay(win.mToken); 1161 1162 // Figure out this window's ordering relative to the parent window. 1163 final int wCount = windowsOnSameDisplay.size(); 1164 final int sublayer = win.mSubLayer; 1165 int largestSublayer = Integer.MIN_VALUE; 1166 WindowState windowWithLargestSublayer = null; 1167 int i; 1168 for (i = 0; i < wCount; i++) { 1169 WindowState w = windowsOnSameDisplay.get(i); 1170 final int wSublayer = w.mSubLayer; 1171 if (wSublayer >= largestSublayer) { 1172 largestSublayer = wSublayer; 1173 windowWithLargestSublayer = w; 1174 } 1175 if (sublayer < 0) { 1176 // For negative sublayers, we go below all windows in the same sublayer. 1177 if (wSublayer >= sublayer) { 1178 addWindowToListBefore(win, wSublayer >= 0 ? parentWindow : w); 1179 break; 1180 } 1181 } else { 1182 // For positive sublayers, we go above all windows in the same sublayer. 1183 if (wSublayer > sublayer) { 1184 addWindowToListBefore(win, w); 1185 break; 1186 } 1187 } 1188 } 1189 if (i >= wCount) { 1190 if (sublayer < 0) { 1191 addWindowToListBefore(win, parentWindow); 1192 } else { 1193 addWindowToListAfter(win, 1194 largestSublayer >= 0 ? windowWithLargestSublayer : parentWindow); 1195 } 1196 } 1197 } 1198 1199 /** Updates the layer assignment of windows on this display. */ 1200 void assignWindowLayers(boolean setLayoutNeeded) { 1201 mLayersController.assignWindowLayers(mWindows); 1202 if (setLayoutNeeded) { 1203 setLayoutNeeded(); 1204 } 1205 } 1206 1207 /** 1208 * Z-orders the display window list so that: 1209 * <ul> 1210 * <li>Any windows that are currently below the wallpaper window stay below the wallpaper 1211 * window. 1212 * <li>Exiting application windows are at the bottom, but above the wallpaper window. 1213 * <li>All other application windows are above the exiting application windows and ordered based 1214 * on the ordering of their stacks and tasks on the display. 1215 * <li>Non-application windows are at the very top. 1216 * </ul> 1217 * <p> 1218 * NOTE: This isn't a complete picture of what the user see. Further manipulation of the window 1219 * surface layering is done in {@link WindowLayersController}. 1220 */ 1221 void rebuildAppWindowList() { 1222 int count = mWindows.size(); 1223 int i; 1224 int lastBelow = -1; 1225 int numRemoved = 0; 1226 1227 if (mRebuildTmp.length < count) { 1228 mRebuildTmp = new WindowState[count + 10]; 1229 } 1230 1231 // First remove all existing app windows. 1232 i = 0; 1233 while (i < count) { 1234 final WindowState w = mWindows.get(i); 1235 if (w.mAppToken != null) { 1236 final WindowState win = mWindows.remove(i); 1237 win.mRebuilding = true; 1238 mRebuildTmp[numRemoved] = win; 1239 mService.mWindowsChanged = true; 1240 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Rebuild removing window: " + win); 1241 count--; 1242 numRemoved++; 1243 continue; 1244 } else if (lastBelow == i-1) { 1245 if (w.mAttrs.type == TYPE_WALLPAPER) { 1246 lastBelow = i; 1247 } 1248 } 1249 i++; 1250 } 1251 1252 // Keep whatever windows were below the app windows still below, by skipping them. 1253 lastBelow++; 1254 i = lastBelow; 1255 1256 // First add all of the exiting app tokens... these are no longer in the main app list, 1257 // but still have windows shown. We put them in the back because now that the animation is 1258 // over we no longer will care about them. 1259 final int numStacks = mTaskStackContainers.size(); 1260 for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { 1261 AppTokenList exitingAppTokens = mTaskStackContainers.get(stackNdx).mExitingAppTokens; 1262 int NT = exitingAppTokens.size(); 1263 for (int j = 0; j < NT; j++) { 1264 i = exitingAppTokens.get(j).rebuildWindowListUnchecked(i); 1265 } 1266 } 1267 1268 // And add in the still active app tokens in Z order. 1269 for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { 1270 i = mTaskStackContainers.get(stackNdx).rebuildWindowList(i); 1271 } 1272 1273 i -= lastBelow; 1274 if (i != numRemoved) { 1275 setLayoutNeeded(); 1276 Slog.w(TAG_WM, "On display=" + mDisplayId + " Rebuild removed " + numRemoved 1277 + " windows but added " + i + " rebuildAppWindowListLocked() " 1278 + " callers=" + Debug.getCallers(10)); 1279 for (i = 0; i < numRemoved; i++) { 1280 WindowState ws = mRebuildTmp[i]; 1281 if (ws.mRebuilding) { 1282 StringWriter sw = new StringWriter(); 1283 PrintWriter pw = new FastPrintWriter(sw, false, 1024); 1284 ws.dump(pw, "", true); 1285 pw.flush(); 1286 Slog.w(TAG_WM, "This window was lost: " + ws); 1287 Slog.w(TAG_WM, sw.toString()); 1288 ws.mWinAnimator.destroySurfaceLocked(); 1289 } 1290 } 1291 Slog.w(TAG_WM, "Current window hierarchy:"); 1292 dumpChildrenNames(); 1293 Slog.w(TAG_WM, "Final window list:"); 1294 dumpWindows(); 1295 } 1296 Arrays.fill(mRebuildTmp, null); 1297 } 1298 1299 /** Return the list of Windows on this display associated with the input token. */ 1300 WindowList getTokenWindowsOnDisplay(WindowToken token) { 1301 final WindowList windowList = new WindowList(); 1302 final int count = mWindows.size(); 1303 for (int i = 0; i < count; i++) { 1304 final WindowState win = mWindows.get(i); 1305 if (win.mToken == token) { 1306 windowList.add(win); 1307 } 1308 } 1309 return windowList; 1310 } 1311 1312 private void reAddToWindowList(WindowState win) { 1313 win.mToken.addWindow(win); 1314 // This is a hack to get all of the child windows added as well at the right position. Child 1315 // windows should be rare and this case should be rare, so it shouldn't be that big a deal. 1316 int wpos = mWindows.indexOf(win); 1317 if (wpos >= 0) { 1318 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "ReAdd removing from " + wpos + ": " + win); 1319 mWindows.remove(wpos); 1320 mService.mWindowsChanged = true; 1321 win.reAddWindow(wpos); 1322 } 1323 } 1324 1325 void moveInputMethodDialogs(int pos) { 1326 ArrayList<WindowState> dialogs = mService.mInputMethodDialogs; 1327 1328 final int N = dialogs.size(); 1329 if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Removing " + N + " dialogs w/pos=" + pos); 1330 for (int i = 0; i < N; i++) { 1331 pos = removeWindowAndChildrenFromWindowList(dialogs.get(i), pos); 1332 } 1333 if (DEBUG_INPUT_METHOD) { 1334 Slog.v(TAG_WM, "Window list w/pos=" + pos); 1335 logWindowList(mWindows, " "); 1336 } 1337 1338 WindowState ime = mService.mInputMethodWindow; 1339 if (pos >= 0) { 1340 // Skip windows owned by the input method. 1341 if (ime != null) { 1342 while (pos < mWindows.size()) { 1343 WindowState wp = mWindows.get(pos); 1344 if (wp == ime || wp.getParentWindow() == ime) { 1345 pos++; 1346 continue; 1347 } 1348 break; 1349 } 1350 } 1351 if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Adding " + N + " dialogs at pos=" + pos); 1352 for (int i=0; i<N; i++) { 1353 WindowState win = dialogs.get(i); 1354 pos = win.reAddWindow(pos); 1355 } 1356 if (DEBUG_INPUT_METHOD) { 1357 Slog.v(TAG_WM, "Final window list:"); 1358 logWindowList(mWindows, " "); 1359 } 1360 return; 1361 } 1362 for (int i=0; i<N; i++) { 1363 WindowState win = dialogs.get(i); 1364 reAddToWindowList(win); 1365 if (DEBUG_INPUT_METHOD) { 1366 Slog.v(TAG_WM, "No IM target, final list:"); 1367 logWindowList(mWindows, " "); 1368 } 1369 } 1370 } 1371 1372 boolean moveInputMethodWindowsIfNeeded(boolean needAssignLayers) { 1373 final WindowState imWin = mService.mInputMethodWindow; 1374 final int DN = mService.mInputMethodDialogs.size(); 1375 if (imWin == null && DN == 0) { 1376 return false; 1377 } 1378 1379 // TODO(multidisplay): IMEs are only supported on the default display. 1380 WindowList windows = mWindows; 1381 1382 int imPos = findDesiredInputMethodWindowIndex(true); 1383 if (imPos >= 0) { 1384 // In this case, the input method windows are to be placed 1385 // immediately above the window they are targeting. 1386 1387 // First check to see if the input method windows are already 1388 // located here, and contiguous. 1389 final int N = windows.size(); 1390 final WindowState firstImWin = imPos < N ? windows.get(imPos) : null; 1391 1392 // Figure out the actual input method window that should be 1393 // at the bottom of their stack. 1394 WindowState baseImWin = imWin != null ? imWin : mService.mInputMethodDialogs.get(0); 1395 final WindowState cw = baseImWin.getBottomChild(); 1396 if (cw != null && cw.mSubLayer < 0) { 1397 baseImWin = cw; 1398 } 1399 1400 if (firstImWin == baseImWin) { 1401 // The windows haven't moved... but are they still contiguous? 1402 // First find the top IM window. 1403 int pos = imPos+1; 1404 while (pos < N) { 1405 if (!(windows.get(pos)).mIsImWindow) { 1406 break; 1407 } 1408 pos++; 1409 } 1410 pos++; 1411 // Now there should be no more input method windows above. 1412 while (pos < N) { 1413 if ((windows.get(pos)).mIsImWindow) { 1414 break; 1415 } 1416 pos++; 1417 } 1418 if (pos >= N) { 1419 return false; 1420 } 1421 } 1422 1423 if (imWin != null) { 1424 if (DEBUG_INPUT_METHOD) { 1425 Slog.v(TAG_WM, "Moving IM from " + imPos); 1426 logWindowList(windows, " "); 1427 } 1428 imPos = removeWindowAndChildrenFromWindowList(imWin, imPos); 1429 if (DEBUG_INPUT_METHOD) { 1430 Slog.v(TAG_WM, "List after removing with new pos " + imPos + ":"); 1431 logWindowList(windows, " "); 1432 } 1433 imWin.reAddWindow(imPos); 1434 if (DEBUG_INPUT_METHOD) { 1435 Slog.v(TAG_WM, "List after moving IM to " + imPos + ":"); 1436 logWindowList(windows, " "); 1437 } 1438 if (DN > 0) moveInputMethodDialogs(imPos+1); 1439 } else { 1440 moveInputMethodDialogs(imPos); 1441 } 1442 1443 } else { 1444 // In this case, the input method windows go in a fixed layer, 1445 // because they aren't currently associated with a focus window. 1446 1447 if (imWin != null) { 1448 if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Moving IM from " + imPos); 1449 removeWindowAndChildrenFromWindowList(imWin, 0); 1450 reAddToWindowList(imWin); 1451 if (DEBUG_INPUT_METHOD) { 1452 Slog.v(TAG_WM, "List with no IM target:"); 1453 logWindowList(windows, " "); 1454 } 1455 if (DN > 0) moveInputMethodDialogs(-1); 1456 } else { 1457 moveInputMethodDialogs(-1); 1458 } 1459 1460 } 1461 1462 if (needAssignLayers) { 1463 assignWindowLayers(false /* setLayoutNeeded */); 1464 } 1465 1466 return true; 1467 } 1468 1469 /** 1470 * Dig through the WindowStates and find the one that the Input Method will target. 1471 * @param willMove 1472 * @return The index+1 in mWindows of the discovered target. 1473 */ 1474 int findDesiredInputMethodWindowIndex(boolean willMove) { 1475 // TODO(multidisplay): Needs some serious rethought when the target and IME are not on the 1476 // same display. Or even when the current IME/target are not on the same screen as the next 1477 // IME/target. For now only look for input windows on the main screen. 1478 final WindowList windows = getWindowList(); 1479 WindowState w = null; 1480 int i; 1481 for (i = windows.size() - 1; i >= 0; --i) { 1482 WindowState win = windows.get(i); 1483 1484 if (DEBUG_INPUT_METHOD && willMove) Slog.i(TAG_WM, "Checking window @" + i 1485 + " " + win + " fl=0x" + Integer.toHexString(win.mAttrs.flags)); 1486 if (canBeImeTarget(win)) { 1487 w = win; 1488 //Slog.i(TAG_WM, "Putting input method here!"); 1489 1490 // Yet more tricksyness! If this window is a "starting" window, we do actually want 1491 // to be on top of it, but it is not -really- where input will go. So if the caller 1492 // is not actually looking to move the IME, look down below for a real window to 1493 // target... 1494 if (!willMove && w.mAttrs.type == TYPE_APPLICATION_STARTING && i > 0) { 1495 WindowState wb = windows.get(i-1); 1496 if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) { 1497 i--; 1498 w = wb; 1499 } 1500 } 1501 break; 1502 } 1503 } 1504 1505 // Now w is either mWindows[0] or an IME (or null if mWindows is empty). 1506 1507 if (DEBUG_INPUT_METHOD && willMove) Slog.v(TAG_WM, "Proposed new IME target: " + w); 1508 1509 // Now, a special case -- if the last target's window is in the process of exiting, and is 1510 // above the new target, keep on the last target to avoid flicker. Consider for example a 1511 // Dialog with the IME shown: when the Dialog is dismissed, we want to keep the IME above it 1512 // until it is completely gone so it doesn't drop behind the dialog or its full-screen 1513 // scrim. 1514 final WindowState curTarget = mService.mInputMethodTarget; 1515 if (curTarget != null 1516 && curTarget.isDisplayedLw() 1517 && curTarget.isClosing() 1518 && (w == null || curTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer)) { 1519 if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Current target higher, not changing"); 1520 return windows.indexOf(curTarget) + 1; 1521 } 1522 1523 if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Desired input method target=" 1524 + w + " willMove=" + willMove); 1525 1526 if (willMove && w != null) { 1527 AppWindowToken token = curTarget == null ? null : curTarget.mAppToken; 1528 if (token != null) { 1529 1530 // Now some fun for dealing with window animations that modify the Z order. We need 1531 // to look at all windows below the current target that are in this app, finding the 1532 // highest visible one in layering. 1533 WindowState highestTarget = null; 1534 int highestPos = 0; 1535 if (token.mAppAnimator.animating || token.mAppAnimator.animation != null) { 1536 WindowList curWindows = token.getDisplayContent().getWindowList(); 1537 int pos = curWindows.indexOf(curTarget); 1538 while (pos >= 0) { 1539 WindowState win = curWindows.get(pos); 1540 if (win.mAppToken != token) { 1541 break; 1542 } 1543 if (!win.mRemoved) { 1544 if (highestTarget == null || win.mWinAnimator.mAnimLayer > 1545 highestTarget.mWinAnimator.mAnimLayer) { 1546 highestTarget = win; 1547 highestPos = pos; 1548 } 1549 } 1550 pos--; 1551 } 1552 } 1553 1554 if (highestTarget != null) { 1555 final AppTransition appTransition = mService.mAppTransition; 1556 if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, appTransition + " " + highestTarget 1557 + " animating=" + highestTarget.mWinAnimator.isAnimationSet() 1558 + " layer=" + highestTarget.mWinAnimator.mAnimLayer 1559 + " new layer=" + w.mWinAnimator.mAnimLayer); 1560 1561 if (appTransition.isTransitionSet()) { 1562 // If we are currently setting up for an animation, hold everything until we 1563 // can find out what will happen. 1564 mService.mInputMethodTargetWaitingAnim = true; 1565 mService.mInputMethodTarget = highestTarget; 1566 return highestPos + 1; 1567 } else if (highestTarget.mWinAnimator.isAnimationSet() && 1568 highestTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer) { 1569 // If the window we are currently targeting is involved with an animation, 1570 // and it is on top of the next target we will be over, then hold off on 1571 // moving until that is done. 1572 mService.mInputMethodTargetWaitingAnim = true; 1573 mService.mInputMethodTarget = highestTarget; 1574 return highestPos + 1; 1575 } 1576 } 1577 } 1578 } 1579 1580 //Slog.i(TAG_WM, "Placing input method @" + (i+1)); 1581 if (w != null) { 1582 if (willMove) { 1583 if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget + " to " 1584 + w + (SHOW_STACK_CRAWLS ? " Callers=" + Debug.getCallers(4) : "")); 1585 mService.mInputMethodTarget = w; 1586 mService.mInputMethodTargetWaitingAnim = false; 1587 if (w.mAppToken != null) { 1588 setInputMethodAnimLayerAdjustment( 1589 w.mAppToken.mAppAnimator.animLayerAdjustment); 1590 } else { 1591 setInputMethodAnimLayerAdjustment(0); 1592 } 1593 } 1594 1595 // If the docked divider is visible, we still need to go through this whole excercise to 1596 // find the appropriate input method target (used for animations and dialog 1597 // adjustments), but for purposes of Z ordering we simply wish to place it above the 1598 // docked divider. Unless it is already above the divider. 1599 final WindowState dockedDivider = mDividerControllerLocked.getWindow(); 1600 if (dockedDivider != null && dockedDivider.isVisibleLw()) { 1601 int dividerIndex = windows.indexOf(dockedDivider); 1602 if (dividerIndex > 0 && dividerIndex > i) { 1603 return dividerIndex + 1; 1604 } 1605 } 1606 return i+1; 1607 } 1608 if (willMove) { 1609 if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget 1610 + " to null." + (SHOW_STACK_CRAWLS ? " Callers=" + Debug.getCallers(4) : "")); 1611 mService.mInputMethodTarget = null; 1612 setInputMethodAnimLayerAdjustment(0); 1613 } 1614 return -1; 1615 } 1616 1617 private static boolean canBeImeTarget(WindowState w) { 1618 final int fl = w.mAttrs.flags & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM); 1619 final int type = w.mAttrs.type; 1620 1621 if (fl != 0 && fl != (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM) 1622 && type != TYPE_APPLICATION_STARTING) { 1623 return false; 1624 } 1625 1626 if (DEBUG_INPUT_METHOD) { 1627 Slog.i(TAG_WM, "isVisibleOrAdding " + w + ": " + w.isVisibleOrAdding()); 1628 if (!w.isVisibleOrAdding()) { 1629 Slog.i(TAG_WM, " mSurfaceController=" + w.mWinAnimator.mSurfaceController 1630 + " relayoutCalled=" + w.mRelayoutCalled 1631 + " viewVis=" + w.mViewVisibility 1632 + " policyVis=" + w.mPolicyVisibility 1633 + " policyVisAfterAnim=" + w.mPolicyVisibilityAfterAnim 1634 + " parentHidden=" + w.isParentWindowHidden() 1635 + " exiting=" + w.mAnimatingExit + " destroying=" + w.mDestroying); 1636 if (w.mAppToken != null) { 1637 Slog.i(TAG_WM, " mAppToken.hiddenRequested=" + w.mAppToken.hiddenRequested); 1638 } 1639 } 1640 } 1641 return w.isVisibleOrAdding(); 1642 } 1643 1644 private void logWindowList(final WindowList windows, String prefix) { 1645 int N = windows.size(); 1646 while (N > 0) { 1647 N--; 1648 Slog.v(TAG_WM, prefix + "#" + N + ": " + windows.get(N)); 1649 } 1650 } 1651 1652 boolean getNeedsMenu(WindowState win, WindowManagerPolicy.WindowState bottom) { 1653 int index = -1; 1654 WindowList windows = getWindowList(); 1655 while (true) { 1656 if (win.mAttrs.needsMenuKey != NEEDS_MENU_UNSET) { 1657 return win.mAttrs.needsMenuKey == NEEDS_MENU_SET_TRUE; 1658 } 1659 // If we reached the bottom of the range of windows we are considering, 1660 // assume no menu is needed. 1661 if (win == bottom) { 1662 return false; 1663 } 1664 // The current window hasn't specified whether menu key is needed; look behind it. 1665 // First, we may need to determine the starting position. 1666 if (index < 0) { 1667 index = windows.indexOf(win); 1668 } 1669 index--; 1670 if (index < 0) { 1671 return false; 1672 } 1673 win = windows.get(index); 1674 } 1675 } 1676 1677 void setLayoutNeeded() { 1678 if (DEBUG_LAYOUT) Slog.w(TAG_WM, "setLayoutNeeded: callers=" + Debug.getCallers(3)); 1679 mLayoutNeeded = true; 1680 } 1681 1682 void clearLayoutNeeded() { 1683 if (DEBUG_LAYOUT) Slog.w(TAG_WM, "clearLayoutNeeded: callers=" + Debug.getCallers(3)); 1684 mLayoutNeeded = false; 1685 } 1686 1687 boolean isLayoutNeeded() { 1688 return mLayoutNeeded; 1689 } 1690 1691 private int addAppWindowExisting(WindowState win, WindowList tokenWindowList) { 1692 1693 int tokenWindowsPos; 1694 // If this application has existing windows, we simply place the new window on top of 1695 // them... but keep the starting window on top. 1696 if (win.mAttrs.type == TYPE_BASE_APPLICATION) { 1697 // Base windows go behind everything else. 1698 final WindowState lowestWindow = tokenWindowList.get(0); 1699 addWindowToListBefore(win, lowestWindow); 1700 tokenWindowsPos = win.mToken.getWindowIndex(lowestWindow); 1701 } else { 1702 final AppWindowToken atoken = win.mAppToken; 1703 final int windowListPos = tokenWindowList.size(); 1704 final WindowState lastWindow = tokenWindowList.get(windowListPos - 1); 1705 if (atoken != null && lastWindow == atoken.startingWindow) { 1706 addWindowToListBefore(win, lastWindow); 1707 tokenWindowsPos = win.mToken.getWindowIndex(lastWindow); 1708 } else { 1709 int newIdx = findIdxBasedOnAppTokens(win); 1710 // There is a window above this one associated with the same apptoken note that the 1711 // window could be a floating window that was created later or a window at the top 1712 // of the list of windows associated with this token. 1713 if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, 1714 "not Base app: Adding window " + win + " at " + (newIdx + 1) + " of " 1715 + mWindows.size()); 1716 mWindows.add(newIdx + 1, win); 1717 if (newIdx < 0) { 1718 // No window from token found on win's display. 1719 tokenWindowsPos = 0; 1720 } else { 1721 tokenWindowsPos = win.mToken.getWindowIndex(mWindows.get(newIdx)) + 1; 1722 } 1723 mService.mWindowsChanged = true; 1724 } 1725 } 1726 return tokenWindowsPos; 1727 } 1728 1729 /** Places the first input window after the second input window in the window list. */ 1730 private void addWindowToListAfter(WindowState first, WindowState second) { 1731 final int i = mWindows.indexOf(second); 1732 if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, 1733 "Adding window " + this + " at " + (i + 1) + " of " + mWindows.size() 1734 + " (after " + second + ")"); 1735 mWindows.add(i + 1, first); 1736 mService.mWindowsChanged = true; 1737 } 1738 1739 /** Places the first input window before the second input window in the window list. */ 1740 private void addWindowToListBefore(WindowState first, WindowState second) { 1741 int i = mWindows.indexOf(second); 1742 if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, 1743 "Adding window " + this + " at " + i + " of " + mWindows.size() 1744 + " (before " + second + ")"); 1745 if (i < 0) { 1746 Slog.w(TAG_WM, "addWindowToListBefore: Unable to find " + second + " in " + mWindows); 1747 i = 0; 1748 } 1749 mWindows.add(i, first); 1750 mService.mWindowsChanged = true; 1751 } 1752 1753 /** 1754 * This method finds out the index of a window that has the same app token as win. used for z 1755 * ordering the windows in mWindows 1756 */ 1757 private int findIdxBasedOnAppTokens(WindowState win) { 1758 for(int j = mWindows.size() - 1; j >= 0; j--) { 1759 final WindowState wentry = mWindows.get(j); 1760 if(wentry.mAppToken == win.mAppToken) { 1761 return j; 1762 } 1763 } 1764 return -1; 1765 } 1766 1767 private void dumpChildrenNames() { 1768 StringBuilder output = new StringBuilder(); 1769 dumpChildrenNames(output, " "); 1770 Slog.v(TAG_WM, output.toString()); 1771 } 1772 1773 private void dumpWindows() { 1774 Slog.v(TAG_WM, " Display #" + mDisplayId); 1775 final WindowList windows = getWindowList(); 1776 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 1777 Slog.v(TAG_WM, " #" + winNdx + ": " + windows.get(winNdx)); 1778 } 1779 } 1780 1781 void dumpTokens(PrintWriter pw, boolean dumpAll) { 1782 if (mTokenMap.isEmpty()) { 1783 return; 1784 } 1785 pw.println(" Display #" + mDisplayId); 1786 final Iterator<WindowToken> it = mTokenMap.values().iterator(); 1787 while (it.hasNext()) { 1788 final WindowToken token = it.next(); 1789 pw.print(" "); 1790 pw.print(token); 1791 if (dumpAll) { 1792 pw.println(':'); 1793 token.dump(pw, " "); 1794 } else { 1795 pw.println(); 1796 } 1797 } 1798 } 1799 1800 void enableSurfaceTrace(FileDescriptor fd) { 1801 for (int i = mWindows.size() - 1; i >= 0; i--) { 1802 final WindowState win = mWindows.get(i); 1803 win.mWinAnimator.enableSurfaceTrace(fd); 1804 } 1805 } 1806 1807 void disableSurfaceTrace() { 1808 for (int i = mWindows.size() - 1; i >= 0; i--) { 1809 final WindowState win = mWindows.get(i); 1810 win.mWinAnimator.disableSurfaceTrace(); 1811 } 1812 } 1813 1814 static final class GetWindowOnDisplaySearchResult { 1815 boolean reachedToken; 1816 WindowState foundWindow; 1817 1818 void reset() { 1819 reachedToken = false; 1820 foundWindow = null; 1821 } 1822 } 1823 1824 static final class TaskForResizePointSearchResult { 1825 boolean searchDone; 1826 Task taskForResize; 1827 1828 void reset() { 1829 searchDone = false; 1830 taskForResize = null; 1831 } 1832 } 1833 1834 /** 1835 * Base class for any direct child window container of {@link #DisplayContent} need to inherit 1836 * from. This is mainly a pass through class that allows {@link #DisplayContent} to have 1837 * homogeneous children type which is currently required by sub-classes of 1838 * {@link WindowContainer} class. 1839 */ 1840 static class DisplayChildWindowContainer<E extends WindowContainer> extends WindowContainer<E> { 1841 1842 int size() { 1843 return mChildren.size(); 1844 } 1845 1846 E get(int index) { 1847 return mChildren.get(index); 1848 } 1849 1850 @Override 1851 boolean fillsParent() { 1852 return true; 1853 } 1854 1855 @Override 1856 boolean isVisible() { 1857 return true; 1858 } 1859 } 1860 1861 /** 1862 * Window container class that contains all containers on this display relating to Apps. 1863 * I.e Activities. 1864 */ 1865 private class TaskStackContainers extends DisplayChildWindowContainer<TaskStack> { 1866 1867 void attachStack(TaskStack stack, boolean onTop) { 1868 if (stack.mStackId == HOME_STACK_ID) { 1869 if (mHomeStack != null) { 1870 throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first."); 1871 } 1872 mHomeStack = stack; 1873 } 1874 addChild(stack, onTop); 1875 stack.onDisplayChanged(DisplayContent.this); 1876 } 1877 1878 void moveStack(TaskStack stack, boolean toTop) { 1879 if (StackId.isAlwaysOnTop(stack.mStackId) && !toTop) { 1880 // This stack is always-on-top silly... 1881 Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + stack + " to bottom"); 1882 return; 1883 } 1884 1885 if (!mChildren.contains(stack)) { 1886 Slog.wtf(TAG_WM, "moving stack that was not added: " + stack, new Throwable()); 1887 } 1888 removeChild(stack); 1889 addChild(stack, toTop); 1890 } 1891 1892 private void addChild(TaskStack stack, boolean toTop) { 1893 int addIndex = toTop ? mChildren.size() : 0; 1894 1895 if (toTop 1896 && mService.isStackVisibleLocked(PINNED_STACK_ID) 1897 && stack.mStackId != PINNED_STACK_ID) { 1898 // The pinned stack is always the top most stack (always-on-top) when it is visible. 1899 // So, stack is moved just below the pinned stack. 1900 addIndex--; 1901 TaskStack topStack = mChildren.get(addIndex); 1902 if (topStack.mStackId != PINNED_STACK_ID) { 1903 throw new IllegalStateException("Pinned stack isn't top stack??? " + mChildren); 1904 } 1905 } 1906 addChild(stack, addIndex); 1907 setLayoutNeeded(); 1908 } 1909 1910 } 1911 1912 /** 1913 * Window container class that contains all containers on this display that are not related to 1914 * Apps. E.g. status bar. 1915 */ 1916 private static class NonAppWindowContainers extends DisplayChildWindowContainer<WindowToken> { 1917 1918 } 1919} 1920