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 final SeamlessRotator mRotator; 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 final ArrayList<WindowContainer<?>> mRotatedContainers = new ArrayList<>(3); 129 boolean mIsTransforming = true; 130 FixedRotationTransformState(DisplayInfo rotatedDisplayInfo, DisplayFrames rotatedDisplayFrames, Configuration rotatedConfig, int currentRotation)131 FixedRotationTransformState(DisplayInfo rotatedDisplayInfo, 132 DisplayFrames rotatedDisplayFrames, Configuration rotatedConfig, 133 int currentRotation) { 134 mDisplayInfo = rotatedDisplayInfo; 135 mDisplayFrames = rotatedDisplayFrames; 136 mRotatedOverrideConfiguration = rotatedConfig; 137 // This will use unrotate as rotate, so the new and old rotation are inverted. 138 mRotator = new SeamlessRotator(rotatedDisplayInfo.rotation, currentRotation, 139 rotatedDisplayInfo, true /* applyFixedTransformationHint */); 140 } 141 142 /** 143 * Transforms the window container from the next rotation to the current rotation for 144 * showing the window in a display with different rotation. 145 */ transform(WindowContainer<?> container)146 void transform(WindowContainer<?> container) { 147 mRotator.unrotate(container.getPendingTransaction(), container); 148 if (!mRotatedContainers.contains(container)) { 149 mRotatedContainers.add(container); 150 } 151 } 152 153 /** 154 * Resets the transformation of the window containers which have been rotated. This should 155 * be called when the window has the same rotation as display. 156 */ resetTransform()157 void resetTransform() { 158 for (int i = mRotatedContainers.size() - 1; i >= 0; i--) { 159 final WindowContainer<?> c = mRotatedContainers.get(i); 160 // If the window is detached (no parent), its surface may have been released. 161 if (c.getParent() != null) { 162 mRotator.finish(c.getPendingTransaction(), c); 163 } 164 } 165 } 166 167 /** The state may not only be used by self. Make sure to leave the influence by others. */ disassociate(WindowToken token)168 void disassociate(WindowToken token) { 169 mAssociatedTokens.remove(token); 170 mRotatedContainers.remove(token); 171 } 172 } 173 174 /** 175 * Compares two child window of this token and returns -1 if the first is lesser than the 176 * second in terms of z-order and 1 otherwise. 177 */ 178 private final Comparator<WindowState> mWindowComparator = 179 (WindowState newWindow, WindowState existingWindow) -> { 180 final WindowToken token = WindowToken.this; 181 if (newWindow.mToken != token) { 182 throw new IllegalArgumentException("newWindow=" + newWindow 183 + " is not a child of token=" + token); 184 } 185 186 if (existingWindow.mToken != token) { 187 throw new IllegalArgumentException("existingWindow=" + existingWindow 188 + " is not a child of token=" + token); 189 } 190 191 return isFirstChildWindowGreaterThanSecond(newWindow, existingWindow) ? 1 : -1; 192 }; 193 WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens)194 protected WindowToken(WindowManagerService service, IBinder _token, int type, 195 boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens) { 196 this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens, 197 false /* roundedCornerOverlay */, false /* fromClientToken */, null /* options */); 198 } 199 WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options)200 protected WindowToken(WindowManagerService service, IBinder _token, int type, 201 boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens, 202 boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) { 203 super(service); 204 token = _token; 205 windowType = type; 206 mOptions = options; 207 mPersistOnEmpty = persistOnEmpty; 208 mOwnerCanManageAppTokens = ownerCanManageAppTokens; 209 mRoundedCornerOverlay = roundedCornerOverlay; 210 mFromClientToken = fromClientToken; 211 if (dc != null) { 212 dc.addWindowToken(token, this); 213 } 214 } 215 removeAllWindowsIfPossible()216 void removeAllWindowsIfPossible() { 217 for (int i = mChildren.size() - 1; i >= 0; --i) { 218 final WindowState win = mChildren.get(i); 219 ProtoLog.w(WM_DEBUG_WINDOW_MOVEMENT, 220 "removeAllWindowsIfPossible: removing win=%s", win); 221 win.removeIfPossible(); 222 if (i > mChildren.size()) { 223 // It's possible for removeIfPossible to delete siblings (for example if it is a 224 // starting window, it will perform operations on the ActivityRecord). 225 i = mChildren.size(); 226 } 227 } 228 } 229 230 /** Starts exit animation or hides windows if needed. It is only used for non-activity token. */ setExiting(boolean animateExit)231 void setExiting(boolean animateExit) { 232 if (isEmpty()) { 233 super.removeImmediately(); 234 return; 235 } 236 237 // This token is exiting, so allow it to be removed when it no longer contains any windows. 238 mPersistOnEmpty = false; 239 240 if (!isVisible()) { 241 return; 242 } 243 244 final int count = mChildren.size(); 245 boolean changed = false; 246 for (int i = 0; i < count; i++) { 247 final WindowState win = mChildren.get(i); 248 changed |= win.onSetAppExiting(animateExit); 249 } 250 251 if (changed) { 252 mWmService.mWindowPlacerLocked.performSurfacePlacement(); 253 mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /*updateInputWindows*/); 254 } 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 getReplacingWindow()318 WindowState getReplacingWindow() { 319 for (int i = mChildren.size() - 1; i >= 0; i--) { 320 final WindowState win = mChildren.get(i); 321 final WindowState replacing = win.getReplacingWindow(); 322 if (replacing != null) { 323 return replacing; 324 } 325 } 326 return null; 327 } 328 329 /** Return true if this token has a window that wants the wallpaper displayed behind it. */ windowsCanBeWallpaperTarget()330 boolean windowsCanBeWallpaperTarget() { 331 for (int j = mChildren.size() - 1; j >= 0; j--) { 332 final WindowState w = mChildren.get(j); 333 if (w.hasWallpaper()) { 334 return true; 335 } 336 } 337 338 return false; 339 } 340 341 @Override removeImmediately()342 void removeImmediately() { 343 if (mDisplayContent != null) { 344 mDisplayContent.removeWindowToken(token, true /* animateExit */); 345 } 346 // Needs to occur after the token is removed from the display above to avoid attempt at 347 // duplicate removal of this window container from it's parent. 348 super.removeImmediately(); 349 } 350 351 @Override onDisplayChanged(DisplayContent dc)352 void onDisplayChanged(DisplayContent dc) { 353 dc.reParentWindowToken(this); 354 355 // TODO(b/36740756): One day this should perhaps be hooked 356 // up with goodToGo, so we don't move a window 357 // to another display before the window behind 358 // it is ready. 359 super.onDisplayChanged(dc); 360 } 361 362 @Override assignLayer(SurfaceControl.Transaction t, int layer)363 void assignLayer(SurfaceControl.Transaction t, int layer) { 364 if (mRoundedCornerOverlay) { 365 super.assignLayer(t, WindowManagerPolicy.COLOR_FADE_LAYER + 1); 366 } else { 367 super.assignLayer(t, layer); 368 } 369 } 370 371 @Override makeSurface()372 SurfaceControl.Builder makeSurface() { 373 final SurfaceControl.Builder builder = super.makeSurface(); 374 if (mRoundedCornerOverlay) { 375 builder.setParent(null); 376 } 377 return builder; 378 } 379 isClientVisible()380 boolean isClientVisible() { 381 return mClientVisible; 382 } 383 setClientVisible(boolean clientVisible)384 void setClientVisible(boolean clientVisible) { 385 if (mClientVisible == clientVisible) { 386 return; 387 } 388 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, 389 "setClientVisible: %s clientVisible=%b Callers=%s", this, clientVisible, 390 Debug.getCallers(5)); 391 mClientVisible = clientVisible; 392 sendAppVisibilityToClients(); 393 } 394 hasFixedRotationTransform()395 boolean hasFixedRotationTransform() { 396 return mFixedRotationTransformState != null; 397 } 398 399 /** Returns {@code true} if the given token shares the same transform. */ hasFixedRotationTransform(WindowToken token)400 boolean hasFixedRotationTransform(WindowToken token) { 401 if (mFixedRotationTransformState == null || token == null) { 402 return false; 403 } 404 return this == token || mFixedRotationTransformState == token.mFixedRotationTransformState; 405 } 406 isFinishingFixedRotationTransform()407 boolean isFinishingFixedRotationTransform() { 408 return mFixedRotationTransformState != null 409 && !mFixedRotationTransformState.mIsTransforming; 410 } 411 isFixedRotationTransforming()412 boolean isFixedRotationTransforming() { 413 return mFixedRotationTransformState != null 414 && mFixedRotationTransformState.mIsTransforming; 415 } 416 getFixedRotationTransformDisplayInfo()417 DisplayInfo getFixedRotationTransformDisplayInfo() { 418 return isFixedRotationTransforming() ? mFixedRotationTransformState.mDisplayInfo : null; 419 } 420 getFixedRotationTransformDisplayFrames()421 DisplayFrames getFixedRotationTransformDisplayFrames() { 422 return isFixedRotationTransforming() ? mFixedRotationTransformState.mDisplayFrames : null; 423 } 424 getFixedRotationTransformMaxBounds()425 Rect getFixedRotationTransformMaxBounds() { 426 return isFixedRotationTransforming() 427 ? mFixedRotationTransformState.mRotatedOverrideConfiguration.windowConfiguration 428 .getMaxBounds() 429 : null; 430 } 431 getFixedRotationTransformDisplayBounds()432 Rect getFixedRotationTransformDisplayBounds() { 433 return isFixedRotationTransforming() 434 ? mFixedRotationTransformState.mRotatedOverrideConfiguration.windowConfiguration 435 .getBounds() 436 : null; 437 } 438 getFixedRotationTransformInsetsState()439 InsetsState getFixedRotationTransformInsetsState() { 440 return isFixedRotationTransforming() 441 ? mFixedRotationTransformState.mDisplayFrames.mInsetsState 442 : null; 443 } 444 445 /** Applies the rotated layout environment to this token in the simulated rotated display. */ applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, Configuration config)446 void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, 447 Configuration config) { 448 if (mFixedRotationTransformState != null) { 449 mFixedRotationTransformState.disassociate(this); 450 } 451 // TODO(b/233855302): Remove TaskFragment override if the DisplayContent uses the same 452 // bounds for screenLayout calculation. 453 final Configuration overrideConfig = new Configuration(config); 454 overrideConfig.screenLayout = TaskFragment.computeScreenLayoutOverride( 455 overrideConfig.screenLayout, overrideConfig.screenWidthDp, 456 overrideConfig.screenHeightDp); 457 mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames, 458 overrideConfig, mDisplayContent.getRotation()); 459 mFixedRotationTransformState.mAssociatedTokens.add(this); 460 mDisplayContent.getDisplayPolicy().simulateLayoutDisplay(displayFrames); 461 onFixedRotationStatePrepared(); 462 } 463 464 /** 465 * Reuses the {@link FixedRotationTransformState} (if any) from the other WindowToken to this 466 * one. This takes the same effect as {@link #applyFixedRotationTransform}. 467 */ linkFixedRotationTransform(WindowToken other)468 void linkFixedRotationTransform(WindowToken other) { 469 final FixedRotationTransformState fixedRotationState = other.mFixedRotationTransformState; 470 if (fixedRotationState == null || mFixedRotationTransformState == fixedRotationState) { 471 return; 472 } 473 if (mFixedRotationTransformState != null) { 474 mFixedRotationTransformState.disassociate(this); 475 } 476 mFixedRotationTransformState = fixedRotationState; 477 fixedRotationState.mAssociatedTokens.add(this); 478 onFixedRotationStatePrepared(); 479 } 480 481 /** 482 * Makes the rotated states take effect for this window container and its client process. 483 * This should only be called when {@link #mFixedRotationTransformState} is non-null. 484 */ onFixedRotationStatePrepared()485 private void onFixedRotationStatePrepared() { 486 // Resolve the rotated configuration. 487 onConfigurationChanged(getParent().getConfiguration()); 488 final ActivityRecord r = asActivityRecord(); 489 if (r != null && r.hasProcess()) { 490 // The application needs to be configured as in a rotated environment for compatibility. 491 // This registration will send the rotated configuration to its process. 492 r.app.registerActivityConfigurationListener(r); 493 } 494 } 495 496 /** 497 * Return {@code true} if one of the associated activity is still animating. Otherwise, 498 * return {@code false}. 499 */ hasAnimatingFixedRotationTransition()500 boolean hasAnimatingFixedRotationTransition() { 501 if (mFixedRotationTransformState == null) { 502 return false; 503 } 504 505 for (int i = mFixedRotationTransformState.mAssociatedTokens.size() - 1; i >= 0; i--) { 506 final ActivityRecord r = 507 mFixedRotationTransformState.mAssociatedTokens.get(i).asActivityRecord(); 508 if (r != null && r.isInTransition()) { 509 return true; 510 } 511 } 512 return false; 513 } 514 finishFixedRotationTransform()515 void finishFixedRotationTransform() { 516 finishFixedRotationTransform(null /* applyDisplayRotation */); 517 } 518 519 /** 520 * Finishes the transform and apply display rotation if the action is given. If the display will 521 * not rotate, the transformed containers are restored to their original states. 522 */ finishFixedRotationTransform(Runnable applyDisplayRotation)523 void finishFixedRotationTransform(Runnable applyDisplayRotation) { 524 final FixedRotationTransformState state = mFixedRotationTransformState; 525 if (state == null) { 526 return; 527 } 528 if (!mTransitionController.isShellTransitionsEnabled()) { 529 state.resetTransform(); 530 } else { 531 // Remove all the leashes 532 for (int i = state.mAssociatedTokens.size() - 1; i >= 0; --i) { 533 state.mAssociatedTokens.get(i).removeFixedRotationLeash(); 534 } 535 } 536 // Clear the flag so if the display will be updated to the same orientation, the transform 537 // won't take effect. 538 state.mIsTransforming = false; 539 if (applyDisplayRotation != null) { 540 applyDisplayRotation.run(); 541 } 542 // The state is cleared at the end, because it is used to indicate that other windows can 543 // use seamless rotation when applying rotation to display. 544 for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) { 545 final WindowToken token = state.mAssociatedTokens.get(i); 546 token.mFixedRotationTransformState = null; 547 if (applyDisplayRotation == null) { 548 // Notify cancellation because the display does not change rotation. 549 token.cancelFixedRotationTransform(); 550 } 551 } 552 } 553 554 /** Restores the changes that applies to this container. */ cancelFixedRotationTransform()555 private void cancelFixedRotationTransform() { 556 final WindowContainer<?> parent = getParent(); 557 if (parent == null) { 558 // The window may be detached or detaching. 559 return; 560 } 561 if (mTransitionController.isShellTransitionsEnabled() 562 && asActivityRecord() != null && isVisible()) { 563 // Trigger an activity level rotation transition. 564 mTransitionController.requestTransitionIfNeeded(WindowManager.TRANSIT_CHANGE, this); 565 mTransitionController.setReady(this); 566 } 567 final int originalRotation = getWindowConfiguration().getRotation(); 568 onConfigurationChanged(parent.getConfiguration()); 569 onCancelFixedRotationTransform(originalRotation); 570 } 571 572 /** 573 * Gets or creates a leash which can be treated as if this window is not-rotated. This is 574 * used to adapt mismatched-rotation surfaces into code that expects all windows to share 575 * the same rotation. 576 */ 577 @Nullable getOrCreateFixedRotationLeash(@onNull SurfaceControl.Transaction t)578 SurfaceControl getOrCreateFixedRotationLeash(@NonNull SurfaceControl.Transaction t) { 579 if (!mTransitionController.isShellTransitionsEnabled()) return null; 580 final int rotation = getRelativeDisplayRotation(); 581 if (rotation == Surface.ROTATION_0) return mFixedRotationTransformLeash; 582 if (mFixedRotationTransformLeash != null) return mFixedRotationTransformLeash; 583 584 final SurfaceControl leash = makeSurface().setContainerLayer() 585 .setParent(getParentSurfaceControl()) 586 .setName(getSurfaceControl() + " - rotation-leash") 587 .setHidden(false) 588 .setCallsite("WindowToken.getOrCreateFixedRotationLeash") 589 .build(); 590 t.setPosition(leash, mLastSurfacePosition.x, mLastSurfacePosition.y); 591 t.reparent(getSurfaceControl(), leash); 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 t.reparent(getSurfaceControl(), getParentSurfaceControl()); 610 t.remove(mFixedRotationTransformLeash); 611 mFixedRotationTransformLeash = null; 612 } 613 614 /** 615 * It is called when the window is using fixed rotation transform, and before display applies 616 * the same rotation, the rotation change for display is canceled, e.g. the orientation from 617 * sensor is updated to previous direction. 618 */ onCancelFixedRotationTransform(int originalDisplayRotation)619 void onCancelFixedRotationTransform(int originalDisplayRotation) { 620 } 621 622 @Override resolveOverrideConfiguration(Configuration newParentConfig)623 void resolveOverrideConfiguration(Configuration newParentConfig) { 624 super.resolveOverrideConfiguration(newParentConfig); 625 if (isFixedRotationTransforming()) { 626 // Apply the rotated configuration to current resolved configuration, so the merged 627 // override configuration can update to the same state. 628 getResolvedOverrideConfiguration().updateFrom( 629 mFixedRotationTransformState.mRotatedOverrideConfiguration); 630 } 631 } 632 633 @Override updateSurfacePosition(SurfaceControl.Transaction t)634 void updateSurfacePosition(SurfaceControl.Transaction t) { 635 super.updateSurfacePosition(t); 636 if (!mTransitionController.isShellTransitionsEnabled() && isFixedRotationTransforming()) { 637 final ActivityRecord r = asActivityRecord(); 638 final Task rootTask = r != null ? r.getRootTask() : null; 639 // Don't transform the activity in PiP because the PiP task organizer will handle it. 640 if (rootTask == null || !rootTask.inPinnedWindowingMode()) { 641 // The window is laid out in a simulated rotated display but the real display hasn't 642 // rotated, so here transforms its surface to fit in the real display. 643 mFixedRotationTransformState.transform(this); 644 } 645 } 646 } 647 648 @Override updateSurfaceRotation(SurfaceControl.Transaction t, @Surface.Rotation int deltaRotation, SurfaceControl positionLeash)649 protected void updateSurfaceRotation(SurfaceControl.Transaction t, 650 @Surface.Rotation int deltaRotation, SurfaceControl positionLeash) { 651 final ActivityRecord r = asActivityRecord(); 652 if (r != null) { 653 final Task rootTask = r.getRootTask(); 654 // Don't transform the activity exiting PiP because the PiP task organizer will handle 655 // it. 656 if (rootTask != null && mTransitionController.getWindowingModeAtStart(rootTask) 657 == WINDOWING_MODE_PINNED) { 658 return; 659 } 660 } 661 super.updateSurfaceRotation(t, deltaRotation, positionLeash); 662 } 663 664 @Override resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t)665 void resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t) { 666 // Keep the transformed position to animate because the surface will show in different 667 // rotation than the animator of leash. 668 if (!isFixedRotationTransforming()) { 669 super.resetSurfacePositionForAnimationLeash(t); 670 } 671 } 672 673 @Override prepareSync()674 boolean prepareSync() { 675 if (mDisplayContent != null && mDisplayContent.isRotationChanging() 676 && AsyncRotationController.canBeAsync(this)) { 677 return false; 678 } 679 return super.prepareSync(); 680 } 681 682 @CallSuper 683 @Override dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel)684 public void dumpDebug(ProtoOutputStream proto, long fieldId, 685 @WindowTraceLogLevel int logLevel) { 686 if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { 687 return; 688 } 689 690 final long token = proto.start(fieldId); 691 super.dumpDebug(proto, WINDOW_CONTAINER, logLevel); 692 proto.write(HASH_CODE, System.identityHashCode(this)); 693 proto.write(WAITING_TO_SHOW, waitingToShow); 694 proto.write(PAUSED, paused); 695 proto.end(token); 696 } 697 698 @Override getProtoFieldId()699 long getProtoFieldId() { 700 return WINDOW_TOKEN; 701 } 702 dump(PrintWriter pw, String prefix, boolean dumpAll)703 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 704 super.dump(pw, prefix, dumpAll); 705 pw.print(prefix); pw.print("windows="); pw.println(mChildren); 706 pw.print(prefix); pw.print("windowType="); pw.print(windowType); 707 if (waitingToShow) { 708 pw.print(" waitingToShow=true"); 709 } 710 pw.println(); 711 if (hasFixedRotationTransform()) { 712 pw.print(prefix); 713 pw.print("fixedRotationConfig="); 714 pw.println(mFixedRotationTransformState.mRotatedOverrideConfiguration); 715 } 716 } 717 718 @Override toString()719 public String toString() { 720 if (stringName == null) { 721 stringName = "WindowToken{" + Integer.toHexString(System.identityHashCode(this)) 722 + " type=" + windowType + " " + token + "}"; 723 } 724 return stringName; 725 } 726 727 @Override getName()728 String getName() { 729 return toString(); 730 } 731 732 @Override asWindowToken()733 WindowToken asWindowToken() { 734 return this; 735 } 736 737 /** 738 * Return whether windows from this token can layer above the 739 * system bars, or in other words extend outside of the "Decor Frame" 740 */ canLayerAboveSystemBars()741 boolean canLayerAboveSystemBars() { 742 int layer = getWindowLayerFromType(); 743 int navLayer = mWmService.mPolicy.getWindowLayerFromTypeLw(TYPE_NAVIGATION_BAR, 744 mOwnerCanManageAppTokens); 745 return mOwnerCanManageAppTokens && (layer > navLayer); 746 } 747 getWindowLayerFromType()748 int getWindowLayerFromType() { 749 return mWmService.mPolicy.getWindowLayerFromTypeLw(windowType, mOwnerCanManageAppTokens, 750 mRoundedCornerOverlay); 751 } 752 isFromClient()753 boolean isFromClient() { 754 return mFromClientToken; 755 } 756 757 /** @see WindowState#freezeInsetsState() */ setInsetsFrozen(boolean freeze)758 void setInsetsFrozen(boolean freeze) { 759 forAllWindows(w -> { 760 if (w.mToken == this) { 761 if (freeze) { 762 w.freezeInsetsState(); 763 } else { 764 w.clearFrozenInsetsState(); 765 } 766 } 767 }, true /* traverseTopToBottom */); 768 } 769 770 @Override getWindowType()771 @WindowType int getWindowType() { 772 return windowType; 773 } 774 775 static class Builder { 776 private final WindowManagerService mService; 777 private final IBinder mToken; 778 @WindowType 779 private final int mType; 780 781 private boolean mPersistOnEmpty; 782 private DisplayContent mDisplayContent; 783 private boolean mOwnerCanManageAppTokens; 784 private boolean mRoundedCornerOverlay; 785 private boolean mFromClientToken; 786 @Nullable 787 private Bundle mOptions; 788 Builder(WindowManagerService service, IBinder token, int type)789 Builder(WindowManagerService service, IBinder token, int type) { 790 mService = service; 791 mToken = token; 792 mType = type; 793 } 794 795 /** @see WindowToken#mPersistOnEmpty */ setPersistOnEmpty(boolean persistOnEmpty)796 Builder setPersistOnEmpty(boolean persistOnEmpty) { 797 mPersistOnEmpty = persistOnEmpty; 798 return this; 799 } 800 801 /** Sets the {@link DisplayContent} to be associated. */ setDisplayContent(DisplayContent dc)802 Builder setDisplayContent(DisplayContent dc) { 803 mDisplayContent = dc; 804 return this; 805 } 806 807 /** @see WindowToken#mOwnerCanManageAppTokens */ setOwnerCanManageAppTokens(boolean ownerCanManageAppTokens)808 Builder setOwnerCanManageAppTokens(boolean ownerCanManageAppTokens) { 809 mOwnerCanManageAppTokens = ownerCanManageAppTokens; 810 return this; 811 } 812 813 /** @see WindowToken#mRoundedCornerOverlay */ setRoundedCornerOverlay(boolean roundedCornerOverlay)814 Builder setRoundedCornerOverlay(boolean roundedCornerOverlay) { 815 mRoundedCornerOverlay = roundedCornerOverlay; 816 return this; 817 } 818 819 /** @see WindowToken#mFromClientToken */ setFromClientToken(boolean fromClientToken)820 Builder setFromClientToken(boolean fromClientToken) { 821 mFromClientToken = fromClientToken; 822 return this; 823 } 824 825 /** @see WindowToken#mOptions */ setOptions(Bundle options)826 Builder setOptions(Bundle options) { 827 mOptions = options; 828 return this; 829 } 830 build()831 WindowToken build() { 832 return new WindowToken(mService, mToken, mType, mPersistOnEmpty, mDisplayContent, 833 mOwnerCanManageAppTokens, mRoundedCornerOverlay, mFromClientToken, mOptions); 834 } 835 } 836 } 837