summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java4
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java131
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java13
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java27
4 files changed, 163 insertions, 12 deletions
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 57812c1d604c..2b5648f39d2c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -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.
@@ -2993,6 +2994,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
reconfigureDisplayLocked();
if (physicalDisplayChanged) {
+ mDisplayPolicy.physicalDisplayUpdated();
mDisplaySwitchTransitionLauncher.onDisplayUpdated(currentRotation, getRotation(),
getDisplayAreaInfo());
}
@@ -3042,7 +3044,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
+ mBaseDisplayHeight + " on display:" + getDisplayId());
}
}
- if (mDisplayReady) {
+ if (mDisplayReady && !mDisplayPolicy.shouldKeepCurrentDecorInsets()) {
mDisplayPolicy.mDecorInsets.invalidate();
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index be52e5a4566b..0dac7d6cb546 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -173,6 +173,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;
@@ -217,6 +221,8 @@ public class DisplayPolicy {
private final 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;
@@ -1695,11 +1701,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);
@@ -1870,10 +1872,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) + '}';
}
}
@@ -1911,6 +1914,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);
+ }
+ }
}
/**
@@ -1918,6 +1954,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;
@@ -1928,6 +1967,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;
@@ -1937,6 +1980,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) {
@@ -2613,9 +2721,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);
}
mSystemGestures.dump(pw, prefix);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index c9316bf6e972..9890f135c462 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -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)) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 353a8ecaf13d..5d5a3a5e48f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -299,6 +299,33 @@ public class DisplayPolicyTests extends WindowTestsBase {
}
@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());
final WindowState navbar = createNavBarWithProvidedInsets(mDisplayContent);