Merge "Publish dream state to OverviewProxyService." into tm-qpr-dev

This commit is contained in:
Bryce Lee
2023-01-26 21:08:57 +00:00
committed by Android (Google) Code Review
17 changed files with 361 additions and 9 deletions

View File

@@ -104,6 +104,11 @@ public interface StatusBarStateController {
*/ */
default void onDozingChanged(boolean isDozing) {} 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. * 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 * Note: this will be called for each animation frame. Please be careful to avoid

View File

@@ -112,7 +112,8 @@ public class QuickStepContract {
public static final int SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING = 1 << 25; public static final int SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING = 1 << 25;
// Freeform windows are showing in desktop mode // Freeform windows are showing in desktop mode
public static final int SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE = 1 << 26; 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) @Retention(RetentionPolicy.SOURCE)
@IntDef({SYSUI_STATE_SCREEN_PINNING, @IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -141,7 +142,8 @@ public class QuickStepContract {
SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED, SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED,
SYSUI_STATE_IMMERSIVE_MODE, SYSUI_STATE_IMMERSIVE_MODE,
SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING, 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 {} public @interface SystemUiStateFlags {}
@@ -179,6 +181,7 @@ public class QuickStepContract {
str.add((flags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0 ? "vis_win_showing" : ""); str.add((flags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0 ? "vis_win_showing" : "");
str.add((flags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0 str.add((flags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0
? "freeform_active_in_desktop_mode" : ""); ? "freeform_active_in_desktop_mode" : "");
str.add((flags & SYSUI_STATE_DEVICE_DREAMING) != 0 ? "device_dreaming" : "");
return str.toString(); return str.toString();
} }

View File

@@ -207,7 +207,8 @@ public class SystemActions implements CoreStartable {
// Saving in instance variable since to prevent GC since // Saving in instance variable since to prevent GC since
// NotificationShadeWindowController.registerCallback() only keeps weak references. // NotificationShadeWindowController.registerCallback() only keeps weak references.
mNotificationShadeCallback = mNotificationShadeCallback =
(keyguardShowing, keyguardOccluded, bouncerShowing, mDozing, panelExpanded) -> (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing, panelExpanded,
isDreaming) ->
registerOrUnregisterDismissNotificationShadeAction(); registerOrUnregisterDismissNotificationShadeAction();
mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
} }

View File

@@ -27,6 +27,7 @@ import com.android.systemui.accessibility.WindowMagnification
import com.android.systemui.biometrics.AuthController import com.android.systemui.biometrics.AuthController
import com.android.systemui.clipboardoverlay.ClipboardListener import com.android.systemui.clipboardoverlay.ClipboardListener
import com.android.systemui.dagger.qualifiers.PerUser import com.android.systemui.dagger.qualifiers.PerUser
import com.android.systemui.dreams.DreamMonitor
import com.android.systemui.globalactions.GlobalActionsComponent import com.android.systemui.globalactions.GlobalActionsComponent
import com.android.systemui.keyboard.KeyboardUI import com.android.systemui.keyboard.KeyboardUI
import com.android.systemui.keyguard.KeyguardViewMediator import com.android.systemui.keyguard.KeyguardViewMediator
@@ -286,4 +287,10 @@ abstract class SystemUICoreStartableModule {
@IntoMap @IntoMap
@ClassKey(StylusUsiPowerStartable::class) @ClassKey(StylusUsiPowerStartable::class)
abstract fun bindStylusUsiPowerStartable(sysui: StylusUsiPowerStartable): CoreStartable abstract fun bindStylusUsiPowerStartable(sysui: StylusUsiPowerStartable): CoreStartable
/**Inject into DreamMonitor */
@Binds
@IntoMap
@ClassKey(DreamMonitor::class)
abstract fun bindDreamMonitor(sysui: DreamMonitor): CoreStartable
} }

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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.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_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_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;
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_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED; 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, 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, mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
keyguardShowing && !keyguardOccluded) keyguardShowing && !keyguardOccluded)
.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED, .setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED,
keyguardShowing && keyguardOccluded) keyguardShowing && keyguardOccluded)
.setFlag(SYSUI_STATE_BOUNCER_SHOWING, bouncerShowing) .setFlag(SYSUI_STATE_BOUNCER_SHOWING, bouncerShowing)
.setFlag(SYSUI_STATE_DEVICE_DOZING, isDozing) .setFlag(SYSUI_STATE_DEVICE_DOZING, isDozing)
.setFlag(SYSUI_STATE_DEVICE_DREAMING, isDreaming)
.commitUpdate(mContext.getDisplayId()); .commitUpdate(mContext.getDisplayId());
} }

View File

