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