Loading services/core/java/com/android/server/wm/DisplayContent.java +3 −1 Original line number Diff line number Diff line Loading @@ -2962,6 +2962,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mDisplaySwitchTransitionLauncher.requestDisplaySwitchTransitionIfNeeded(mDisplayId, mInitialDisplayWidth, mInitialDisplayHeight, newWidth, newHeight); mDisplayRotation.physicalDisplayChanged(); mDisplayPolicy.physicalDisplayChanged(); } // If there is an override set for base values - use it, otherwise use new values. Loading Loading @@ -2993,6 +2994,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp reconfigureDisplayLocked(); if (physicalDisplayChanged) { mDisplayPolicy.physicalDisplayUpdated(); mDisplaySwitchTransitionLauncher.onDisplayUpdated(currentRotation, getRotation(), getDisplayAreaInfo()); } Loading Loading @@ -3042,7 +3044,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp + mBaseDisplayHeight + " on display:" + getDisplayId()); } } if (mDisplayReady) { if (mDisplayReady && !mDisplayPolicy.shouldKeepCurrentDecorInsets()) { mDisplayPolicy.mDecorInsets.invalidate(); } } Loading services/core/java/com/android/server/wm/DisplayPolicy.java +120 −11 Original line number Diff line number Diff line Loading @@ -174,6 +174,10 @@ public class DisplayPolicy { private static final int INSETS_OVERRIDE_INDEX_INVALID = -1; // TODO(b/266197298): Remove this by a more general protocol from the insets providers. private static final boolean USE_CACHED_INSETS_FOR_DISPLAY_SWITCH = SystemProperties.getBoolean("persist.wm.debug.cached_insets_switch", false); private final WindowManagerService mService; private final Context mContext; private final Context mUiContext; Loading Loading @@ -218,6 +222,8 @@ public class DisplayPolicy { private SystemGesturesPointerEventListener mSystemGestures; final DecorInsets mDecorInsets; /** Currently it can only be non-null when physical display switch happens. */ private DecorInsets.Cache mCachedDecorInsets; private volatile int mLidState = LID_ABSENT; private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED; Loading Loading @@ -1707,11 +1713,7 @@ public class DisplayPolicy { * Called when the configuration has changed, and it's safe to load new values from resources. */ public void onConfigurationChanged() { final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation(); final Resources res = getCurrentUserResources(); final int portraitRotation = displayRotation.getPortraitRotation(); mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode); mLeftGestureInset = mGestureNavigationSettingsObserver.getLeftSensitivity(res); mRightGestureInset = mGestureNavigationSettingsObserver.getRightSensitivity(res); Loading Loading @@ -1882,10 +1884,11 @@ public class DisplayPolicy { @Override public String toString() { return "{nonDecorInsets=" + mNonDecorInsets + ", configInsets=" + mConfigInsets + ", nonDecorFrame=" + mNonDecorFrame + ", configFrame=" + mConfigFrame + '}'; final StringBuilder tmpSb = new StringBuilder(32); return "{nonDecorInsets=" + mNonDecorInsets.toShortString(tmpSb) + ", configInsets=" + mConfigInsets.toShortString(tmpSb) + ", nonDecorFrame=" + mNonDecorFrame.toShortString(tmpSb) + ", configFrame=" + mConfigFrame.toShortString(tmpSb) + '}'; } } Loading Loading @@ -1923,6 +1926,39 @@ public class DisplayPolicy { info.mNeedUpdate = true; } } void setTo(DecorInsets src) { for (int i = mInfoForRotation.length - 1; i >= 0; i--) { mInfoForRotation[i].set(src.mInfoForRotation[i]); } } void dump(String prefix, PrintWriter pw) { for (int rotation = 0; rotation < mInfoForRotation.length; rotation++) { final DecorInsets.Info info = mInfoForRotation[rotation]; pw.println(prefix + Surface.rotationToString(rotation) + "=" + info); } } private static class Cache { /** * If {@link #mPreserveId} is this value, it is in the middle of updating display * configuration before a transition is started. Then the active cache should be used. */ static final int ID_UPDATING_CONFIG = -1; final DecorInsets mDecorInsets; int mPreserveId; boolean mActive; Cache(DisplayContent dc) { mDecorInsets = new DecorInsets(dc); } boolean canPreserve() { return mPreserveId == ID_UPDATING_CONFIG || mDecorInsets.mDisplayContent .mTransitionController.inTransition(mPreserveId); } } } /** Loading @@ -1930,6 +1966,9 @@ public class DisplayPolicy { * call {@link DisplayContent#sendNewConfiguration()} if this method returns {@code true}. */ boolean updateDecorInsetsInfo() { if (shouldKeepCurrentDecorInsets()) { return false; } final DisplayFrames displayFrames = mDisplayContent.mDisplayFrames; final int rotation = displayFrames.mRotation; final int dw = displayFrames.mWidth; Loading @@ -1940,6 +1979,10 @@ public class DisplayPolicy { if (newInfo.mConfigFrame.equals(currentInfo.mConfigFrame)) { return false; } if (mCachedDecorInsets != null && !mCachedDecorInsets.canPreserve() && !mDisplayContent.isSleeping()) { mCachedDecorInsets = null; } mDecorInsets.invalidate(); mDecorInsets.mInfoForRotation[rotation].set(newInfo); return true; Loading @@ -1949,6 +1992,71 @@ public class DisplayPolicy { return mDecorInsets.get(rotation, w, h); } /** Returns {@code true} to trust that {@link #mDecorInsets} already has the expected state. */ boolean shouldKeepCurrentDecorInsets() { return mCachedDecorInsets != null && mCachedDecorInsets.mActive && mCachedDecorInsets.canPreserve(); } void physicalDisplayChanged() { if (USE_CACHED_INSETS_FOR_DISPLAY_SWITCH) { updateCachedDecorInsets(); } } /** * Caches the current insets and switches current insets to previous cached insets. This is to * reduce multiple display configuration changes if there are multiple insets provider windows * which may trigger {@link #updateDecorInsetsInfo()} individually. */ @VisibleForTesting void updateCachedDecorInsets() { DecorInsets prevCache = null; if (mCachedDecorInsets == null) { mCachedDecorInsets = new DecorInsets.Cache(mDisplayContent); } else { prevCache = new DecorInsets(mDisplayContent); prevCache.setTo(mCachedDecorInsets.mDecorInsets); } // Set a special id to preserve it before a real id is available from transition. mCachedDecorInsets.mPreserveId = DecorInsets.Cache.ID_UPDATING_CONFIG; // Cache the current insets. mCachedDecorInsets.mDecorInsets.setTo(mDecorInsets); // Switch current to previous cache. if (prevCache != null) { mDecorInsets.setTo(prevCache); mCachedDecorInsets.mActive = true; } } /** * Called after the display configuration is updated according to the physical change. Suppose * there should be a display change transition, so associate the cached decor insets with the * transition to limit the lifetime of using the cache. */ void physicalDisplayUpdated() { if (mCachedDecorInsets == null) { return; } if (!mDisplayContent.mTransitionController.isCollecting()) { // Unable to know when the display switch is finished. mCachedDecorInsets = null; return; } mCachedDecorInsets.mPreserveId = mDisplayContent.mTransitionController.getCollectingTransitionId(); // The validator will run after the transition is finished. So if the insets are changed // during the transition, it can update to the latest state. mDisplayContent.mTransitionController.mStateValidators.add(() -> { // The insets provider client may defer to change its window until screen is on. So // only validate when awake to avoid the cache being always dropped. if (!mDisplayContent.isSleeping() && updateDecorInsetsInfo()) { Slog.d(TAG, "Insets changed after display switch transition"); mDisplayContent.sendNewConfiguration(); } }); } @NavigationBarPosition int navigationBarPosition(int displayRotation) { if (mNavigationBar != null) { Loading Loading @@ -2626,9 +2734,10 @@ public class DisplayPolicy { pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars="); pw.println(mRemoteInsetsControllerControlsSystemBars); pw.print(prefix); pw.println("mDecorInsetsInfo:"); for (int rotation = 0; rotation < mDecorInsets.mInfoForRotation.length; rotation++) { final DecorInsets.Info info = mDecorInsets.mInfoForRotation[rotation]; pw.println(prefixInner + Surface.rotationToString(rotation) + "=" + info); mDecorInsets.dump(prefixInner, pw); if (mCachedDecorInsets != null) { pw.print(prefix); pw.println("mCachedDecorInsets:"); mCachedDecorInsets.mDecorInsets.dump(prefixInner, pw); } if (!CLIENT_TRANSIENT) { mSystemGestures.dump(pw, prefix); Loading services/core/java/com/android/server/wm/TransitionController.java +13 −0 Original line number Diff line number Diff line Loading @@ -431,6 +431,19 @@ class TransitionController { return inCollectingTransition(wc) || inPlayingTransition(wc); } /** Returns {@code true} if the id matches a collecting or playing transition. */ boolean inTransition(int syncId) { if (mCollectingTransition != null && mCollectingTransition.getSyncId() == syncId) { return true; } for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) { if (mPlayingTransitions.get(i).getSyncId() == syncId) { return true; } } return false; } /** @return {@code true} if wc is in a participant subtree */ boolean isTransitionOnDisplay(@NonNull DisplayContent dc) { if (mCollectingTransition != null && mCollectingTransition.isOnDisplay(dc)) { Loading services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java +27 −0 Original line number Diff line number Diff line Loading @@ -300,6 +300,33 @@ public class DisplayPolicyTests extends WindowTestsBase { DisplayPolicy.isOverlappingWithNavBar(targetWin)); } @Test public void testSwitchDecorInsets() { createNavBarWithProvidedInsets(mDisplayContent); final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); final DisplayInfo info = mDisplayContent.getDisplayInfo(); final int w = info.logicalWidth; final int h = info.logicalHeight; displayPolicy.updateDecorInsetsInfo(); final Rect prevConfigFrame = new Rect(displayPolicy.getDecorInsetsInfo(info.rotation, info.logicalWidth, info.logicalHeight).mConfigFrame); displayPolicy.updateCachedDecorInsets(); mDisplayContent.updateBaseDisplayMetrics(w / 2, h / 2, info.logicalDensityDpi, info.physicalXDpi, info.physicalYDpi); // There is no previous cache. But the current state will be cached. assertFalse(displayPolicy.shouldKeepCurrentDecorInsets()); // Switch to original state. displayPolicy.updateCachedDecorInsets(); mDisplayContent.updateBaseDisplayMetrics(w, h, info.logicalDensityDpi, info.physicalXDpi, info.physicalYDpi); assertTrue(displayPolicy.shouldKeepCurrentDecorInsets()); // The current insets are restored from cache directly. assertEquals(prevConfigFrame, displayPolicy.getDecorInsetsInfo(info.rotation, info.logicalWidth, info.logicalHeight).mConfigFrame); } @Test public void testUpdateDisplayConfigurationByDecor() { doReturn(NO_CUTOUT).when(mDisplayContent).calculateDisplayCutoutForRotation(anyInt()); Loading Loading
services/core/java/com/android/server/wm/DisplayContent.java +3 −1 Original line number Diff line number Diff line Loading @@ -2962,6 +2962,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mDisplaySwitchTransitionLauncher.requestDisplaySwitchTransitionIfNeeded(mDisplayId, mInitialDisplayWidth, mInitialDisplayHeight, newWidth, newHeight); mDisplayRotation.physicalDisplayChanged(); mDisplayPolicy.physicalDisplayChanged(); } // If there is an override set for base values - use it, otherwise use new values. Loading Loading @@ -2993,6 +2994,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp reconfigureDisplayLocked(); if (physicalDisplayChanged) { mDisplayPolicy.physicalDisplayUpdated(); mDisplaySwitchTransitionLauncher.onDisplayUpdated(currentRotation, getRotation(), getDisplayAreaInfo()); } Loading Loading @@ -3042,7 +3044,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp + mBaseDisplayHeight + " on display:" + getDisplayId()); } } if (mDisplayReady) { if (mDisplayReady && !mDisplayPolicy.shouldKeepCurrentDecorInsets()) { mDisplayPolicy.mDecorInsets.invalidate(); } } Loading
services/core/java/com/android/server/wm/DisplayPolicy.java +120 −11 Original line number Diff line number Diff line Loading @@ -174,6 +174,10 @@ public class DisplayPolicy { private static final int INSETS_OVERRIDE_INDEX_INVALID = -1; // TODO(b/266197298): Remove this by a more general protocol from the insets providers. private static final boolean USE_CACHED_INSETS_FOR_DISPLAY_SWITCH = SystemProperties.getBoolean("persist.wm.debug.cached_insets_switch", false); private final WindowManagerService mService; private final Context mContext; private final Context mUiContext; Loading Loading @@ -218,6 +222,8 @@ public class DisplayPolicy { private SystemGesturesPointerEventListener mSystemGestures; final DecorInsets mDecorInsets; /** Currently it can only be non-null when physical display switch happens. */ private DecorInsets.Cache mCachedDecorInsets; private volatile int mLidState = LID_ABSENT; private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED; Loading Loading @@ -1707,11 +1713,7 @@ public class DisplayPolicy { * Called when the configuration has changed, and it's safe to load new values from resources. */ public void onConfigurationChanged() { final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation(); final Resources res = getCurrentUserResources(); final int portraitRotation = displayRotation.getPortraitRotation(); mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode); mLeftGestureInset = mGestureNavigationSettingsObserver.getLeftSensitivity(res); mRightGestureInset = mGestureNavigationSettingsObserver.getRightSensitivity(res); Loading Loading @@ -1882,10 +1884,11 @@ public class DisplayPolicy { @Override public String toString() { return "{nonDecorInsets=" + mNonDecorInsets + ", configInsets=" + mConfigInsets + ", nonDecorFrame=" + mNonDecorFrame + ", configFrame=" + mConfigFrame + '}'; final StringBuilder tmpSb = new StringBuilder(32); return "{nonDecorInsets=" + mNonDecorInsets.toShortString(tmpSb) + ", configInsets=" + mConfigInsets.toShortString(tmpSb) + ", nonDecorFrame=" + mNonDecorFrame.toShortString(tmpSb) + ", configFrame=" + mConfigFrame.toShortString(tmpSb) + '}'; } } Loading Loading @@ -1923,6 +1926,39 @@ public class DisplayPolicy { info.mNeedUpdate = true; } } void setTo(DecorInsets src) { for (int i = mInfoForRotation.length - 1; i >= 0; i--) { mInfoForRotation[i].set(src.mInfoForRotation[i]); } } void dump(String prefix, PrintWriter pw) { for (int rotation = 0; rotation < mInfoForRotation.length; rotation++) { final DecorInsets.Info info = mInfoForRotation[rotation]; pw.println(prefix + Surface.rotationToString(rotation) + "=" + info); } } private static class Cache { /** * If {@link #mPreserveId} is this value, it is in the middle of updating display * configuration before a transition is started. Then the active cache should be used. */ static final int ID_UPDATING_CONFIG = -1; final DecorInsets mDecorInsets; int mPreserveId; boolean mActive; Cache(DisplayContent dc) { mDecorInsets = new DecorInsets(dc); } boolean canPreserve() { return mPreserveId == ID_UPDATING_CONFIG || mDecorInsets.mDisplayContent .mTransitionController.inTransition(mPreserveId); } } } /** Loading @@ -1930,6 +1966,9 @@ public class DisplayPolicy { * call {@link DisplayContent#sendNewConfiguration()} if this method returns {@code true}. */ boolean updateDecorInsetsInfo() { if (shouldKeepCurrentDecorInsets()) { return false; } final DisplayFrames displayFrames = mDisplayContent.mDisplayFrames; final int rotation = displayFrames.mRotation; final int dw = displayFrames.mWidth; Loading @@ -1940,6 +1979,10 @@ public class DisplayPolicy { if (newInfo.mConfigFrame.equals(currentInfo.mConfigFrame)) { return false; } if (mCachedDecorInsets != null && !mCachedDecorInsets.canPreserve() && !mDisplayContent.isSleeping()) { mCachedDecorInsets = null; } mDecorInsets.invalidate(); mDecorInsets.mInfoForRotation[rotation].set(newInfo); return true; Loading @@ -1949,6 +1992,71 @@ public class DisplayPolicy { return mDecorInsets.get(rotation, w, h); } /** Returns {@code true} to trust that {@link #mDecorInsets} already has the expected state. */ boolean shouldKeepCurrentDecorInsets() { return mCachedDecorInsets != null && mCachedDecorInsets.mActive && mCachedDecorInsets.canPreserve(); } void physicalDisplayChanged() { if (USE_CACHED_INSETS_FOR_DISPLAY_SWITCH) { updateCachedDecorInsets(); } } /** * Caches the current insets and switches current insets to previous cached insets. This is to * reduce multiple display configuration changes if there are multiple insets provider windows * which may trigger {@link #updateDecorInsetsInfo()} individually. */ @VisibleForTesting void updateCachedDecorInsets() { DecorInsets prevCache = null; if (mCachedDecorInsets == null) { mCachedDecorInsets = new DecorInsets.Cache(mDisplayContent); } else { prevCache = new DecorInsets(mDisplayContent); prevCache.setTo(mCachedDecorInsets.mDecorInsets); } // Set a special id to preserve it before a real id is available from transition. mCachedDecorInsets.mPreserveId = DecorInsets.Cache.ID_UPDATING_CONFIG; // Cache the current insets. mCachedDecorInsets.mDecorInsets.setTo(mDecorInsets); // Switch current to previous cache. if (prevCache != null) { mDecorInsets.setTo(prevCache); mCachedDecorInsets.mActive = true; } } /** * Called after the display configuration is updated according to the physical change. Suppose * there should be a display change transition, so associate the cached decor insets with the * transition to limit the lifetime of using the cache. */ void physicalDisplayUpdated() { if (mCachedDecorInsets == null) { return; } if (!mDisplayContent.mTransitionController.isCollecting()) { // Unable to know when the display switch is finished. mCachedDecorInsets = null; return; } mCachedDecorInsets.mPreserveId = mDisplayContent.mTransitionController.getCollectingTransitionId(); // The validator will run after the transition is finished. So if the insets are changed // during the transition, it can update to the latest state. mDisplayContent.mTransitionController.mStateValidators.add(() -> { // The insets provider client may defer to change its window until screen is on. So // only validate when awake to avoid the cache being always dropped. if (!mDisplayContent.isSleeping() && updateDecorInsetsInfo()) { Slog.d(TAG, "Insets changed after display switch transition"); mDisplayContent.sendNewConfiguration(); } }); } @NavigationBarPosition int navigationBarPosition(int displayRotation) { if (mNavigationBar != null) { Loading Loading @@ -2626,9 +2734,10 @@ public class DisplayPolicy { pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars="); pw.println(mRemoteInsetsControllerControlsSystemBars); pw.print(prefix); pw.println("mDecorInsetsInfo:"); for (int rotation = 0; rotation < mDecorInsets.mInfoForRotation.length; rotation++) { final DecorInsets.Info info = mDecorInsets.mInfoForRotation[rotation]; pw.println(prefixInner + Surface.rotationToString(rotation) + "=" + info); mDecorInsets.dump(prefixInner, pw); if (mCachedDecorInsets != null) { pw.print(prefix); pw.println("mCachedDecorInsets:"); mCachedDecorInsets.mDecorInsets.dump(prefixInner, pw); } if (!CLIENT_TRANSIENT) { mSystemGestures.dump(pw, prefix); Loading
services/core/java/com/android/server/wm/TransitionController.java +13 −0 Original line number Diff line number Diff line Loading @@ -431,6 +431,19 @@ class TransitionController { return inCollectingTransition(wc) || inPlayingTransition(wc); } /** Returns {@code true} if the id matches a collecting or playing transition. */ boolean inTransition(int syncId) { if (mCollectingTransition != null && mCollectingTransition.getSyncId() == syncId) { return true; } for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) { if (mPlayingTransitions.get(i).getSyncId() == syncId) { return true; } } return false; } /** @return {@code true} if wc is in a participant subtree */ boolean isTransitionOnDisplay(@NonNull DisplayContent dc) { if (mCollectingTransition != null && mCollectingTransition.isOnDisplay(dc)) { Loading
services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java +27 −0 Original line number Diff line number Diff line Loading @@ -300,6 +300,33 @@ public class DisplayPolicyTests extends WindowTestsBase { DisplayPolicy.isOverlappingWithNavBar(targetWin)); } @Test public void testSwitchDecorInsets() { createNavBarWithProvidedInsets(mDisplayContent); final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); final DisplayInfo info = mDisplayContent.getDisplayInfo(); final int w = info.logicalWidth; final int h = info.logicalHeight; displayPolicy.updateDecorInsetsInfo(); final Rect prevConfigFrame = new Rect(displayPolicy.getDecorInsetsInfo(info.rotation, info.logicalWidth, info.logicalHeight).mConfigFrame); displayPolicy.updateCachedDecorInsets(); mDisplayContent.updateBaseDisplayMetrics(w / 2, h / 2, info.logicalDensityDpi, info.physicalXDpi, info.physicalYDpi); // There is no previous cache. But the current state will be cached. assertFalse(displayPolicy.shouldKeepCurrentDecorInsets()); // Switch to original state. displayPolicy.updateCachedDecorInsets(); mDisplayContent.updateBaseDisplayMetrics(w, h, info.logicalDensityDpi, info.physicalXDpi, info.physicalYDpi); assertTrue(displayPolicy.shouldKeepCurrentDecorInsets()); // The current insets are restored from cache directly. assertEquals(prevConfigFrame, displayPolicy.getDecorInsetsInfo(info.rotation, info.logicalWidth, info.logicalHeight).mConfigFrame); } @Test public void testUpdateDisplayConfigurationByDecor() { doReturn(NO_CUTOUT).when(mDisplayContent).calculateDisplayCutoutForRotation(anyInt()); Loading