diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 08e1654c8dbf9..701d1391d2711 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -113,6 +113,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationShadeDepthController; +import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.DozeParameters; @@ -318,6 +319,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, // the properties of the keyguard private final KeyguardUpdateMonitor mUpdateMonitor; + private final Lazy mNotificationShadeWindowControllerLazy; /** * Last SIM state reported by the telephony system. @@ -833,7 +835,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, ScreenOffAnimationController screenOffAnimationController, Lazy notificationShadeDepthController, ScreenOnCoordinator screenOnCoordinator, - InteractionJankMonitor interactionJankMonitor) { + InteractionJankMonitor interactionJankMonitor, + Lazy notificationShadeWindowControllerLazy) { super(context); mFalsingCollector = falsingCollector; mLockPatternUtils = lockPatternUtils; @@ -850,6 +853,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, dumpManager.registerDumpable(getClass().getName(), this); mDeviceConfig = deviceConfig; mScreenOnCoordinator = screenOnCoordinator; + mNotificationShadeWindowControllerLazy = notificationShadeWindowControllerLazy; mShowHomeOverLockscreen = mDeviceConfig.getBoolean( DeviceConfig.NAMESPACE_SYSTEMUI, NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, @@ -1837,10 +1841,14 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, Trace.beginSection( "KeyguardViewMediator#handleMessage START_KEYGUARD_EXIT_ANIM"); StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj; - handleStartKeyguardExitAnimation(params.startTime, params.fadeoutDuration, - params.mApps, params.mWallpapers, params.mNonApps, - params.mFinishedCallback); - mFalsingCollector.onSuccessfulUnlock(); + mNotificationShadeWindowControllerLazy.get().batchApplyWindowLayoutParams( + () -> { + handleStartKeyguardExitAnimation(params.startTime, + params.fadeoutDuration, + params.mApps, params.mWallpapers, params.mNonApps, + params.mFinishedCallback); + mFalsingCollector.onSuccessfulUnlock(); + }); Trace.endSection(); break; case CANCEL_KEYGUARD_EXIT_ANIM: @@ -2139,10 +2147,12 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, mKeyguardGoingAwayRunnable.run(); } else { // TODO(bc-unlock): Fill parameters - handleStartKeyguardExitAnimation( - SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(), - mHideAnimation.getDuration(), null /* apps */, null /* wallpapers */, - null /* nonApps */, null /* finishedCallback */); + mNotificationShadeWindowControllerLazy.get().batchApplyWindowLayoutParams(() -> { + handleStartKeyguardExitAnimation( + SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(), + mHideAnimation.getDuration(), null /* apps */, null /* wallpapers */, + null /* nonApps */, null /* finishedCallback */); + }); } } Trace.endSection(); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index dd844e8d49abe..f14d130936206 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -44,6 +44,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationShadeDepthController; +import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardLiftController; @@ -98,7 +99,8 @@ public class KeyguardModule { ScreenOffAnimationController screenOffAnimationController, Lazy notificationShadeDepthController, ScreenOnCoordinator screenOnCoordinator, - InteractionJankMonitor interactionJankMonitor) { + InteractionJankMonitor interactionJankMonitor, + Lazy notificationShadeWindowController) { return new KeyguardViewMediator( context, falsingCollector, @@ -122,7 +124,8 @@ public class KeyguardModule { screenOffAnimationController, notificationShadeDepthController, screenOnCoordinator, - interactionJankMonitor + interactionJankMonitor, + notificationShadeWindowController ); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java index 4adf2bc836c46..ebd610bb0af44 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java @@ -19,6 +19,7 @@ package com.android.systemui.statusbar; import android.graphics.Region; import android.view.ViewGroup; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.systemui.statusbar.phone.StatusBarWindowCallback; @@ -191,6 +192,14 @@ public interface NotificationShadeWindowController extends RemoteInputController */ default void setLightRevealScrimOpaque(boolean opaque) {} + /** + * Defer any application of window {@link WindowManager.LayoutParams} until {@code scope} is + * fully applied. + */ + default void batchApplyWindowLayoutParams(@NonNull Runnable scope) { + scope.run(); + } + /** * Custom listener to pipe data back to plugins about whether or not the status bar would be * collapsed if not for the plugin. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 769f689769587..57973c9b90e03 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -162,6 +162,7 @@ import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShadeDepthController; +import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.QsFrameTranslateController; @@ -741,6 +742,7 @@ public class NotificationPanelViewController extends PanelViewController { KeyguardStateController keyguardStateController, StatusBarStateController statusBarStateController, StatusBarWindowStateController statusBarWindowStateController, + NotificationShadeWindowController notificationShadeWindowController, DozeLog dozeLog, DozeParameters dozeParameters, CommandQueue commandQueue, VibratorHelper vibratorHelper, LatencyTracker latencyTracker, PowerManager powerManager, @@ -800,6 +802,7 @@ public class NotificationPanelViewController extends PanelViewController { dozeLog, keyguardStateController, (SysuiStatusBarStateController) statusBarStateController, + notificationShadeWindowController, vibratorHelper, statusBarKeyguardViewManager, latencyTracker, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java index c859e70e6c767..474653b9728c7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java @@ -111,6 +111,12 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW private final SysuiColorExtractor mColorExtractor; private final ScreenOffAnimationController mScreenOffAnimationController; private float mFaceAuthDisplayBrightness = LayoutParams.BRIGHTNESS_OVERRIDE_NONE; + /** + * Layout params would be aggregated and dispatched all at once if this is > 0. + * + * @see #batchApplyWindowLayoutParams(Runnable) + */ + private int mDeferWindowLayoutParams; @Inject public NotificationShadeWindowControllerImpl(Context context, WindowManager windowManager, @@ -437,6 +443,20 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW } } + private void applyWindowLayoutParams() { + if (mDeferWindowLayoutParams == 0 && mLp != null && mLp.copyFrom(mLpChanged) != 0) { + mWindowManager.updateViewLayout(mNotificationShadeView, mLp); + } + } + + @Override + public void batchApplyWindowLayoutParams(Runnable scope) { + mDeferWindowLayoutParams++; + scope.run(); + mDeferWindowLayoutParams--; + applyWindowLayoutParams(); + } + private void apply(State state) { applyKeyguardFlags(state); applyFocusableFlag(state); @@ -451,9 +471,8 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW applyHasTopUi(state); applyNotTouchable(state); applyStatusBarColorSpaceAgnosticFlag(state); - if (mLp != null && mLp.copyFrom(mLpChanged) != 0) { - mWindowManager.updateViewLayout(mNotificationShadeView, mLp); - } + applyWindowLayoutParams(); + if (mHasTopUi != mHasTopUiChanged) { whitelistIpcs(() -> { try { @@ -739,6 +758,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW pw.println(TAG + ":"); pw.println(" mKeyguardMaxRefreshRate=" + mKeyguardMaxRefreshRate); pw.println(" mKeyguardPreferredRefreshRate=" + mKeyguardPreferredRefreshRate); + pw.println(" mDeferWindowLayoutParams=" + mDeferWindowLayoutParams); pw.println(mCurrentState); if (mNotificationShadeView != null && mNotificationShadeView.getViewRootImpl() != null) { mNotificationShadeView.getViewRootImpl().dump(" ", pw); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index 05ac2a35c7777..54d0b0351a8f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -57,6 +57,7 @@ import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; @@ -180,6 +181,7 @@ public abstract class PanelViewController { private boolean mExpandLatencyTracking; private final PanelView mView; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + private final NotificationShadeWindowController mNotificationShadeWindowController; protected final Resources mResources; protected final KeyguardStateController mKeyguardStateController; protected final SysuiStatusBarStateController mStatusBarStateController; @@ -222,6 +224,7 @@ public abstract class PanelViewController { DozeLog dozeLog, KeyguardStateController keyguardStateController, SysuiStatusBarStateController statusBarStateController, + NotificationShadeWindowController notificationShadeWindowController, VibratorHelper vibratorHelper, StatusBarKeyguardViewManager statusBarKeyguardViewManager, LatencyTracker latencyTracker, @@ -263,6 +266,7 @@ public abstract class PanelViewController { mResources = mView.getResources(); mKeyguardStateController = keyguardStateController; mStatusBarStateController = statusBarStateController; + mNotificationShadeWindowController = notificationShadeWindowController; mFlingAnimationUtils = flingAnimationUtilsBuilder .reset() .setMaxLengthSeconds(0.6f) @@ -760,34 +764,36 @@ public abstract class PanelViewController { if (isNaN(h)) { Log.wtf(TAG, "ExpandedHeight set to NaN"); } - if (mExpandLatencyTracking && h != 0f) { - DejankUtils.postAfterTraversal( - () -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL)); - mExpandLatencyTracking = false; - } - float maxPanelHeight = getMaxPanelHeight(); - if (mHeightAnimator == null) { - if (mTracking) { - float overExpansionPixels = Math.max(0, h - maxPanelHeight); - setOverExpansionInternal(overExpansionPixels, true /* isFromGesture */); + mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> { + if (mExpandLatencyTracking && h != 0f) { + DejankUtils.postAfterTraversal( + () -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL)); + mExpandLatencyTracking = false; + } + float maxPanelHeight = getMaxPanelHeight(); + if (mHeightAnimator == null) { + if (mTracking) { + float overExpansionPixels = Math.max(0, h - maxPanelHeight); + setOverExpansionInternal(overExpansionPixels, true /* isFromGesture */); + } + mExpandedHeight = Math.min(h, maxPanelHeight); + } else { + mExpandedHeight = h; } - mExpandedHeight = Math.min(h, maxPanelHeight); - } else { - mExpandedHeight = h; - } - // If we are closing the panel and we are almost there due to a slow decelerating - // interpolator, abort the animation. - if (mExpandedHeight < 1f && mExpandedHeight != 0f && mClosing) { - mExpandedHeight = 0f; - if (mHeightAnimator != null) { - mHeightAnimator.end(); + // If we are closing the panel and we are almost there due to a slow decelerating + // interpolator, abort the animation. + if (mExpandedHeight < 1f && mExpandedHeight != 0f && mClosing) { + mExpandedHeight = 0f; + if (mHeightAnimator != null) { + mHeightAnimator.end(); + } } - } - mExpandedFraction = Math.min(1f, - maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight); - onHeightUpdated(mExpandedHeight); - updatePanelExpansionAndVisibility(); + mExpandedFraction = Math.min(1f, + maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight); + onHeightUpdated(mExpandedHeight); + updatePanelExpansionAndVisibility(); + }); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index ae4a19e2b2127..2a44c5cc12e82 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -3597,26 +3597,28 @@ public class StatusBar extends CoreStartable implements public void onStartedWakingUp() { String tag = "StatusBar#onStartedWakingUp"; DejankUtils.startDetectingBlockingIpcs(tag); - mDeviceInteractive = true; - mWakeUpCoordinator.setWakingUp(true); - if (!mKeyguardBypassController.getBypassEnabled()) { - mHeadsUpManager.releaseAllImmediately(); - } - updateVisibleToUser(); - updateIsKeyguard(); - mDozeServiceHost.stopDozing(); - // This is intentionally below the stopDozing call above, since it avoids that we're - // unnecessarily animating the wakeUp transition. Animations should only be enabled - // once we fully woke up. - updateRevealEffect(true /* wakingUp */); - updateNotificationPanelTouchState(); + mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> { + mDeviceInteractive = true; + mWakeUpCoordinator.setWakingUp(true); + if (!mKeyguardBypassController.getBypassEnabled()) { + mHeadsUpManager.releaseAllImmediately(); + } + updateVisibleToUser(); + updateIsKeyguard(); + mDozeServiceHost.stopDozing(); + // This is intentionally below the stopDozing call above, since it avoids that we're + // unnecessarily animating the wakeUp transition. Animations should only be enabled + // once we fully woke up. + updateRevealEffect(true /* wakingUp */); + updateNotificationPanelTouchState(); - // If we are waking up during the screen off animation, we should undo making the - // expanded visible (we did that so the LightRevealScrim would be visible). - if (mScreenOffAnimationController.shouldHideLightRevealScrimOnWakeUp()) { - makeExpandedInvisible(); - } + // If we are waking up during the screen off animation, we should undo making the + // expanded visible (we did that so the LightRevealScrim would be visible). + if (mScreenOffAnimationController.shouldHideLightRevealScrimOnWakeUp()) { + makeExpandedInvisible(); + } + }); DejankUtils.stopDetectingBlockingIpcs(tag); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index 9827d21e29b07..da8ab27d7e3d2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -51,6 +51,7 @@ import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.dump.DumpManager; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.statusbar.NotificationShadeDepthController; +import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; @@ -68,6 +69,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import dagger.Lazy; + @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest @@ -94,6 +97,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock ScreenOffAnimationController mScreenOffAnimationController; private @Mock InteractionJankMonitor mInteractionJankMonitor; private @Mock ScreenOnCoordinator mScreenOnCoordinator; + private @Mock Lazy mNotificationShadeWindowControllerLazy; private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake(); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); @@ -197,7 +201,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mScreenOffAnimationController, () -> mNotificationShadeDepthController, mScreenOnCoordinator, - mInteractionJankMonitor); + mInteractionJankMonitor, + mNotificationShadeWindowControllerLazy); mViewMediator.start(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java index 1c8b35aeaeaf5..dee88dbfe29d3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java @@ -23,7 +23,6 @@ import static com.android.keyguard.KeyguardClockSwitch.SMALL; import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; import static com.android.systemui.statusbar.StatusBarState.SHADE; import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED; -import static com.android.systemui.statusbar.notification.ViewGroupFadeHelper.reset; import static com.google.common.truth.Truth.assertThat; @@ -38,6 +37,7 @@ import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -120,6 +120,7 @@ import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShadeDepthController; +import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.QsFrameTranslateController; @@ -365,6 +366,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { private StatusBarWindowStateController mStatusBarWindowStateController; @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; + @Mock + private NotificationShadeWindowController mNotificationShadeWindowController; private Optional mSysUIUnfoldComponent = Optional.empty(); private SysuiStatusBarStateController mStatusBarStateController; private NotificationPanelViewController mNotificationPanelViewController; @@ -490,7 +493,10 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { .thenReturn(true); when(mInteractionJankMonitor.end(anyInt())) .thenReturn(true); - reset(mView); + doAnswer(invocation -> { + ((Runnable) invocation.getArgument(0)).run(); + return null; + }).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any()); mMainHandler = new Handler(Looper.getMainLooper()); @@ -505,6 +511,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { mCommunalStateController, mKeyguardStateController, mStatusBarStateController, mStatusBarWindowStateController, + mNotificationShadeWindowController, mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper, mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor, mCommunalSourceMonitor, mMetricsLogger, mActivityManager, mConfigurationController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java index a5651f3bd43e1..671ab597eb2a0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java @@ -26,6 +26,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -225,4 +226,17 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { assertThat((mLayoutParameters.getValue().flags & FLAG_NOT_FOCUSABLE) != 0).isTrue(); assertThat((mLayoutParameters.getValue().flags & FLAG_ALT_FOCUSABLE_IM) == 0).isTrue(); } + + @Test + public void batchApplyWindowLayoutParams_doesNotDispatchEvents() { + mNotificationShadeWindowController.setForceDozeBrightness(true); + verify(mWindowManager).updateViewLayout(any(), any()); + + clearInvocations(mWindowManager); + mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> { + mNotificationShadeWindowController.setForceDozeBrightness(false); + verify(mWindowManager, never()).updateViewLayout(any(), any()); + }); + verify(mWindowManager).updateViewLayout(any(), any()); + } }