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