diff options
4 files changed, 95 insertions, 1 deletions
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index f2ba16cf43d6..b4fec416bd5f 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -51,6 +51,17 @@ flag { } flag { + name: "use_cached_insets_for_display_switch" + namespace: "windowing_frontend" + description: "Reduce intermediate insets changes for display switch" + bug: "266197298" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "edge_to_edge_by_default" namespace: "windowing_frontend" description: "Make app go edge-to-edge by default when targeting SDK 35 or greater" diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index ec5b503fbb9b..c27aefa0b1bc 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -107,6 +107,7 @@ import android.view.InsetsFlags; import android.view.InsetsFrameProvider; import android.view.InsetsSource; import android.view.InsetsState; +import android.view.PrivacyIndicatorBounds; import android.view.Surface; import android.view.View; import android.view.ViewDebug; @@ -2121,6 +2122,8 @@ public class DisplayPolicy { } private static class Cache { + static final int TYPE_REGULAR_BARS = WindowInsets.Type.statusBars() + | WindowInsets.Type.navigationBars(); /** * 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. @@ -2130,6 +2133,14 @@ public class DisplayPolicy { int mPreserveId; boolean mActive; + /** + * When display switches, mRegularBarsInsets will assign to mPreservedInsets, and the + * insets sources of previous device state will copy to mRegularBarsInsets. + */ + ArrayList<InsetsSource> mPreservedInsets; + ArrayList<InsetsSource> mRegularBarsInsets; + PrivacyIndicatorBounds mPrivacyIndicatorBounds; + Cache(DisplayContent dc) { mDecorInsets = new DecorInsets(dc); } @@ -2138,6 +2149,17 @@ public class DisplayPolicy { return mPreserveId == ID_UPDATING_CONFIG || mDecorInsets.mDisplayContent .mTransitionController.inTransition(mPreserveId); } + + static ArrayList<InsetsSource> copyRegularBarInsets(InsetsState srcState) { + final ArrayList<InsetsSource> state = new ArrayList<>(); + for (int i = srcState.sourceSize() - 1; i >= 0; i--) { + final InsetsSource source = srcState.sourceAt(i); + if ((source.getType() & TYPE_REGULAR_BARS) != 0) { + state.add(new InsetsSource(source)); + } + } + return state; + } } } @@ -2213,24 +2235,60 @@ public class DisplayPolicy { @VisibleForTesting void updateCachedDecorInsets() { DecorInsets prevCache = null; + PrivacyIndicatorBounds privacyIndicatorBounds = null; if (mCachedDecorInsets == null) { mCachedDecorInsets = new DecorInsets.Cache(mDisplayContent); } else { prevCache = new DecorInsets(mDisplayContent); prevCache.setTo(mCachedDecorInsets.mDecorInsets); + privacyIndicatorBounds = mCachedDecorInsets.mPrivacyIndicatorBounds; + mCachedDecorInsets.mPreservedInsets = mCachedDecorInsets.mRegularBarsInsets; } // 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); + if (com.android.window.flags.Flags.useCachedInsetsForDisplaySwitch()) { + mCachedDecorInsets.mRegularBarsInsets = DecorInsets.Cache.copyRegularBarInsets( + mDisplayContent.mDisplayFrames.mInsetsState); + mCachedDecorInsets.mPrivacyIndicatorBounds = + mDisplayContent.mCurrentPrivacyIndicatorBounds; + } else { + mCachedDecorInsets.mRegularBarsInsets = null; + mCachedDecorInsets.mPrivacyIndicatorBounds = null; + } // Switch current to previous cache. if (prevCache != null) { mDecorInsets.setTo(prevCache); + if (privacyIndicatorBounds != null) { + mDisplayContent.mCurrentPrivacyIndicatorBounds = privacyIndicatorBounds; + } mCachedDecorInsets.mActive = true; } } /** + * This returns a new InsetsState with replacing the insets in target device state when the + * display is switching (e.g. fold/unfold). Otherwise, it returns the original state. This is + * to avoid dispatching old insets source before the insets providers update new insets. + */ + InsetsState replaceInsetsSourcesIfNeeded(InsetsState originalState, boolean copyState) { + if (mCachedDecorInsets == null || mCachedDecorInsets.mPreservedInsets == null + || !shouldKeepCurrentDecorInsets()) { + return originalState; + } + final ArrayList<InsetsSource> preservedSources = mCachedDecorInsets.mPreservedInsets; + final InsetsState state = copyState ? new InsetsState(originalState) : originalState; + for (int i = preservedSources.size() - 1; i >= 0; i--) { + final InsetsSource cacheSource = preservedSources.get(i); + if (state.peekSource(cacheSource.getId()) != null) { + state.addSource(new InsetsSource(cacheSource)); + } + } + return state; + } + + /** * 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. diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index 28722141dcd3..06754c4517ab 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -229,6 +229,7 @@ class InsetsPolicy { state = originalState; } state = adjustVisibilityForIme(target, state, state == originalState); + state = mPolicy.replaceInsetsSourcesIfNeeded(state, state == originalState); return adjustInsetsForRoundedCorners(target.mToken, state, state == originalState); } 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 4854f0d948b4..862158e8a0a1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java @@ -362,7 +362,19 @@ public class DisplayPolicyTests extends WindowTestsBase { @Test public void testSwitchDecorInsets() { - createNavBarWithProvidedInsets(mDisplayContent); + final WindowState win = createApplicationWindow(); + final WindowState bar = createNavBarWithProvidedInsets(mDisplayContent); + bar.getFrame().set(0, mDisplayContent.mDisplayFrames.mHeight - NAV_BAR_HEIGHT, + mDisplayContent.mDisplayFrames.mWidth, mDisplayContent.mDisplayFrames.mHeight); + final int insetsId = bar.mAttrs.providedInsets[0].getId(); + final InsetsSourceProvider provider = mDisplayContent.getInsetsStateController() + .getOrCreateSourceProvider(insetsId, bar.mAttrs.providedInsets[0].getType()); + provider.setServerVisible(true); + provider.updateSourceFrame(bar.getFrame()); + + final InsetsState prevInsetsState = new InsetsState(); + prevInsetsState.addSource(new InsetsSource(provider.getSource())); + final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); final DisplayInfo info = mDisplayContent.getDisplayInfo(); final int w = info.logicalWidth; @@ -385,6 +397,18 @@ public class DisplayPolicyTests extends WindowTestsBase { // The current insets are restored from cache directly. assertEquals(prevConfigFrame, displayPolicy.getDecorInsetsInfo(info.rotation, info.logicalWidth, info.logicalHeight).mConfigFrame); + // Assume that the InsetsSource in current InsetsState is not updated yet. And it will be + // replaced by the one in cache. + InsetsState currentInsetsState = new InsetsState(); + final InsetsSource prevSource = new InsetsSource(provider.getSource()); + prevSource.getFrame().scale(0.5f); + currentInsetsState.addSource(prevSource); + currentInsetsState = mDisplayContent.getInsetsPolicy().adjustInsetsForWindow( + win, currentInsetsState); + if (com.android.window.flags.Flags.useCachedInsetsForDisplaySwitch()) { + assertEquals(prevInsetsState.peekSource(insetsId), + currentInsetsState.peekSource(insetsId)); + } // If screen is not fully turned on, then the cache should be preserved. displayPolicy.screenTurnedOff(false /* acquireSleepToken */); |