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.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION; 20 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 21 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; 22 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; 23 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; 24 25 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; 26 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; 27 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; 28 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT; 29 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; 30 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; 31 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; 32 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; 33 import static com.android.server.wm.WindowContainerChildProto.WINDOW_TOKEN; 34 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 35 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 36 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; 37 import static com.android.server.wm.WindowTokenProto.HASH_CODE; 38 import static com.android.server.wm.WindowTokenProto.PAUSED; 39 import static com.android.server.wm.WindowTokenProto.WAITING_TO_SHOW; 40 import static com.android.server.wm.WindowTokenProto.WINDOW_CONTAINER; 41 42 import android.annotation.CallSuper; 43 import android.annotation.Nullable; 44 import android.app.servertransaction.FixedRotationAdjustmentsItem; 45 import android.content.res.Configuration; 46 import android.graphics.Rect; 47 import android.os.Bundle; 48 import android.os.Debug; 49 import android.os.IBinder; 50 import android.os.RemoteException; 51 import android.util.Slog; 52 import android.util.SparseArray; 53 import android.util.proto.ProtoOutputStream; 54 import android.view.DisplayAdjustments.FixedRotationAdjustments; 55 import android.view.DisplayInfo; 56 import android.view.InsetsState; 57 import android.view.SurfaceControl; 58 import android.view.WindowManager; 59 import android.view.WindowManager.LayoutParams.WindowType; 60 import android.window.WindowContext; 61 62 import com.android.internal.protolog.common.ProtoLog; 63 import com.android.server.policy.WindowManagerPolicy; 64 65 import java.io.PrintWriter; 66 import java.util.ArrayList; 67 import java.util.Comparator; 68 69 /** 70 * Container of a set of related windows in the window manager. Often this is an AppWindowToken, 71 * which is the handle for an Activity that it uses to display windows. For nested windows, there is 72 * a WindowToken created for the parent window to manage its children. 73 */ 74 class WindowToken extends WindowContainer<WindowState> { 75 private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowToken" : TAG_WM; 76 77 /** The actual token */ 78 final IBinder token; 79 80 /** The type of window this token is for, as per {@link WindowManager.LayoutParams} */ 81 final int windowType; 82 83 /** 84 * Options that will be used to determine which {@link RootDisplayArea} this window should be 85 * attached to. 86 */ 87 @Nullable 88 final Bundle mOptions; 89 90 /** {@code true} if this holds the rounded corner overlay */ 91 final boolean mRoundedCornerOverlay; 92 93 /** 94 * Set if this token was explicitly added by a client, so should persist (not be removed) 95 * when all windows are removed. 96 */ 97 boolean mPersistOnEmpty; 98 99 // For printing. 100 String stringName; 101 102 // Is key dispatching paused for this token? 103 boolean paused = false; 104 105 // Temporary for finding which tokens no longer have visible windows. 106 boolean hasVisible; 107 108 // Set to true when this token is in a pending transaction where it 109 // will be shown. 110 boolean waitingToShow; 111 112 /** The owner has {@link android.Manifest.permission#MANAGE_APP_TOKENS} */ 113 final boolean mOwnerCanManageAppTokens; 114 115 private FixedRotationTransformState mFixedRotationTransformState; 116 117 /** 118 * When set to {@code true}, this window token is created from {@link WindowContext} 119 */ 120 private final boolean mFromClientToken; 121 122 /** Have we told the window clients to show themselves? */ 123 private boolean mClientVisible; 124 125 /** 126 * Used to fix the transform of the token to be rotated to a rotation different than it's 127 * display. The window frames and surfaces corresponding to this token will be layouted and 128 * rotated by the given rotated display info, frames and insets. 129 */ 130 private static class FixedRotationTransformState { 131 final DisplayInfo mDisplayInfo; 132 final DisplayFrames mDisplayFrames; 133 final Configuration mRotatedOverrideConfiguration; 134 final SeamlessRotator mRotator; 135 /** 136 * The tokens that share the same transform. Their end time of transform are the same. The 137 * list should at least contain the token who creates this state. 138 */ 139 final ArrayList<WindowToken> mAssociatedTokens = new ArrayList<>(3); 140 final ArrayList<WindowContainer<?>> mRotatedContainers = new ArrayList<>(3); 141 final SparseArray<Rect> mBarContentFrames = new SparseArray<>(); 142 boolean mIsTransforming = true; 143 FixedRotationTransformState(DisplayInfo rotatedDisplayInfo, DisplayFrames rotatedDisplayFrames, Configuration rotatedConfig, int currentRotation)144 FixedRotationTransformState(DisplayInfo rotatedDisplayInfo, 145 DisplayFrames rotatedDisplayFrames, Configuration rotatedConfig, 146 int currentRotation) { 147 mDisplayInfo = rotatedDisplayInfo; 148 mDisplayFrames = rotatedDisplayFrames; 149 mRotatedOverrideConfiguration = rotatedConfig; 150 // This will use unrotate as rotate, so the new and old rotation are inverted. 151 mRotator = new SeamlessRotator(rotatedDisplayInfo.rotation, currentRotation, 152 rotatedDisplayInfo, true /* applyFixedTransformationHint */); 153 } 154 155 /** 156 * Transforms the window container from the next rotation to the current rotation for 157 * showing the window in a display with different rotation. 158 */ transform(WindowContainer<?> container)159 void transform(WindowContainer<?> container) { 160 mRotator.unrotate(container.getPendingTransaction(), container); 161 if (!mRotatedContainers.contains(container)) { 162 mRotatedContainers.add(container); 163 } 164 } 165 166 /** 167 * Resets the transformation of the window containers which have been rotated. This should 168 * be called when the window has the same rotation as display. 169 */ resetTransform()170 void resetTransform() { 171 for (int i = mRotatedContainers.size() - 1; i >= 0; i--) { 172 final WindowContainer<?> c = mRotatedContainers.get(i); 173 // If the window is detached (no parent), its surface may have been released. 174 if (c.getParent() != null) { 175 mRotator.finish(c.getPendingTransaction(), c); 176 } 177 } 178 } 179 180 /** The state may not only be used by self. Make sure to leave the influence by others. */ disassociate(WindowToken token)181 void disassociate(WindowToken token) { 182 mAssociatedTokens.remove(token); 183 mRotatedContainers.remove(token); 184 } 185 } 186 187 /** 188 * Compares two child window of this token and returns -1 if the first is lesser than the 189 * second in terms of z-order and 1 otherwise. 190 */ 191 private final Comparator<WindowState> mWindowComparator = 192 (WindowState newWindow, WindowState existingWindow) -> { 193 final WindowToken token = WindowToken.this; 194 if (newWindow.mToken != token) { 195 throw new IllegalArgumentException("newWindow=" + newWindow 196 + " is not a child of token=" + token); 197 } 198 199 if (existingWindow.mToken != token) { 200 throw new IllegalArgumentException("existingWindow=" + existingWindow 201 + " is not a child of token=" + token); 202 } 203 204 return isFirstChildWindowGreaterThanSecond(newWindow, existingWindow) ? 1 : -1; 205 }; 206 WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens)207 protected WindowToken(WindowManagerService service, IBinder _token, int type, 208 boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens) { 209 this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens, 210 false /* roundedCornerOverlay */, false /* fromClientToken */, null /* options */); 211 } 212 WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options)213 protected WindowToken(WindowManagerService service, IBinder _token, int type, 214 boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens, 215 boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) { 216 super(service); 217 token = _token; 218 windowType = type; 219 mOptions = options; 220 mPersistOnEmpty = persistOnEmpty; 221 mOwnerCanManageAppTokens = ownerCanManageAppTokens; 222 mRoundedCornerOverlay = roundedCornerOverlay; 223 mFromClientToken = fromClientToken; 224 if (dc != null) { 225 dc.addWindowToken(token, this); 226 } 227 } 228 removeAllWindowsIfPossible()229 void removeAllWindowsIfPossible() { 230 for (int i = mChildren.size() - 1; i >= 0; --i) { 231 final WindowState win = mChildren.get(i); 232 ProtoLog.w(WM_DEBUG_WINDOW_MOVEMENT, 233 "removeAllWindowsIfPossible: removing win=%s", win); 234 win.removeIfPossible(); 235 if (i > mChildren.size()) { 236 // It's possible for removeIfPossible to delete siblings (for example if it is a 237 // starting window, it will perform operations on the ActivityRecord). 238 i = mChildren.size(); 239 } 240 } 241 } 242 setExiting(boolean animateExit)243 void setExiting(boolean animateExit) { 244 if (isEmpty()) { 245 super.removeImmediately(); 246 return; 247 } 248 249 // This token is exiting, so allow it to be removed when it no longer contains any windows. 250 mPersistOnEmpty = false; 251 252 if (!isVisible()) { 253 return; 254 } 255 256 final int count = mChildren.size(); 257 boolean changed = false; 258 final boolean delayed = isAnimating(TRANSITION | PARENTS) 259 || (isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION) && animateExit); 260 261 for (int i = 0; i < count; i++) { 262 final WindowState win = mChildren.get(i); 263 changed |= win.onSetAppExiting(animateExit); 264 } 265 266 final ActivityRecord app = asActivityRecord(); 267 if (app != null) { 268 app.setVisible(false); 269 } 270 271 if (changed) { 272 mWmService.mWindowPlacerLocked.performSurfacePlacement(); 273 mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /*updateInputWindows*/); 274 } 275 276 if (delayed) { 277 mDisplayContent.mExitingTokens.add(this); 278 } 279 } 280 281 /** 282 * @return The scale for applications running in compatibility mode. Multiply the size in the 283 * application by this scale will be the size in the screen. 284 */ getSizeCompatScale()285 float getSizeCompatScale() { 286 return mDisplayContent.mCompatibleScreenScale; 287 } 288 289 /** 290 * @return {@code true} if this window token has bounds for size compatibility mode. 291 */ hasSizeCompatBounds()292 boolean hasSizeCompatBounds() { 293 return false; 294 } 295 296 /** 297 * Returns true if the new window is considered greater than the existing window in terms of 298 * z-order. 299 */ isFirstChildWindowGreaterThanSecond(WindowState newWindow, WindowState existingWindow)300 protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow, 301 WindowState existingWindow) { 302 // New window is considered greater if it has a higher or equal base layer. 303 return newWindow.mBaseLayer >= existingWindow.mBaseLayer; 304 } 305 addWindow(final WindowState win)306 void addWindow(final WindowState win) { 307 ProtoLog.d(WM_DEBUG_FOCUS, 308 "addWindow: win=%s Callers=%s", win, Debug.getCallers(5)); 309 310 if (win.isChildWindow()) { 311 // Child windows are added to their parent windows. 312 return; 313 } 314 // This token is created from WindowContext and the client requests to addView now, create a 315 // surface for this token. 316 if (mSurfaceControl == null) { 317 createSurfaceControl(true /* force */); 318 } 319 if (!mChildren.contains(win)) { 320 ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", win, this); 321 addChild(win, mWindowComparator); 322 mWmService.mWindowsChanged = true; 323 // TODO: Should we also be setting layout needed here and other places? 324 } 325 } 326 327 @Override createSurfaceControl(boolean force)328 void createSurfaceControl(boolean force) { 329 if (!mFromClientToken || force) { 330 super.createSurfaceControl(force); 331 } 332 } 333 334 /** Returns true if the token windows list is empty. */ isEmpty()335 boolean isEmpty() { 336 return mChildren.isEmpty(); 337 } 338 getReplacingWindow()339 WindowState getReplacingWindow() { 340 for (int i = mChildren.size() - 1; i >= 0; i--) { 341 final WindowState win = mChildren.get(i); 342 final WindowState replacing = win.getReplacingWindow(); 343 if (replacing != null) { 344 return replacing; 345 } 346 } 347 return null; 348 } 349 350 /** Return true if this token has a window that wants the wallpaper displayed behind it. */ windowsCanBeWallpaperTarget()351 boolean windowsCanBeWallpaperTarget() { 352 for (int j = mChildren.size() - 1; j >= 0; j--) { 353 final WindowState w = mChildren.get(j); 354 if (w.hasWallpaper()) { 355 return true; 356 } 357 } 358 359 return false; 360 } 361 362 @Override removeImmediately()363 void removeImmediately() { 364 if (mDisplayContent != null) { 365 mDisplayContent.removeWindowToken(token, true /* animateExit */); 366 } 367 // Needs to occur after the token is removed from the display above to avoid attempt at 368 // duplicate removal of this window container from it's parent. 369 super.removeImmediately(); 370 } 371 372 @Override onDisplayChanged(DisplayContent dc)373 void onDisplayChanged(DisplayContent dc) { 374 dc.reParentWindowToken(this); 375 376 // TODO(b/36740756): One day this should perhaps be hooked 377 // up with goodToGo, so we don't move a window 378 // to another display before the window behind 379 // it is ready. 380 super.onDisplayChanged(dc); 381 } 382 383 @Override onConfigurationChanged(Configuration newParentConfig)384 public void onConfigurationChanged(Configuration newParentConfig) { 385 super.onConfigurationChanged(newParentConfig); 386 } 387 388 @Override assignLayer(SurfaceControl.Transaction t, int layer)389 void assignLayer(SurfaceControl.Transaction t, int layer) { 390 if (windowType == TYPE_DOCK_DIVIDER) { 391 // See {@link DisplayContent#mSplitScreenDividerAnchor} 392 super.assignRelativeLayer(t, 393 mDisplayContent.getDefaultTaskDisplayArea().getSplitScreenDividerAnchor(), 1); 394 } else if (mRoundedCornerOverlay) { 395 super.assignLayer(t, WindowManagerPolicy.COLOR_FADE_LAYER + 1); 396 } else { 397 super.assignLayer(t, layer); 398 } 399 } 400 401 @Override makeSurface()402 SurfaceControl.Builder makeSurface() { 403 final SurfaceControl.Builder builder = super.makeSurface(); 404 if (mRoundedCornerOverlay) { 405 builder.setParent(null); 406 } 407 return builder; 408 } 409 isClientVisible()410 boolean isClientVisible() { 411 return mClientVisible; 412 } 413 setClientVisible(boolean clientVisible)414 void setClientVisible(boolean clientVisible) { 415 if (mClientVisible == clientVisible) { 416 return; 417 } 418 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, 419 "setClientVisible: %s clientVisible=%b Callers=%s", this, clientVisible, 420 Debug.getCallers(5)); 421 mClientVisible = clientVisible; 422 sendAppVisibilityToClients(); 423 } 424 hasFixedRotationTransform()425 boolean hasFixedRotationTransform() { 426 return mFixedRotationTransformState != null; 427 } 428 429 /** Returns {@code true} if the given token shares the same transform. */ hasFixedRotationTransform(WindowToken token)430 boolean hasFixedRotationTransform(WindowToken token) { 431 if (mFixedRotationTransformState == null || token == null) { 432 return false; 433 } 434 return this == token || mFixedRotationTransformState == token.mFixedRotationTransformState; 435 } 436 isFinishingFixedRotationTransform()437 boolean isFinishingFixedRotationTransform() { 438 return mFixedRotationTransformState != null 439 && !mFixedRotationTransformState.mIsTransforming; 440 } 441 isFixedRotationTransforming()442 boolean isFixedRotationTransforming() { 443 return mFixedRotationTransformState != null 444 && mFixedRotationTransformState.mIsTransforming; 445 } 446 getFixedRotationTransformDisplayInfo()447 DisplayInfo getFixedRotationTransformDisplayInfo() { 448 return isFixedRotationTransforming() ? mFixedRotationTransformState.mDisplayInfo : null; 449 } 450 getFixedRotationTransformDisplayFrames()451 DisplayFrames getFixedRotationTransformDisplayFrames() { 452 return isFixedRotationTransforming() ? mFixedRotationTransformState.mDisplayFrames : null; 453 } 454 getFixedRotationTransformDisplayBounds()455 Rect getFixedRotationTransformDisplayBounds() { 456 return isFixedRotationTransforming() 457 ? mFixedRotationTransformState.mRotatedOverrideConfiguration.windowConfiguration 458 .getBounds() 459 : null; 460 } 461 getFixedRotationBarContentFrame(int windowType)462 Rect getFixedRotationBarContentFrame(int windowType) { 463 if (!isFixedRotationTransforming()) { 464 return null; 465 } 466 if (!INSETS_LAYOUT_GENERALIZATION) { 467 return mFixedRotationTransformState.mBarContentFrames.get(windowType); 468 } 469 final DisplayFrames displayFrames = mFixedRotationTransformState.mDisplayFrames; 470 final Rect tmpRect = new Rect(); 471 if (windowType == TYPE_NAVIGATION_BAR) { 472 tmpRect.set(displayFrames.mInsetsState.getSource(InsetsState.ITYPE_NAVIGATION_BAR) 473 .getFrame()); 474 } 475 if (windowType == TYPE_STATUS_BAR) { 476 tmpRect.set(displayFrames.mInsetsState.getSource(InsetsState.ITYPE_STATUS_BAR) 477 .getFrame()); 478 } 479 tmpRect.intersect(displayFrames.mDisplayCutoutSafe); 480 return tmpRect; 481 } 482 getFixedRotationTransformInsetsState()483 InsetsState getFixedRotationTransformInsetsState() { 484 return isFixedRotationTransforming() 485 ? mFixedRotationTransformState.mDisplayFrames.mInsetsState 486 : null; 487 } 488 489 /** Applies the rotated layout environment to this token in the simulated rotated display. */ applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, Configuration config)490 void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, 491 Configuration config) { 492 if (mFixedRotationTransformState != null) { 493 mFixedRotationTransformState.disassociate(this); 494 } 495 mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames, 496 new Configuration(config), mDisplayContent.getRotation()); 497 mFixedRotationTransformState.mAssociatedTokens.add(this); 498 mDisplayContent.getDisplayPolicy().simulateLayoutDisplay(displayFrames, 499 mFixedRotationTransformState.mBarContentFrames); 500 onFixedRotationStatePrepared(); 501 } 502 503 /** 504 * Reuses the {@link FixedRotationTransformState} (if any) from the other WindowToken to this 505 * one. This takes the same effect as {@link #applyFixedRotationTransform}. 506 */ linkFixedRotationTransform(WindowToken other)507 void linkFixedRotationTransform(WindowToken other) { 508 final FixedRotationTransformState fixedRotationState = other.mFixedRotationTransformState; 509 if (fixedRotationState == null || mFixedRotationTransformState == fixedRotationState) { 510 return; 511 } 512 if (mFixedRotationTransformState != null) { 513 mFixedRotationTransformState.disassociate(this); 514 } 515 mFixedRotationTransformState = fixedRotationState; 516 fixedRotationState.mAssociatedTokens.add(this); 517 onFixedRotationStatePrepared(); 518 } 519 520 /** 521 * Makes the rotated states take effect for this window container and its client process. 522 * This should only be called when {@link #mFixedRotationTransformState} is non-null. 523 */ onFixedRotationStatePrepared()524 private void onFixedRotationStatePrepared() { 525 // Send the adjustment info first so when the client receives configuration change, it can 526 // get the rotated display metrics. 527 notifyFixedRotationTransform(true /* enabled */); 528 // Resolve the rotated configuration. 529 onConfigurationChanged(getParent().getConfiguration()); 530 final ActivityRecord r = asActivityRecord(); 531 if (r != null && r.hasProcess()) { 532 // The application needs to be configured as in a rotated environment for compatibility. 533 // This registration will send the rotated configuration to its process. 534 r.app.registerActivityConfigurationListener(r); 535 } 536 } 537 538 /** 539 * Return {@code true} if one of the associated activity is still animating. Otherwise, 540 * return {@code false}. 541 */ hasAnimatingFixedRotationTransition()542 boolean hasAnimatingFixedRotationTransition() { 543 if (mFixedRotationTransformState == null) { 544 return false; 545 } 546 547 for (int i = mFixedRotationTransformState.mAssociatedTokens.size() - 1; i >= 0; i--) { 548 final ActivityRecord r = 549 mFixedRotationTransformState.mAssociatedTokens.get(i).asActivityRecord(); 550 if (r != null && r.isAnimating(TRANSITION | PARENTS)) { 551 return true; 552 } 553 } 554 return false; 555 } 556 finishFixedRotationTransform()557 void finishFixedRotationTransform() { 558 finishFixedRotationTransform(null /* applyDisplayRotation */); 559 } 560 561 /** 562 * Finishes the transform and apply display rotation if the action is given. If the display will 563 * not rotate, the transformed containers are restored to their original states. 564 */ finishFixedRotationTransform(Runnable applyDisplayRotation)565 void finishFixedRotationTransform(Runnable applyDisplayRotation) { 566 final FixedRotationTransformState state = mFixedRotationTransformState; 567 if (state == null) { 568 return; 569 } 570 571 state.resetTransform(); 572 // Clear the flag so if the display will be updated to the same orientation, the transform 573 // won't take effect. 574 state.mIsTransforming = false; 575 if (applyDisplayRotation != null) { 576 applyDisplayRotation.run(); 577 } 578 // The state is cleared at the end, because it is used to indicate that other windows can 579 // use seamless rotation when applying rotation to display. 580 for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) { 581 final WindowToken token = state.mAssociatedTokens.get(i); 582 token.mFixedRotationTransformState = null; 583 token.notifyFixedRotationTransform(false /* enabled */); 584 if (applyDisplayRotation == null) { 585 // Notify cancellation because the display does not change rotation. 586 token.cancelFixedRotationTransform(); 587 } 588 } 589 } 590 591 /** Notifies application side to enable or disable the rotation adjustment of display info. */ notifyFixedRotationTransform(boolean enabled)592 void notifyFixedRotationTransform(boolean enabled) { 593 FixedRotationAdjustments adjustments = null; 594 // A token may contain windows of the same processes or different processes. The list is 595 // used to avoid sending the same adjustments to a process multiple times. 596 ArrayList<WindowProcessController> notifiedProcesses = null; 597 for (int i = mChildren.size() - 1; i >= 0; i--) { 598 final WindowState w = mChildren.get(i); 599 final WindowProcessController app; 600 if (w.mAttrs.type == TYPE_APPLICATION_STARTING) { 601 // Use the host activity because starting window is controlled by window manager. 602 final ActivityRecord r = asActivityRecord(); 603 if (r == null) { 604 continue; 605 } 606 app = r.app; 607 } else { 608 app = mWmService.mAtmService.mProcessMap.getProcess(w.mSession.mPid); 609 } 610 if (app == null || !app.hasThread()) { 611 continue; 612 } 613 if (notifiedProcesses == null) { 614 notifiedProcesses = new ArrayList<>(2); 615 adjustments = enabled ? createFixedRotationAdjustmentsIfNeeded() : null; 616 } else if (notifiedProcesses.contains(app)) { 617 continue; 618 } 619 notifiedProcesses.add(app); 620 try { 621 mWmService.mAtmService.getLifecycleManager().scheduleTransaction( 622 app.getThread(), FixedRotationAdjustmentsItem.obtain(token, adjustments)); 623 } catch (RemoteException e) { 624 Slog.w(TAG, "Failed to schedule DisplayAdjustmentsItem to " + app, e); 625 } 626 } 627 } 628 629 /** Restores the changes that applies to this container. */ cancelFixedRotationTransform()630 private void cancelFixedRotationTransform() { 631 final WindowContainer<?> parent = getParent(); 632 if (parent == null) { 633 // The window may be detached or detaching. 634 return; 635 } 636 final int originalRotation = getWindowConfiguration().getRotation(); 637 onConfigurationChanged(parent.getConfiguration()); 638 onCancelFixedRotationTransform(originalRotation); 639 } 640 641 /** 642 * It is called when the window is using fixed rotation transform, and before display applies 643 * the same rotation, the rotation change for display is canceled, e.g. the orientation from 644 * sensor is updated to previous direction. 645 */ onCancelFixedRotationTransform(int originalDisplayRotation)646 void onCancelFixedRotationTransform(int originalDisplayRotation) { 647 } 648 createFixedRotationAdjustmentsIfNeeded()649 FixedRotationAdjustments createFixedRotationAdjustmentsIfNeeded() { 650 if (!isFixedRotationTransforming()) { 651 return null; 652 } 653 final DisplayInfo displayInfo = mFixedRotationTransformState.mDisplayInfo; 654 return new FixedRotationAdjustments(displayInfo.rotation, displayInfo.appWidth, 655 displayInfo.appHeight, displayInfo.displayCutout); 656 } 657 658 @Override resolveOverrideConfiguration(Configuration newParentConfig)659 void resolveOverrideConfiguration(Configuration newParentConfig) { 660 super.resolveOverrideConfiguration(newParentConfig); 661 if (isFixedRotationTransforming()) { 662 // Apply the rotated configuration to current resolved configuration, so the merged 663 // override configuration can update to the same state. 664 getResolvedOverrideConfiguration().updateFrom( 665 mFixedRotationTransformState.mRotatedOverrideConfiguration); 666 } 667 } 668 669 @Override updateSurfacePosition(SurfaceControl.Transaction t)670 void updateSurfacePosition(SurfaceControl.Transaction t) { 671 super.updateSurfacePosition(t); 672 if (isFixedRotationTransforming()) { 673 final ActivityRecord r = asActivityRecord(); 674 final Task rootTask = r != null ? r.getRootTask() : null; 675 // Don't transform the activity in PiP because the PiP task organizer will handle it. 676 if (rootTask == null || !rootTask.inPinnedWindowingMode()) { 677 // The window is laid out in a simulated rotated display but the real display hasn't 678 // rotated, so here transforms its surface to fit in the real display. 679 mFixedRotationTransformState.transform(this); 680 } 681 } 682 } 683 684 @Override resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t)685 void resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t) { 686 // Keep the transformed position to animate because the surface will show in different 687 // rotation than the animator of leash. 688 if (!isFixedRotationTransforming()) { 689 super.resetSurfacePositionForAnimationLeash(t); 690 } 691 } 692 693 /** 694 * Gives a chance to this {@link WindowToken} to adjust the {@link 695 * android.view.WindowManager.LayoutParams} of its windows. 696 */ adjustWindowParams(WindowState win, WindowManager.LayoutParams attrs)697 void adjustWindowParams(WindowState win, WindowManager.LayoutParams attrs) { 698 } 699 700 701 @CallSuper 702 @Override dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel)703 public void dumpDebug(ProtoOutputStream proto, long fieldId, 704 @WindowTraceLogLevel int logLevel) { 705 if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { 706 return; 707 } 708 709 final long token = proto.start(fieldId); 710 super.dumpDebug(proto, WINDOW_CONTAINER, logLevel); 711 proto.write(HASH_CODE, System.identityHashCode(this)); 712 proto.write(WAITING_TO_SHOW, waitingToShow); 713 proto.write(PAUSED, paused); 714 proto.end(token); 715 } 716 717 @Override getProtoFieldId()718 long getProtoFieldId() { 719 return WINDOW_TOKEN; 720 } 721 dump(PrintWriter pw, String prefix, boolean dumpAll)722 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 723 super.dump(pw, prefix, dumpAll); 724 pw.print(prefix); pw.print("windows="); pw.println(mChildren); 725 pw.print(prefix); pw.print("windowType="); pw.print(windowType); 726 pw.print(" hasVisible="); pw.print(hasVisible); 727 if (waitingToShow) { 728 pw.print(" waitingToShow=true"); 729 } 730 pw.println(); 731 if (hasFixedRotationTransform()) { 732 pw.print(prefix); 733 pw.print("fixedRotationConfig="); 734 pw.println(mFixedRotationTransformState.mRotatedOverrideConfiguration); 735 } 736 } 737 738 @Override toString()739 public String toString() { 740 if (stringName == null) { 741 StringBuilder sb = new StringBuilder(); 742 sb.append("WindowToken{"); 743 sb.append(Integer.toHexString(System.identityHashCode(this))); 744 sb.append(" "); sb.append(token); sb.append('}'); 745 stringName = sb.toString(); 746 } 747 return stringName; 748 } 749 750 @Override getName()751 String getName() { 752 return toString(); 753 } 754 755 @Override asWindowToken()756 WindowToken asWindowToken() { 757 return this; 758 } 759 760 /** 761 * Return whether windows from this token can layer above the 762 * system bars, or in other words extend outside of the "Decor Frame" 763 */ canLayerAboveSystemBars()764 boolean canLayerAboveSystemBars() { 765 int layer = getWindowLayerFromType(); 766 int navLayer = mWmService.mPolicy.getWindowLayerFromTypeLw(TYPE_NAVIGATION_BAR, 767 mOwnerCanManageAppTokens); 768 return mOwnerCanManageAppTokens && (layer > navLayer); 769 } 770 getWindowLayerFromType()771 int getWindowLayerFromType() { 772 return mWmService.mPolicy.getWindowLayerFromTypeLw(windowType, mOwnerCanManageAppTokens, 773 mRoundedCornerOverlay); 774 } 775 isFromClient()776 boolean isFromClient() { 777 return mFromClientToken; 778 } 779 780 /** @see WindowState#freezeInsetsState() */ setInsetsFrozen(boolean freeze)781 void setInsetsFrozen(boolean freeze) { 782 forAllWindows(w -> { 783 if (w.mToken == this) { 784 if (freeze) { 785 w.freezeInsetsState(); 786 } else { 787 w.clearFrozenInsetsState(); 788 } 789 } 790 }, true /* traverseTopToBottom */); 791 } 792 793 @Override getWindowType()794 @WindowType int getWindowType() { 795 return windowType; 796 } 797 798 static class Builder { 799 private final WindowManagerService mService; 800 private final IBinder mToken; 801 @WindowType 802 private final int mType; 803 804 private boolean mPersistOnEmpty; 805 private DisplayContent mDisplayContent; 806 private boolean mOwnerCanManageAppTokens; 807 private boolean mRoundedCornerOverlay; 808 private boolean mFromClientToken; 809 @Nullable 810 private Bundle mOptions; 811 Builder(WindowManagerService service, IBinder token, int type)812 Builder(WindowManagerService service, IBinder token, int type) { 813 mService = service; 814 mToken = token; 815 mType = type; 816 } 817 818 /** @see WindowToken#mPersistOnEmpty */ setPersistOnEmpty(boolean persistOnEmpty)819 Builder setPersistOnEmpty(boolean persistOnEmpty) { 820 mPersistOnEmpty = persistOnEmpty; 821 return this; 822 } 823 824 /** Sets the {@link DisplayContent} to be associated. */ setDisplayContent(DisplayContent dc)825 Builder setDisplayContent(DisplayContent dc) { 826 mDisplayContent = dc; 827 return this; 828 } 829 830 /** @see WindowToken#mOwnerCanManageAppTokens */ setOwnerCanManageAppTokens(boolean ownerCanManageAppTokens)831 Builder setOwnerCanManageAppTokens(boolean ownerCanManageAppTokens) { 832 mOwnerCanManageAppTokens = ownerCanManageAppTokens; 833 return this; 834 } 835 836 /** @see WindowToken#mRoundedCornerOverlay */ setRoundedCornerOverlay(boolean roundedCornerOverlay)837 Builder setRoundedCornerOverlay(boolean roundedCornerOverlay) { 838 mRoundedCornerOverlay = roundedCornerOverlay; 839 return this; 840 } 841 842 /** @see WindowToken#mFromClientToken */ setFromClientToken(boolean fromClientToken)843 Builder setFromClientToken(boolean fromClientToken) { 844 mFromClientToken = fromClientToken; 845 return this; 846 } 847 848 /** @see WindowToken#mOptions */ setOptions(Bundle options)849 Builder setOptions(Bundle options) { 850 mOptions = options; 851 return this; 852 } 853 build()854 WindowToken build() { 855 return new WindowToken(mService, mToken, mType, mPersistOnEmpty, mDisplayContent, 856 mOwnerCanManageAppTokens, mRoundedCornerOverlay, mFromClientToken, mOptions); 857 } 858 } 859 } 860