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