• 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.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