diff options
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>() } |