• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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