From 0711ce3cb22c5c71c6bdf6be951b81d9a2e551c2 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Fri, 12 May 2023 08:20:00 +0000 Subject: Enable insets cache for display switch To reduce latency of physical display switch. Bug: 266197298 Bug: 293131586 Bug: 292472402 Test: Check latency of fold/unfold. (cherry picked from commit 5dfc7882dfa7431f8d3df257fe59ebfaa15705e2) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:b71e95146f2c2241ab48c4602e4cbcec87d246da) Merged-In: Id2e796edee45dae281f867c2b1549a80984c8a8e Change-Id: Id2e796edee45dae281f867c2b1549a80984c8a8e --- services/core/java/com/android/server/wm/DisplayPolicy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 95c953a5cf2d..a1a9a0877710 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -176,7 +176,7 @@ public class DisplayPolicy { // 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); + SystemProperties.getBoolean("persist.wm.debug.cached_insets_switch", true); private final WindowManagerService mService; private final Context mContext; -- cgit v1.2.3-59-g8ed1b From 4e6f49df54e7cf40e3bc8df735d3e15d4644002a Mon Sep 17 00:00:00 2001 From: Caitlin Shkuratov Date: Tue, 11 Jul 2023 19:32:41 +0000 Subject: [Status Bar] Set status bar window insets to status bar height always. This is needed for the animation shown when you tap the ongoing call chip in order to launch the call app. If we do *not* set the insets, then the insets will change during the animation, which will result in the animation being cancelled and show jank when launching the app. This CL is improvement of ag/23875866. That CL originally caused b/290300359, where the status bar height changed but the insets were *not* changed, so the insets were too small. This CL also adds the insets to the #applyHeight function, which is called when the status bar height changes. Bug: 283958440 Test: tap on ongoing call chip -> verify no jank during animation Test: status bar smoke test on phone (verify status bar in portrait and landscape, with and without ongoing call chip) Test: status bar smoke test on tablet (same as above) Test: status bar smoke test on foldable (same as above) Test: regression test for b/290300359: Boot foldable device while unfolded (no display cutout) > fold device (has display cutout now) > open app > verify there's no white/black bar showing between the status bar and the app (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4b89585868f4c95b2458bb1eef77587a896751a7) Merged-In: I35df87ef05cb75dcd551cc4899a0a9863fdcbcc7 Change-Id: I35df87ef05cb75dcd551cc4899a0a9863fdcbcc7 --- .../window/StatusBarWindowController.java | 35 +++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java index bcf3b0cbfc86..24987abd7a85 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java @@ -240,8 +240,10 @@ public class StatusBarWindowController { Insets.of(0, safeTouchRegionHeight, 0, 0)); } lp.providedInsets = new InsetsFrameProvider[] { - new InsetsFrameProvider(mInsetsSourceOwner, 0, statusBars()), - new InsetsFrameProvider(mInsetsSourceOwner, 0, tappableElement()), + new InsetsFrameProvider(mInsetsSourceOwner, 0, statusBars()) + .setInsetsSize(getInsets(height)), + new InsetsFrameProvider(mInsetsSourceOwner, 0, tappableElement()) + .setInsetsSize(getInsets(height)), gestureInsetsProvider }; return lp; @@ -306,12 +308,37 @@ public class StatusBarWindowController { mLpChanged.height = state.mIsLaunchAnimationRunning ? ViewGroup.LayoutParams.MATCH_PARENT : mBarHeight; for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) { + int height = SystemBarUtils.getStatusBarHeightForRotation(mContext, rot); mLpChanged.paramsForRotation[rot].height = - state.mIsLaunchAnimationRunning ? ViewGroup.LayoutParams.MATCH_PARENT : - SystemBarUtils.getStatusBarHeightForRotation(mContext, rot); + state.mIsLaunchAnimationRunning ? ViewGroup.LayoutParams.MATCH_PARENT : height; + // The status bar height could change at runtime if one display has a cutout while + // another doesn't (like some foldables). It could also change when using debug cutouts. + // So, we need to re-fetch the height and re-apply it to the insets each time to avoid + // bugs like b/290300359. + InsetsFrameProvider[] providers = mLpChanged.paramsForRotation[rot].providedInsets; + if (providers != null) { + for (InsetsFrameProvider provider : providers) { + provider.setInsetsSize(getInsets(height)); + } + } } } + /** + * Get the insets that should be applied to the status bar window given the current status bar + * height. + * + * The status bar window height can sometimes be full-screen (see {@link #applyHeight(State)}. + * However, the status bar *insets* should *not* be full-screen, because this would prevent apps + * from drawing any content and can cause animations to be cancelled (see b/283958440). Instead, + * the status bar insets should always be equal to the space occupied by the actual status bar + * content -- setting the insets correctly will prevent window manager from unnecessarily + * re-drawing this window and other windows. This method provides the correct insets. + */ + private Insets getInsets(int height) { + return Insets.of(0, height, 0, 0); + } + private void apply(State state) { if (!mIsAttached) { return; -- cgit v1.2.3-59-g8ed1b From f50850a5ed138bb3628260f6270437f0e621943d Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Wed, 2 Aug 2023 05:56:42 +0000 Subject: Fix biometric context update problem. Bug: b/288761850 Test: Check b/288761850 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a7c50568f6e09782429b31eedd547bf72b001d30) Merged-In: I890d102d10a3efa230e26e4e9753f9c66b71afdb Change-Id: I890d102d10a3efa230e26e4e9753f9c66b71afdb --- .../server/biometrics/log/BiometricContextProvider.java | 4 ++++ .../server/biometrics/log/BiometricContextProviderTest.java | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java index fc3d7c8114b0..745222873698 100644 --- a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java +++ b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java @@ -216,6 +216,10 @@ public final class BiometricContextProvider implements BiometricContext { public void subscribe(@NonNull OperationContextExt context, @NonNull Consumer consumer) { mSubscribers.put(context, consumer); + // TODO(b/294161627) Combine the getContext/subscribe APIs to avoid race + if (context.getDisplayState() != getDisplayState()) { + consumer.accept(context.update(this, context.isCrypto()).toAidlContext()); + } } @Override diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java index a4423038a072..437510595ecb 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java @@ -251,6 +251,14 @@ public class BiometricContextProviderTest { assertThat(actual).containsExactly(true, false, true, true, false, false).inOrder(); } + @Test + public void testSubscribesWithDifferentState() throws RemoteException { + final Consumer nonEmptyConsumer = mock(Consumer.class); + mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_AOD); + mProvider.subscribe(mOpContext, nonEmptyConsumer); + verify(nonEmptyConsumer).accept(same(mOpContext.toAidlContext())); + } + @Test public void testUnsubscribes() throws RemoteException { final Consumer emptyConsumer = mock(Consumer.class); @@ -259,6 +267,9 @@ public class BiometricContextProviderTest { mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_AOD); + //reset to unknown to avoid trigger accept when subscribe + mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_UNKNOWN); + final Consumer nonEmptyConsumer = mock(Consumer.class); mProvider.subscribe(mOpContext, nonEmptyConsumer); mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN); -- cgit v1.2.3-59-g8ed1b From 54e819540383b5b0819c0ba4826e0cd3cdfe4484 Mon Sep 17 00:00:00 2001 From: Mike Schneider Date: Fri, 7 Jul 2023 15:09:56 +0200 Subject: Change behind-scrim's tint in BOUNCER state to match GM3 surface color. This is in lieu of relying on the KeyguardSecurityContainer to paint the background with surfaceColor. It fixes an issue during KeyguardSecurityContainer's vertical translation, triggered either via a gesture or during the bouncer dismiss animation, where the wrong color tone is surfaced and the alpha fades conflict. Bug: 281965452 Test: unit tests Test: manually tested bouncer on large screen, incl theme change http://shortn/_DVOtSJtrwy (cherry picked from commit d71e5c8fe2db8e8b0dab26c5979c576a88243316) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:83b55b6a673170d162dd315a6711ff42603c74ba) Merged-In: I67149c6faa2766be6d2537f2315dd2734bdd0447 Change-Id: I67149c6faa2766be6d2537f2315dd2734bdd0447 --- .../keyguard/KeyguardSecurityContainer.java | 2 - .../systemui/statusbar/phone/ScrimController.java | 7 +++ .../systemui/statusbar/phone/ScrimState.java | 15 +++++- .../statusbar/phone/ScrimControllerTest.java | 59 +++++++++++++++++++--- 4 files changed, 72 insertions(+), 11 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 841b5b3a1e82..9ff338e8d5ab 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -786,8 +786,6 @@ public class KeyguardSecurityContainer extends ConstraintLayout { void reloadColors() { mViewMode.reloadColors(); - setBackgroundColor(Utils.getColorAttrDefaultColor(getContext(), - com.android.internal.R.attr.materialColorSurface)); } /** Handles density or font scale changes. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 25ecf1a424e0..c42a6dc5b6f2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -1509,6 +1509,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump mColors.setSupportsDarkText( ColorUtils.calculateContrast(mColors.getMainColor(), Color.WHITE) > 4.5); } + + int surface = Utils.getColorAttr(mScrimBehind.getContext(), + com.android.internal.R.attr.materialColorSurface).getDefaultColor(); + for (ScrimState state : ScrimState.values()) { + state.setSurfaceColor(surface); + } + mNeedsDrawableColorUpdate = true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java index 7b2028310a84..e3b65ab27f48 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -122,11 +122,19 @@ public enum ScrimState { @Override public void prepare(ScrimState previousState) { mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha; - mBehindTint = mClipQsScrim ? Color.BLACK : Color.TRANSPARENT; + mBehindTint = mClipQsScrim ? Color.BLACK : mSurfaceColor; mNotifAlpha = mClipQsScrim ? mDefaultScrimAlpha : 0; mNotifTint = Color.TRANSPARENT; mFrontAlpha = 0f; } + + @Override + public void setSurfaceColor(int surfaceColor) { + super.setSurfaceColor(surfaceColor); + if (!mClipQsScrim) { + mBehindTint = mSurfaceColor; + } + } }, /** @@ -295,6 +303,7 @@ public enum ScrimState { int mFrontTint = Color.TRANSPARENT; int mBehindTint = Color.TRANSPARENT; int mNotifTint = Color.TRANSPARENT; + int mSurfaceColor = Color.TRANSPARENT; boolean mAnimateChange = true; float mAodFrontScrimAlpha; @@ -409,6 +418,10 @@ public enum ScrimState { mDefaultScrimAlpha = defaultScrimAlpha; } + public void setSurfaceColor(int surfaceColor) { + mSurfaceColor = surfaceColor; + } + public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) { mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index a9ed17531926..7fc02280354f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -44,6 +44,9 @@ import static kotlinx.coroutines.flow.FlowKt.emptyFlow; import android.animation.Animator; import android.app.AlarmManager; +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.TypedArray; import android.graphics.Color; import android.os.Handler; import android.testing.AndroidTestingRunner; @@ -121,6 +124,7 @@ public class ScrimControllerTest extends SysuiTestCase { private int mScrimVisibility; private boolean mAlwaysOnEnabled; private TestableLooper mLooper; + private Context mContext; @Mock private AlarmManager mAlarmManager; @Mock private DozeParameters mDozeParameters; @Mock private LightBarController mLightBarController; @@ -134,6 +138,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel; @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor; @Mock private CoroutineDispatcher mMainDispatcher; + @Mock private TypedArray mMockTypedArray; // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The // event-dispatch-on-registration pattern caused some of these unit tests to fail.) @@ -182,10 +187,11 @@ public class ScrimControllerTest extends SysuiTestCase { mNumEnds = 0; mNumCancels = 0; } - }; + } private AnimatorListener mAnimatorListener = new AnimatorListener(); + private int mSurfaceColor = 0x112233; private void finishAnimationsImmediately() { // Execute code that will trigger animations. @@ -214,10 +220,17 @@ public class ScrimControllerTest extends SysuiTestCase { @Before public void setup() { MockitoAnnotations.initMocks(this); + mContext = spy(getContext()); + when(mContext.obtainStyledAttributes( + new int[]{com.android.internal.R.attr.materialColorSurface})) + .thenReturn(mMockTypedArray); + + when(mMockTypedArray.getColorStateList(anyInt())) + .thenAnswer((invocation) -> ColorStateList.valueOf(mSurfaceColor)); - mScrimBehind = spy(new ScrimView(getContext())); - mScrimInFront = new ScrimView(getContext()); - mNotificationsScrim = new ScrimView(getContext()); + mScrimBehind = spy(new ScrimView(mContext)); + mScrimInFront = new ScrimView(mContext); + mNotificationsScrim = new ScrimView(mContext); mAlwaysOnEnabled = true; mLooper = TestableLooper.get(this); DejankUtils.setImmediate(true); @@ -577,7 +590,7 @@ public class ScrimControllerTest extends SysuiTestCase { mScrimController.transitionTo(BOUNCER); finishAnimationsImmediately(); // Front scrim should be transparent - // Back scrim should be visible without tint + // Back scrim should be visible and tinted to the surface color assertScrimAlpha(Map.of( mScrimInFront, TRANSPARENT, mNotificationsScrim, TRANSPARENT, @@ -585,9 +598,31 @@ public class ScrimControllerTest extends SysuiTestCase { assertScrimTinted(Map.of( mScrimInFront, false, - mScrimBehind, false, + mScrimBehind, true, mNotificationsScrim, false )); + + assertScrimTint(mScrimBehind, mSurfaceColor); + } + + @Test + public void onThemeChange_bouncerBehindTint_isUpdatedToSurfaceColor() { + assertEquals(BOUNCER.getBehindTint(), 0x112233); + mSurfaceColor = 0x223344; + mConfigurationController.notifyThemeChanged(); + assertEquals(BOUNCER.getBehindTint(), 0x223344); + } + + @Test + public void onThemeChangeWhileClipQsScrim_bouncerBehindTint_remainsBlack() { + mScrimController.setClipsQsScrim(true); + mScrimController.transitionTo(BOUNCER); + finishAnimationsImmediately(); + + assertEquals(BOUNCER.getBehindTint(), Color.BLACK); + mSurfaceColor = 0x223344; + mConfigurationController.notifyThemeChanged(); + assertEquals(BOUNCER.getBehindTint(), Color.BLACK); } @Test @@ -619,16 +654,17 @@ public class ScrimControllerTest extends SysuiTestCase { finishAnimationsImmediately(); // Front scrim should be transparent - // Back scrim should be visible without tint + // Back scrim should be visible and has a tint of surfaceColor assertScrimAlpha(Map.of( mScrimInFront, TRANSPARENT, mNotificationsScrim, TRANSPARENT, mScrimBehind, OPAQUE)); assertScrimTinted(Map.of( mScrimInFront, false, - mScrimBehind, false, + mScrimBehind, true, mNotificationsScrim, false )); + assertScrimTint(mScrimBehind, mSurfaceColor); } @Test @@ -1809,6 +1845,13 @@ public class ScrimControllerTest extends SysuiTestCase { assertEquals(message, hasTint, scrim.getTint() != Color.TRANSPARENT); } + private void assertScrimTint(ScrimView scrim, int expectedTint) { + String message = "Tint test failed with expected scrim tint: " + + Integer.toHexString(expectedTint) + " and actual tint: " + + Integer.toHexString(scrim.getTint()) + " for scrim: " + getScrimName(scrim); + assertEquals(message, expectedTint, scrim.getTint(), 0.1); + } + private String getScrimName(ScrimView scrim) { if (scrim == mScrimInFront) { return "front"; -- cgit v1.2.3-59-g8ed1b