diff options
17 files changed, 362 insertions, 9 deletions
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java index 9ed3bac57e66..70b5d739ea7c 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java @@ -105,6 +105,11 @@ public interface StatusBarStateController { default void onDozingChanged(boolean isDozing) {} /** + * Callback to be notified when Dreaming changes. Dreaming is stored separately from state. + */ + default void onDreamingChanged(boolean isDreaming) {} + + /** * Callback to be notified when the doze amount changes. Useful for animations. * Note: this will be called for each animation frame. Please be careful to avoid * performance regressions. diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index 766266d9cc94..0d35aa351909 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -112,7 +112,8 @@ public class QuickStepContract { public static final int SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING = 1 << 25; // Freeform windows are showing in desktop mode public static final int SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE = 1 << 26; - + // Device dreaming state + public static final int SYSUI_STATE_DEVICE_DREAMING = 1 << 27; @Retention(RetentionPolicy.SOURCE) @IntDef({SYSUI_STATE_SCREEN_PINNING, @@ -141,7 +142,8 @@ public class QuickStepContract { SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED, SYSUI_STATE_IMMERSIVE_MODE, SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING, - SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE + SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE, + SYSUI_STATE_DEVICE_DREAMING }) public @interface SystemUiStateFlags {} @@ -179,6 +181,8 @@ public class QuickStepContract { str.add((flags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0 ? "vis_win_showing" : ""); str.add((flags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0 ? "freeform_active_in_desktop_mode" : ""); + str.add((flags & SYSUI_STATE_DEVICE_DREAMING) != 0 ? "device_dreaming" : ""); + return str.toString(); } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java index c5d4bbe6b6ba..46cc894c9726 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java @@ -207,7 +207,8 @@ public class SystemActions implements CoreStartable { // Saving in instance variable since to prevent GC since // NotificationShadeWindowController.registerCallback() only keeps weak references. mNotificationShadeCallback = - (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing, panelExpanded) -> + (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing, panelExpanded, + isDreaming) -> registerOrUnregisterDismissNotificationShadeAction(); mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt index 9cbc64e563f0..c9e5449aad9f 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt @@ -28,6 +28,7 @@ import com.android.systemui.biometrics.AuthController import com.android.systemui.biometrics.UdfpsOverlay import com.android.systemui.clipboardoverlay.ClipboardListener import com.android.systemui.dagger.qualifiers.PerUser +import com.android.systemui.dreams.DreamMonitor import com.android.systemui.globalactions.GlobalActionsComponent import com.android.systemui.keyboard.KeyboardUI import com.android.systemui.keyguard.KeyguardViewMediator @@ -293,4 +294,10 @@ abstract class SystemUICoreStartableModule { @IntoMap @ClassKey(StylusUsiPowerStartable::class) abstract fun bindStylusUsiPowerStartable(sysui: StylusUsiPowerStartable): CoreStartable + + /**Inject into DreamMonitor */ + @Binds + @IntoMap + @ClassKey(DreamMonitor::class) + abstract fun bindDreamMonitor(sysui: DreamMonitor): CoreStartable } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java new file mode 100644 index 000000000000..102f2082ebd1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dreams; + +import android.util.Log; + +import com.android.systemui.CoreStartable; +import com.android.systemui.dreams.callbacks.DreamStatusBarStateCallback; +import com.android.systemui.dreams.conditions.DreamCondition; +import com.android.systemui.shared.condition.Monitor; + +import javax.inject.Inject; + +/** + * A {@link CoreStartable} to retain a monitor for tracking dreaming. + */ +public class DreamMonitor implements CoreStartable { + private static final String TAG = "DreamMonitor"; + + // We retain a reference to the monitor so it is not garbage-collected. + private final Monitor mConditionMonitor; + private final DreamCondition mDreamCondition; + private final DreamStatusBarStateCallback mCallback; + + + @Inject + public DreamMonitor(Monitor monitor, DreamCondition dreamCondition, + DreamStatusBarStateCallback callback) { + mConditionMonitor = monitor; + mDreamCondition = dreamCondition; + mCallback = callback; + + } + @Override + public void start() { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "started"); + } + + mConditionMonitor.addSubscription(new Monitor.Subscription.Builder(mCallback) + .addCondition(mDreamCondition) + .build()); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/callbacks/DreamStatusBarStateCallback.java b/packages/SystemUI/src/com/android/systemui/dreams/callbacks/DreamStatusBarStateCallback.java new file mode 100644 index 000000000000..c8c9470f9bf2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dreams/callbacks/DreamStatusBarStateCallback.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.dreams.callbacks; + +import android.util.Log; + +import com.android.systemui.shared.condition.Monitor; +import com.android.systemui.statusbar.SysuiStatusBarStateController; + +import javax.inject.Inject; + +/** + * A callback that informs {@link SysuiStatusBarStateController} when the dream state has changed. + */ +public class DreamStatusBarStateCallback implements Monitor.Callback { + private static final String TAG = "DreamStatusBarCallback"; + + private final SysuiStatusBarStateController mStateController; + + @Inject + public DreamStatusBarStateCallback(SysuiStatusBarStateController statusBarStateController) { + mStateController = statusBarStateController; + } + + @Override + public void onConditionsChanged(boolean allConditionsMet) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "onConditionChanged:" + allConditionsMet); + } + + mStateController.setIsDreaming(allConditionsMet); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java new file mode 100644 index 000000000000..2befce7065ec --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.dreams.conditions; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.text.TextUtils; + +import com.android.systemui.shared.condition.Condition; + +import javax.inject.Inject; + +/** + * {@link DreamCondition} provides a signal when a dream begins and ends. + */ +public class DreamCondition extends Condition { + private final Context mContext; + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + processIntent(intent); + } + }; + + @Inject + public DreamCondition(Context context) { + mContext = context; + } + + private void processIntent(Intent intent) { + // In the case of a non-existent sticky broadcast, ignore when there is no intent. + if (intent == null) { + return; + } + if (TextUtils.equals(intent.getAction(), Intent.ACTION_DREAMING_STARTED)) { + updateCondition(true); + } else if (TextUtils.equals(intent.getAction(), Intent.ACTION_DREAMING_STOPPED)) { + updateCondition(false); + } else { + throw new IllegalStateException("unexpected intent:" + intent); + } + } + + @Override + protected void start() { + final IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_DREAMING_STARTED); + filter.addAction(Intent.ACTION_DREAMING_STOPPED); + final Intent stickyIntent = mContext.registerReceiver(mReceiver, filter); + processIntent(stickyIntent); + } + + @Override + protected void stop() { + mContext.unregisterReceiver(mReceiver); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 1151475f0fc3..dd7ea7658cb1 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -30,6 +30,7 @@ import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNL import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED; @@ -652,13 +653,14 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded, - boolean bouncerShowing, boolean isDozing, boolean panelExpanded) { + boolean bouncerShowing, boolean isDozing, boolean panelExpanded, boolean isDreaming) { mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING, keyguardShowing && !keyguardOccluded) .setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED, keyguardShowing && keyguardOccluded) .setFlag(SYSUI_STATE_BOUNCER_SHOWING, bouncerShowing) .setFlag(SYSUI_STATE_DEVICE_DOZING, isDozing) + .setFlag(SYSUI_STATE_DEVICE_DREAMING, isDreaming) .commitUpdate(mContext.getDisplayId()); } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java index ab2e692915ad..156e4fd1889f 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java @@ -563,7 +563,8 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW mCurrentState.keyguardOccluded, mCurrentState.bouncerShowing, mCurrentState.dozing, - mCurrentState.panelExpanded); + mCurrentState.panelExpanded, + mCurrentState.dreaming); } } @@ -778,6 +779,12 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW } @Override + public void setDreaming(boolean dreaming) { + mCurrentState.dreaming = dreaming; + apply(mCurrentState); + } + + @Override public void setForcePluginOpen(boolean forceOpen, Object token) { if (forceOpen) { mCurrentState.forceOpenTokens.add(token); @@ -904,5 +911,10 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW public void onDozingChanged(boolean isDozing) { setDozing(isDozing); } + + @Override + public void onDreamingChanged(boolean isDreaming) { + setDreaming(isDreaming); + } }; } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt index 736404aa548a..fed9b8469c4b 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt @@ -23,8 +23,8 @@ import com.android.systemui.shade.NotificationShadeWindowState.Buffer import com.android.systemui.statusbar.StatusBarState /** - * Represents state of shade window, used by [NotificationShadeWindowControllerImpl]. - * Contains nested class [Buffer] for pretty table logging in bug reports. + * Represents state of shade window, used by [NotificationShadeWindowControllerImpl]. Contains + * nested class [Buffer] for pretty table logging in bug reports. */ class NotificationShadeWindowState( @JvmField var keyguardShowing: Boolean = false, @@ -55,6 +55,7 @@ class NotificationShadeWindowState( @JvmField var remoteInputActive: Boolean = false, @JvmField var forcePluginOpen: Boolean = false, @JvmField var dozing: Boolean = false, + @JvmField var dreaming: Boolean = false, @JvmField var scrimsVisibility: Int = 0, @JvmField var backgroundBlurRadius: Int = 0, ) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java index 0b1807dd2d70..2ca0b0054bf7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java @@ -143,6 +143,9 @@ public interface NotificationShadeWindowController extends RemoteInputController /** Sets the state of whether sysui is dozing or not. */ default void setDozing(boolean dozing) {} + /** Sets the state of whether sysui is dreaming or not. */ + default void setDreaming(boolean dreaming) {} + /** Sets the state of whether plugin open is forced or not. */ default void setForcePluginOpen(boolean forcePluginOpen, Object token) {} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index 58ce447b84f1..b9ac918d50da 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -128,6 +128,11 @@ public class StatusBarStateControllerImpl implements private boolean mIsDozing; /** + * If the device is currently dreaming or not. + */ + private boolean mIsDreaming; + + /** * If the status bar is currently expanded or not. */ private boolean mIsExpanded; @@ -293,6 +298,29 @@ public class StatusBarStateControllerImpl implements } @Override + public boolean setIsDreaming(boolean isDreaming) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "setIsDreaming:" + isDreaming); + } + if (mIsDreaming == isDreaming) { + return false; + } + + mIsDreaming = isDreaming; + + synchronized (mListeners) { + String tag = getClass().getSimpleName() + "#setIsDreaming"; + DejankUtils.startDetectingBlockingIpcs(tag); + for (RankedListener rl : new ArrayList<>(mListeners)) { + rl.mListener.onDreamingChanged(isDreaming); + } + DejankUtils.stopDetectingBlockingIpcs(tag); + } + + return true; + } + + @Override public void setAndInstrumentDozeAmount(View view, float dozeAmount, boolean animated) { if (mDarkAnimator != null && mDarkAnimator.isRunning()) { if (animated && mDozeAmountTarget == dozeAmount) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java index 5a392a9988d2..4043fcefe0c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java @@ -99,6 +99,13 @@ public interface SysuiStatusBarStateController extends StatusBarStateController boolean setIsDozing(boolean isDozing); /** + * Update the dreaming state from {@link CentralSurfaces}'s perspective + * @param isDreaming whether we are dreaming + * @return {@code true} if the state changed, else {@code false} + */ + boolean setIsDreaming(boolean isDreaming); + + /** * Changes the current doze amount, also starts the * {@link com.android.internal.jank.InteractionJankMonitor InteractionJankMonitor} as possible. * diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java index ae48c2d3b6f3..50cce45cd87a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java @@ -17,5 +17,5 @@ package com.android.systemui.statusbar.phone; public interface StatusBarWindowCallback { void onStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing, - boolean isDozing, boolean panelExpanded); + boolean isDozing, boolean panelExpanded, boolean isDreaming); } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java index 7033ccde8c7d..5d896cbbdab4 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java @@ -236,7 +236,8 @@ public class BubblesManager { // Store callback in a field so it won't get GC'd mStatusBarWindowCallback = - (keyguardShowing, keyguardOccluded, bouncerShowing, isDozing, panelExpanded) -> + (keyguardShowing, keyguardOccluded, bouncerShowing, isDozing, panelExpanded, + isDreaming) -> mBubbles.onNotificationPanelExpandedChanged(panelExpanded); notificationShadeWindowController.registerCallback(mStatusBarWindowCallback); diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java new file mode 100644 index 000000000000..19347c768524 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dreams.conditions; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.shared.condition.Condition; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class DreamConditionTest extends SysuiTestCase { + @Mock + Context mContext; + + @Mock + Condition.Callback mCallback; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + } + + /** + * Ensure a dreaming state immediately triggers the condition. + */ + @Test + public void testInitialState() { + final Intent intent = new Intent(Intent.ACTION_DREAMING_STARTED); + when(mContext.registerReceiver(any(), any())).thenReturn(intent); + final DreamCondition condition = new DreamCondition(mContext); + condition.addCallback(mCallback); + condition.start(); + + verify(mCallback).onConditionChanged(eq(condition)); + assertThat(condition.isConditionMet()).isTrue(); + } + + /** + * Ensure that changing dream state triggers condition. + */ + @Test + public void testChange() { + final Intent intent = new Intent(Intent.ACTION_DREAMING_STARTED); + final ArgumentCaptor<BroadcastReceiver> receiverCaptor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + when(mContext.registerReceiver(receiverCaptor.capture(), any())).thenReturn(intent); + final DreamCondition condition = new DreamCondition(mContext); + condition.addCallback(mCallback); + condition.start(); + clearInvocations(mCallback); + receiverCaptor.getValue().onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STOPPED)); + verify(mCallback).onConditionChanged(eq(condition)); + assertThat(condition.isConditionMet()).isFalse(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt index 5124eb992dc0..e6f272b3ad70 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt @@ -37,6 +37,7 @@ import org.mockito.ArgumentMatchers.anyFloat import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.eq import org.mockito.Mock +import org.mockito.Mockito import org.mockito.Mockito.mock import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever @@ -152,4 +153,18 @@ class StatusBarStateControllerImplTest : SysuiTestCase() { // and cause us to drop a frame during the LOCKSCREEN_TRANSITION_FROM_AOD CUJ. assertEquals(0.99f, controller.dozeAmount, 0.009f) } + + @Test + fun testSetDreamState_invokesCallback() { + val listener = mock(StatusBarStateController.StateListener::class.java) + controller.addCallback(listener) + + controller.setIsDreaming(true) + verify(listener).onDreamingChanged(true) + + Mockito.clearInvocations(listener) + + controller.setIsDreaming(false) + verify(listener).onDreamingChanged(false) + } } |