summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java59
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt136
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewBinder.kt39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt3
9 files changed, 336 insertions, 19 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 4ae2edcd007a..4ccbc5a12ea0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -53,6 +53,7 @@ import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentLogger;
import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.pipeline.shared.ui.binder.CollapsedStatusBarViewBinder;
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
@@ -158,6 +159,7 @@ public abstract class StatusBarViewModule {
StatusBarIconController statusBarIconController,
StatusBarIconController.DarkIconManager.Factory darkIconManagerFactory,
CollapsedStatusBarViewModel collapsedStatusBarViewModel,
+ CollapsedStatusBarViewBinder collapsedStatusBarViewBinder,
StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
KeyguardStateController keyguardStateController,
ShadeViewController shadeViewController,
@@ -182,6 +184,7 @@ public abstract class StatusBarViewModule {
statusBarIconController,
darkIconManagerFactory,
collapsedStatusBarViewModel,
+ collapsedStatusBarViewBinder,
statusBarHideIconsForBouncerManager,
keyguardStateController,
shadeViewController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index b0d459f42791..0d057f349dd3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -14,8 +14,6 @@
package com.android.systemui.statusbar.phone.fragment;
-
-
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.IDLE;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.SHOWING_PERSISTENT_DOT;
@@ -69,6 +67,7 @@ import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentCom
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
import com.android.systemui.statusbar.pipeline.shared.ui.binder.CollapsedStatusBarViewBinder;
+import com.android.systemui.statusbar.pipeline.shared.ui.binder.StatusBarVisibilityChangeListener;
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
@@ -131,6 +130,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private final StatusBarIconController mStatusBarIconController;
private final CarrierConfigTracker mCarrierConfigTracker;
private final CollapsedStatusBarViewModel mCollapsedStatusBarViewModel;
+ private final CollapsedStatusBarViewBinder mCollapsedStatusBarViewBinder;
private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
private final StatusBarIconController.DarkIconManager.Factory mDarkIconManagerFactory;
private final SecureSettings mSecureSettings;
@@ -183,11 +183,21 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private boolean mWaitingForWindowStateChangeAfterCameraLaunch = false;
/**
+ * True when a transition from lockscreen to dream has started, but haven't yet received a
+ * status bar window state change afterward.
+ *
+ * Similar to [mWaitingForWindowStateChangeAfterCameraLaunch].
+ */
+ private boolean mTransitionFromLockscreenToDreamStarted = false;
+
+ /**
* Listener that updates {@link #mWaitingForWindowStateChangeAfterCameraLaunch} when it receives
* a new status bar window state.
*/
- private final StatusBarWindowStateListener mStatusBarWindowStateListener = state ->
- mWaitingForWindowStateChangeAfterCameraLaunch = false;
+ private final StatusBarWindowStateListener mStatusBarWindowStateListener = state -> {
+ mWaitingForWindowStateChangeAfterCameraLaunch = false;
+ mTransitionFromLockscreenToDreamStarted = false;
+ };
@SuppressLint("ValidFragment")
public CollapsedStatusBarFragment(
@@ -201,6 +211,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
StatusBarIconController statusBarIconController,
StatusBarIconController.DarkIconManager.Factory darkIconManagerFactory,
CollapsedStatusBarViewModel collapsedStatusBarViewModel,
+ CollapsedStatusBarViewBinder collapsedStatusBarViewBinder,
StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
KeyguardStateController keyguardStateController,
ShadeViewController shadeViewController,
@@ -224,6 +235,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mFeatureFlags = featureFlags;
mStatusBarIconController = statusBarIconController;
mCollapsedStatusBarViewModel = collapsedStatusBarViewModel;
+ mCollapsedStatusBarViewBinder = collapsedStatusBarViewBinder;
mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager;
mDarkIconManagerFactory = darkIconManagerFactory;
mKeyguardStateController = keyguardStateController;
@@ -296,8 +308,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mCarrierConfigTracker.addCallback(mCarrierConfigCallback);
mCarrierConfigTracker.addDefaultDataSubscriptionChangedListener(mDefaultDataListener);
- CollapsedStatusBarViewBinder.bind(
- mStatusBar, mCollapsedStatusBarViewModel, this::updateStatusBarVisibilities);
+ mCollapsedStatusBarViewBinder.bind(
+ mStatusBar, mCollapsedStatusBarViewModel, mStatusBarVisibilityChangeListener);
}
@Override
@@ -411,6 +423,19 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
return mStatusBarFragmentComponent;
}
+ private StatusBarVisibilityChangeListener mStatusBarVisibilityChangeListener =
+ new StatusBarVisibilityChangeListener() {
+ @Override
+ public void onStatusBarVisibilityMaybeChanged() {
+ updateStatusBarVisibilities(/* animate= */ true);
+ }
+
+ @Override
+ public void onTransitionFromLockscreenToDreamStarted() {
+ mTransitionFromLockscreenToDreamStarted = true;
+ }
+ };
+
@Override
public void disable(int displayId, int state1, int state2, boolean animate) {
if (displayId != getContext().getDisplayId()) {
@@ -423,10 +448,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
updateStatusBarVisibilities(animate);
}
- private void updateStatusBarVisibilities() {
- updateStatusBarVisibilities(/* animate= */ true);
- }
-
private void updateStatusBarVisibilities(boolean animate) {
StatusBarVisibilityModel previousModel = mLastModifiedVisibility;
StatusBarVisibilityModel newModel = calculateInternalModel(mLastSystemVisibility);
@@ -546,6 +567,18 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
return true;
}
+ // Similar to [hideIconsForSecureCamera]: When dream is launched over lockscreen, the icons
+ // are momentarily visible because the dream animation has finished, but SysUI has not been
+ // informed that the dream is full-screen. For extra safety, we double-check that we're
+ // still dreaming.
+ final boolean hideIconsForDream =
+ mTransitionFromLockscreenToDreamStarted
+ && mKeyguardUpdateMonitor.isDreaming()
+ && mKeyguardStateController.isOccluded();
+ if (hideIconsForDream) {
+ return true;
+ }
+
// While the status bar is transitioning from lockscreen to an occluded, we don't yet know
// if the occluding activity is fullscreen or not. If it *is* fullscreen, we don't want to
// briefly show the status bar just to immediately hide it again. So, we wait for the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index 49de5a232f30..27cc64f9a8e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -44,6 +44,8 @@ import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerPr
import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerProxyImpl
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
+import com.android.systemui.statusbar.pipeline.shared.ui.binder.CollapsedStatusBarViewBinder
+import com.android.systemui.statusbar.pipeline.shared.ui.binder.CollapsedStatusBarViewBinderImpl
import com.android.systemui.statusbar.pipeline.wifi.data.repository.RealWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositorySwitcher
@@ -107,6 +109,11 @@ abstract class StatusBarPipelineModule {
impl: CollapsedStatusBarViewModelImpl
): CollapsedStatusBarViewModel
+ @Binds
+ abstract fun collapsedStatusBarViewBinder(
+ impl: CollapsedStatusBarViewBinderImpl
+ ): CollapsedStatusBarViewBinder
+
companion object {
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
index 9a59851a230a..b9b88f4b762c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
@@ -19,34 +19,61 @@ package com.android.systemui.statusbar.pipeline.shared.ui.binder
import android.view.View
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.launch
-object CollapsedStatusBarViewBinder {
+/**
+ * Interface to assist with binding the [CollapsedStatusBarFragment] to
+ * [CollapsedStatusBarViewModel]. Used only to enable easy testing of [CollapsedStatusBarFragment].
+ */
+interface CollapsedStatusBarViewBinder {
/**
* Binds the view to the view-model. [listener] will be notified whenever an event that may
* change the status bar visibility occurs.
*/
- @JvmStatic
fun bind(
view: View,
viewModel: CollapsedStatusBarViewModel,
listener: StatusBarVisibilityChangeListener,
+ )
+}
+
+@SysUISingleton
+class CollapsedStatusBarViewBinderImpl @Inject constructor() : CollapsedStatusBarViewBinder {
+ override fun bind(
+ view: View,
+ viewModel: CollapsedStatusBarViewModel,
+ listener: StatusBarVisibilityChangeListener,
) {
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
- viewModel.isTransitioningFromLockscreenToOccluded.collect {
- listener.onStatusBarVisibilityMaybeChanged()
+ launch {
+ viewModel.isTransitioningFromLockscreenToOccluded.collect {
+ listener.onStatusBarVisibilityMaybeChanged()
+ }
+ }
+
+ launch {
+ viewModel.transitionFromLockscreenToDreamStartedEvent.collect {
+ listener.onTransitionFromLockscreenToDreamStarted()
+ }
}
}
}
}
}
-/**
- * Listener to be notified when the status bar visibility might have changed due to the device
- * moving to a different state.
- */
-fun interface StatusBarVisibilityChangeListener {
+/** Listener for various events that may affect the status bar's visibility. */
+interface StatusBarVisibilityChangeListener {
+ /**
+ * Called when the status bar visibility might have changed due to the device moving to a
+ * different state.
+ */
fun onStatusBarVisibilityMaybeChanged()
+
+ /** Called when a transition from lockscreen to dream has started. */
+ fun onTransitionFromLockscreenToDreamStarted()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
index edb7e4daca1b..15ab143a7aeb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
@@ -22,8 +22,10 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac
import com.android.systemui.keyguard.shared.model.TransitionState
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -43,6 +45,9 @@ interface CollapsedStatusBarViewModel {
* otherwise.
*/
val isTransitioningFromLockscreenToOccluded: StateFlow<Boolean>
+
+ /** Emits whenever a transition from lockscreen to dream has started. */
+ val transitionFromLockscreenToDreamStartedEvent: Flow<Unit>
}
@SysUISingleton
@@ -59,4 +64,9 @@ constructor(
it.transitionState == TransitionState.RUNNING
}
.stateIn(coroutineScope, SharingStarted.WhileSubscribed(), initialValue = false)
+
+ override val transitionFromLockscreenToDreamStartedEvent: Flow<Unit> =
+ keyguardTransitionInteractor.lockscreenToDreamingTransition
+ .filter { it.transitionState == TransitionState.STARTED }
+ .map {}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 10efcd41019c..9b1d93b691c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -74,6 +74,7 @@ import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.FakeCollapsedStatusBarViewBinder;
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.FakeCollapsedStatusBarViewModel;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
@@ -129,6 +130,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
@Mock
private StatusBarIconController.DarkIconManager mIconManager;
private FakeCollapsedStatusBarViewModel mCollapsedStatusBarViewModel;
+ private FakeCollapsedStatusBarViewBinder mCollapsedStatusBarViewBinder;
@Mock
private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
@Mock
@@ -612,6 +614,55 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
assertEquals(View.VISIBLE, getClockView().getVisibility());
}
+ @Test
+ public void testStatusBarIcons_hiddenThroughoutLockscreenToDreamTransition() {
+ final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ // WHEN a transition to dream has started
+ mCollapsedStatusBarViewBinder.getListener().onTransitionFromLockscreenToDreamStarted();
+ when(mKeyguardUpdateMonitor.isDreaming()).thenReturn(true);
+ when(mKeyguardStateController.isOccluded()).thenReturn(true);
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ // THEN status icons should be invisible or gone, but certainly not VISIBLE.
+ assertNotEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+ assertNotEquals(View.VISIBLE, getClockView().getVisibility());
+
+ // WHEN the transition has finished and dream is displaying
+ mockLockscreenToDreamTransitionFinished();
+ // (This approximates "dream is displaying")
+ when(mStatusBarHideIconsForBouncerManager.getShouldHideStatusBarIconsForBouncer())
+ .thenReturn(true);
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ // THEN the views still aren't visible because dream is hiding them
+ assertNotEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+ assertNotEquals(View.VISIBLE, getClockView().getVisibility());
+
+ // WHEN dream has ended
+ when(mStatusBarHideIconsForBouncerManager.getShouldHideStatusBarIconsForBouncer())
+ .thenReturn(false);
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ // THEN the views can be visible again
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+ assertEquals(View.VISIBLE, getClockView().getVisibility());
+ }
+
+ @Test
+ public void testStatusBarIcons_lockscreenToDreamTransitionButNotDreaming_iconsVisible() {
+ final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ // WHEN a transition to dream has started but we're *not* dreaming
+ mCollapsedStatusBarViewBinder.getListener().onTransitionFromLockscreenToDreamStarted();
+ when(mKeyguardUpdateMonitor.isDreaming()).thenReturn(false);
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ // THEN the views are still visible
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+ assertEquals(View.VISIBLE, getClockView().getVisibility());
+ }
+
@Override
protected Fragment instantiate(Context context, String className, Bundle arguments) {
MockitoAnnotations.initMocks(this);
@@ -631,6 +682,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
mShadeExpansionStateManager = new ShadeExpansionStateManager();
mCollapsedStatusBarViewModel = new FakeCollapsedStatusBarViewModel();
+ mCollapsedStatusBarViewBinder = new FakeCollapsedStatusBarViewBinder();
setUpNotificationIconAreaController();
return new CollapsedStatusBarFragment(
@@ -644,6 +696,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
mStatusBarIconController,
mIconManagerFactory,
mCollapsedStatusBarViewModel,
+ mCollapsedStatusBarViewBinder,
mStatusBarHideIconsForBouncerManager,
mKeyguardStateController,
mShadeViewController,
@@ -718,6 +771,12 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
}
}
+ private void mockLockscreenToDreamTransitionFinished() {
+ for (StatusBarWindowStateListener listener : mStatusBarWindowStateListeners) {
+ listener.onStatusBarWindowStateChanged(StatusBarManager.WINDOW_STATE_HIDDEN);
+ }
+ }
+
private CollapsedStatusBarFragment resumeAndGetFragment() {
mFragments.dispatchResume();
processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index 5faed9d952c2..c8c24a770a7a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -176,4 +177,139 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() {
job.cancel()
}
+
+ @Test
+ fun transitionFromLockscreenToDreamStartedEvent_started_emitted() =
+ testScope.runTest {
+ val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.DREAMING,
+ value = 0f,
+ TransitionState.STARTED,
+ )
+ )
+
+ assertThat(emissions.size).isEqualTo(1)
+ }
+
+ @Test
+ fun transitionFromLockscreenToDreamStartedEvent_startedMultiple_emittedMultiple() =
+ testScope.runTest {
+ val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.DREAMING,
+ value = 0f,
+ TransitionState.STARTED,
+ )
+ )
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.DREAMING,
+ value = 0f,
+ TransitionState.STARTED,
+ )
+ )
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.DREAMING,
+ value = 0f,
+ TransitionState.STARTED,
+ )
+ )
+
+ assertThat(emissions.size).isEqualTo(3)
+ }
+
+ @Test
+ fun transitionFromLockscreenToDreamStartedEvent_startedThenRunning_emittedOnlyOne() =
+ testScope.runTest {
+ val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.DREAMING,
+ value = 0f,
+ TransitionState.STARTED,
+ )
+ )
+ assertThat(emissions.size).isEqualTo(1)
+
+ // WHEN the transition progresses through its animation by going through the RUNNING
+ // step with increasing fractions
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.DREAMING,
+ value = .1f,
+ TransitionState.RUNNING,
+ )
+ )
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.DREAMING,
+ value = .2f,
+ TransitionState.RUNNING,
+ )
+ )
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.DREAMING,
+ value = .3f,
+ TransitionState.RUNNING,
+ )
+ )
+
+ // THEN the flow does not emit since the flow should only emit when the transition
+ // starts
+ assertThat(emissions.size).isEqualTo(1)
+ }
+
+ @Test
+ fun transitionFromLockscreenToDreamStartedEvent_irrelevantTransition_notEmitted() =
+ testScope.runTest {
+ val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.OCCLUDED,
+ value = 0f,
+ TransitionState.STARTED,
+ )
+ )
+
+ assertThat(emissions).isEmpty()
+ }
+
+ @Test
+ fun transitionFromLockscreenToDreamStartedEvent_irrelevantTransitionState_notEmitted() =
+ testScope.runTest {
+ val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.DREAMING,
+ value = 1.0f,
+ TransitionState.FINISHED,
+ )
+ )
+
+ assertThat(emissions).isEmpty()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewBinder.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewBinder.kt
new file mode 100644
index 000000000000..2ee928fa6d17
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewBinder.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.statusbar.pipeline.shared.ui.viewmodel
+
+import android.view.View
+import com.android.systemui.statusbar.pipeline.shared.ui.binder.CollapsedStatusBarViewBinder
+import com.android.systemui.statusbar.pipeline.shared.ui.binder.StatusBarVisibilityChangeListener
+
+/**
+ * A fake view binder that can be used from Java tests.
+ *
+ * Since Java tests can't run tests within test scopes, we need to bypass the flows from
+ * [CollapsedStatusBarViewModel] and just trigger the listener directly.
+ */
+class FakeCollapsedStatusBarViewBinder : CollapsedStatusBarViewBinder {
+ var listener: StatusBarVisibilityChangeListener? = null
+
+ override fun bind(
+ view: View,
+ viewModel: CollapsedStatusBarViewModel,
+ listener: StatusBarVisibilityChangeListener,
+ ) {
+ this.listener = listener
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
index cbf6637ad46b..88587b2db0f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
@@ -16,8 +16,11 @@
package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
class FakeCollapsedStatusBarViewModel : CollapsedStatusBarViewModel {
override val isTransitioningFromLockscreenToOccluded = MutableStateFlow(false)
+
+ override val transitionFromLockscreenToDreamStartedEvent = MutableSharedFlow<Unit>()
}