@@ -563,7 +563,8 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
mCurrentState.keyguardOccluded, mCurrentState.keyguardOccluded,
mCurrentState.bouncerShowing, mCurrentState.bouncerShowing,
mCurrentState.dozing, mCurrentState.dozing,
mCurrentState.panelExpanded); mCurrentState.panelExpanded,
mCurrentState.dreaming);
} }
} }
@@ -777,6 +778,12 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
apply(mCurrentState); apply(mCurrentState);
} }
@Override
public void setDreaming(boolean dreaming) {
mCurrentState.dreaming = dreaming;
apply(mCurrentState);
}
@Override @Override
public void setForcePluginOpen(boolean forceOpen, Object token) { public void setForcePluginOpen(boolean forceOpen, Object token) {
if (forceOpen) { if (forceOpen) {
@@ -904,5 +911,10 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
public void onDozingChanged(boolean isDozing) { public void onDozingChanged(boolean isDozing) {
setDozing(isDozing); setDozing(isDozing);
} }
@Override
public void onDreamingChanged(boolean isDreaming) {
setDreaming(isDreaming);
}
}; };
} }

View File

@@ -23,8 +23,8 @@ import com.android.systemui.shade.NotificationShadeWindowState.Buffer
import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.StatusBarState
/** /**
* Represents state of shade window, used by [NotificationShadeWindowControllerImpl]. * Represents state of shade window, used by [NotificationShadeWindowControllerImpl]. Contains
* Contains nested class [Buffer] for pretty table logging in bug reports. * nested class [Buffer] for pretty table logging in bug reports.
*/ */
class NotificationShadeWindowState( class NotificationShadeWindowState(
@JvmField var keyguardShowing: Boolean = false, @JvmField var keyguardShowing: Boolean = false,
@@ -55,6 +55,7 @@ class NotificationShadeWindowState(
@JvmField var remoteInputActive: Boolean = false, @JvmField var remoteInputActive: Boolean = false,
@JvmField var forcePluginOpen: Boolean = false, @JvmField var forcePluginOpen: Boolean = false,
@JvmField var dozing: Boolean = false, @JvmField var dozing: Boolean = false,
@JvmField var dreaming: Boolean = false,
@JvmField var scrimsVisibility: Int = 0, @JvmField var scrimsVisibility: Int = 0,
@JvmField var backgroundBlurRadius: Int = 0, @JvmField var backgroundBlurRadius: Int = 0,
) { ) {

View File

@@ -143,6 +143,9 @@ public interface NotificationShadeWindowController extends RemoteInputController
/** Sets the state of whether sysui is dozing or not. */ /** Sets the state of whether sysui is dozing or not. */
default void setDozing(boolean dozing) {} 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. */ /** Sets the state of whether plugin open is forced or not. */
default void setForcePluginOpen(boolean forcePluginOpen, Object token) {} default void setForcePluginOpen(boolean forcePluginOpen, Object token) {}

View File

@@ -128,6 +128,11 @@ public class StatusBarStateControllerImpl implements
*/ */
private boolean mIsDozing; private boolean mIsDozing;
/**
* If the device is currently dreaming or not.
*/
private boolean mIsDreaming;
/** /**
* If the status bar is currently expanded or not. * If the status bar is currently expanded or not.
*/ */
@@ -293,6 +298,29 @@ public class StatusBarStateControllerImpl implements
return true; return true;
} }
@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 @Override
public void setAndInstrumentDozeAmount(View view, float dozeAmount, boolean animated) { public void setAndInstrumentDozeAmount(View view, float dozeAmount, boolean animated) {
if (mDarkAnimator != null && mDarkAnimator.isRunning()) { if (mDarkAnimator != null && mDarkAnimator.isRunning()) {

View File

@@ -98,6 +98,13 @@ public interface SysuiStatusBarStateController extends StatusBarStateController
*/ */
boolean setIsDozing(boolean isDozing); 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 * Changes the current doze amount, also starts the
* {@link com.android.internal.jank.InteractionJankMonitor InteractionJankMonitor} as possible. * {@link com.android.internal.jank.InteractionJankMonitor InteractionJankMonitor} as possible.

View File

@@ -17,5 +17,5 @@ package com.android.systemui.statusbar.phone;
public interface StatusBarWindowCallback { public interface StatusBarWindowCallback {
void onStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing, void onStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing,
boolean isDozing, boolean panelExpanded); boolean isDozing, boolean panelExpanded, boolean isDreaming);
} }

View File

@@ -236,7 +236,8 @@ public class BubblesManager {
// Store callback in a field so it won't get GC'd // Store callback in a field so it won't get GC'd
mStatusBarWindowCallback = mStatusBarWindowCallback =
(keyguardShowing, keyguardOccluded, bouncerShowing, isDozing, panelExpanded) -> (keyguardShowing, keyguardOccluded, bouncerShowing, isDozing, panelExpanded,
isDreaming) ->
mBubbles.onNotificationPanelExpandedChanged(panelExpanded); mBubbles.onNotificationPanelExpandedChanged(panelExpanded);
notificationShadeWindowController.registerCallback(mStatusBarWindowCallback); notificationShadeWindowController.registerCallback(mStatusBarWindowCallback);

View File

@@ -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();
}
}

View File

@@ -37,6 +37,7 @@ import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.mock import org.mockito.Mockito.mock
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever 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. // and cause us to drop a frame during the LOCKSCREEN_TRANSITION_FROM_AOD CUJ.
assertEquals(0.99f, controller.dozeAmount, 0.009f) 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)
}
} }