Loading core/java/android/window/flags/windowing_frontend.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,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" Loading services/core/java/com/android/server/wm/DisplayPolicy.java +58 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading @@ -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); } Loading @@ -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; } } } Loading Loading @@ -2213,23 +2235,59 @@ 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 Loading services/core/java/com/android/server/wm/InsetsPolicy.java +1 −0 Original line number Diff line number Diff line Loading @@ -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); } Loading services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java +25 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 */); Loading Loading
core/java/android/window/flags/windowing_frontend.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,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" Loading
services/core/java/com/android/server/wm/DisplayPolicy.java +58 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading @@ -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); } Loading @@ -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; } } } Loading Loading @@ -2213,23 +2235,59 @@ 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 Loading
services/core/java/com/android/server/wm/InsetsPolicy.java +1 −0 Original line number Diff line number Diff line Loading @@ -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); } Loading
services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java +25 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 */); Loading