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