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