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