diff options
| author | 2023-09-29 13:55:41 +0000 | |
|---|---|---|
| committer | 2023-09-29 13:55:41 +0000 | |
| commit | 4ca1694709fb16f20c4ec5370bfc08c32c3973fd (patch) | |
| tree | 60d93cbfa8606d9126d8a347699b3f1674c2d621 | |
| parent | 1df8aac487cea70d0c0bcd759f8e6f6a1bfaaeee (diff) | |
| parent | 8ecc679dfc53fd2ff1df408e31bb72b4e8db0774 (diff) | |
Merge "[SB][Scene] Hide lockscreen status bar while dozing or not keyguard." into main
5 files changed, 349 insertions, 3 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java index fc9ecb3f14d6..9cf9714c274c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java @@ -42,13 +42,13 @@ import com.android.keyguard.CarrierTextController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.logging.KeyguardLogger; -import com.android.systemui.res.R; import com.android.systemui.battery.BatteryMeterViewController; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.log.core.LogLevel; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.res.R; import com.android.systemui.shade.ShadeViewStateProvider; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationMediaManager; @@ -67,6 +67,8 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserInfoController; +import com.android.systemui.statusbar.ui.binder.KeyguardStatusBarViewBinder; +import com.android.systemui.statusbar.ui.viewmodel.KeyguardStatusBarViewModel; import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel; import com.android.systemui.util.ViewController; import com.android.systemui.util.settings.SecureSettings; @@ -110,6 +112,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat private final KeyguardStateController mKeyguardStateController; private final KeyguardBypassController mKeyguardBypassController; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final KeyguardStatusBarViewModel mKeyguardStatusBarViewModel; private final BiometricUnlockController mBiometricUnlockController; private final SysuiStatusBarStateController mStatusBarStateController; private final StatusBarContentInsetsProvider mInsetsProvider; @@ -283,6 +286,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat KeyguardStateController keyguardStateController, KeyguardBypassController bypassController, KeyguardUpdateMonitor keyguardUpdateMonitor, + KeyguardStatusBarViewModel keyguardStatusBarViewModel, BiometricUnlockController biometricUnlockController, SysuiStatusBarStateController statusBarStateController, StatusBarContentInsetsProvider statusBarContentInsetsProvider, @@ -309,6 +313,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat mKeyguardStateController = keyguardStateController; mKeyguardBypassController = bypassController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mKeyguardStatusBarViewModel = keyguardStatusBarViewModel; mBiometricUnlockController = biometricUnlockController; mStatusBarStateController = statusBarStateController; mInsetsProvider = statusBarContentInsetsProvider; @@ -356,6 +361,9 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat super.onInit(); mCarrierTextController.init(); mBatteryMeterViewController.init(); + if (isMigrationEnabled()) { + KeyguardStatusBarViewBinder.bind(mView, mKeyguardStatusBarViewModel); + } } @Override @@ -380,7 +388,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat // whenever the shade is opened on top of lockscreen, and then re-attached when the // shade is closed. So, we need to re-add the IconManager each time we're re-attached to // get icon updates. - if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW)) { + if (isMigrationEnabled()) { mStatusBarIconController.addIconGroup(mTintedIconManager); } } @@ -455,6 +463,10 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat /** Sets the dozing state. */ public void setDozing(boolean dozing) { + if (isMigrationEnabled()) { + // [KeyguardStatusBarViewModel] will automatically handle dozing. + return; + } mDozing = dozing; } @@ -502,6 +514,10 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat if (!isKeyguardShowing()) { return; } + if (isMigrationEnabled()) { + // [KeyguardStatusBarViewBinder] will handle view state updates. + return; + } float alphaQsExpansion = 1 - Math.min( 1, mShadeViewStateProvider.getLockscreenShadeDragProgress() * 2); @@ -539,6 +555,11 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat * Updates the {@link KeyguardStatusBarView} state based on the provided values. */ public void updateViewState(float alpha, int visibility) { + if (isMigrationEnabled()) { + // [KeyguardStatusBarViewBinder] will handle view state updates. + return; + } + if (mDisableStateTracker.isDisabled()) { visibility = View.INVISIBLE; } @@ -646,10 +667,19 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat * @param alpha a value between 0 and 1. -1 if the value is to be reset/ignored. */ public void setAlpha(float alpha) { + if (isMigrationEnabled()) { + // [KeyguardStatusBarViewBinder] will handle view state updates. + return; + } + mExplicitAlpha = alpha; updateViewState(); } + private boolean isMigrationEnabled() { + return mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW); + } + private final ContentObserver mVolumeSettingObserver = new ContentObserver(null) { @Override public void onChange(boolean selfChange) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ui/binder/KeyguardStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ui/binder/KeyguardStatusBarViewBinder.kt new file mode 100644 index 000000000000..c63ef9e5e012 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ui/binder/KeyguardStatusBarViewBinder.kt @@ -0,0 +1,41 @@ +/* + * 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.ui.binder + +import android.view.View +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.statusbar.phone.KeyguardStatusBarView +import com.android.systemui.statusbar.ui.viewmodel.KeyguardStatusBarViewModel + +/** Binds [KeyguardStatusBarViewModel] to [KeyguardStatusBarView]. */ +object KeyguardStatusBarViewBinder { + @JvmStatic + fun bind( + view: KeyguardStatusBarView, + viewModel: KeyguardStatusBarViewModel, + ) { + view.repeatWhenAttached { + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.isVisible.collect { isVisible -> + view.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE + } + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt new file mode 100644 index 000000000000..ddfed8795fcf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModel.kt @@ -0,0 +1,54 @@ +/* + * 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.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.shared.model.StatusBarState +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn + +/** + * A view model for the status bar displayed on keyguard (lockscreen). + * + * Note: This view model is for the status bar view as a whole. Certain icons may have their own + * individual view models, such as + * [com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel] or + * [com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel]. + */ +@SysUISingleton +class KeyguardStatusBarViewModel +@Inject +constructor( + @Application scope: CoroutineScope, + keyguardInteractor: KeyguardInteractor, +) { + /** True if this view should be visible and false otherwise. */ + val isVisible: StateFlow<Boolean> = + combine( + keyguardInteractor.isDozing, + keyguardInteractor.statusBarState, + ) { isDozing, statusBarState -> + !isDozing && statusBarState == StatusBarState.KEYGUARD + } + .stateIn(scope, SharingStarted.WhileSubscribed(), false) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java index 2b1ce0e16bbf..da871a88e836 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java @@ -49,14 +49,22 @@ import androidx.test.filters.SmallTest; import com.android.keyguard.CarrierTextController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.keyguard.TestScopeProvider; import com.android.keyguard.logging.KeyguardLogger; -import com.android.systemui.res.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.battery.BatteryMeterViewController; +import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository; +import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository; import com.android.systemui.flags.FakeFeatureFlagsClassic; import com.android.systemui.flags.Flags; +import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository; +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.res.R; +import com.android.systemui.scene.SceneTestUtils; +import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags; import com.android.systemui.shade.ShadeViewStateProvider; +import com.android.systemui.shade.data.repository.FakeShadeRepository; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -66,6 +74,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserInfoController; +import com.android.systemui.statusbar.ui.viewmodel.KeyguardStatusBarViewModel; import com.android.systemui.user.ui.viewmodel.StatusBarUserChipViewModel; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.settings.SecureSettings; @@ -79,6 +88,8 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import kotlinx.coroutines.test.TestScope; + @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -133,16 +144,35 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { private KeyguardStatusBarView mKeyguardStatusBarView; private KeyguardStatusBarViewController mController; private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); + private final TestScope mTestScope = TestScopeProvider.getTestScope(); + private final FakeKeyguardRepository mKeyguardRepository = new FakeKeyguardRepository(); + private KeyguardInteractor mKeyguardInteractor; + private KeyguardStatusBarViewModel mViewModel; @Before public void setup() throws Exception { mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, false); mShadeViewStateProvider = new TestShadeViewStateProvider(); + mShadeViewStateProvider = new TestShadeViewStateProvider(); MockitoAnnotations.initMocks(this); when(mIconManagerFactory.create(any(), any())).thenReturn(mIconManager); + mKeyguardInteractor = new KeyguardInteractor( + mKeyguardRepository, + mCommandQueue, + mFeatureFlags, + new FakeSceneContainerFlags(), + new FakeKeyguardBouncerRepository(), + new FakeConfigurationRepository(), + new FakeShadeRepository(), + () -> new SceneTestUtils(this).sceneInteractor()); + mViewModel = + new KeyguardStatusBarViewModel( + mTestScope.getBackgroundScope(), + mKeyguardInteractor); + allowTestableLooperAsMainThread(); TestableLooper.get(this).runWithLooper(() -> { mKeyguardStatusBarView = @@ -169,6 +199,7 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { mKeyguardStateController, mKeyguardBypassController, mKeyguardUpdateMonitor, + mViewModel, mBiometricUnlockController, mStatusBarStateController, mStatusBarContentInsetsProvider, @@ -455,6 +486,94 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { } @Test + public void updateViewState_dozingTrue_flagOff_viewHidden() { + mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, false); + mController.init(); + mController.onViewAttached(); + updateStateToKeyguard(); + + mController.setDozing(true); + mController.updateViewState(); + + assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE); + } + + @Test + public void updateViewState_dozingFalse_flagOff_viewShown() { + mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, false); + mController.init(); + mController.onViewAttached(); + updateStateToKeyguard(); + + mController.setDozing(false); + mController.updateViewState(); + + assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void updateViewState_flagOn_doesNothing() { + mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, true); + mController.init(); + mController.onViewAttached(); + updateStateToKeyguard(); + + mKeyguardStatusBarView.setVisibility(View.GONE); + mKeyguardStatusBarView.setAlpha(0.456f); + + mController.updateViewState(); + + assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.GONE); + assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(0.456f); + } + + @Test + public void updateViewStateWithAlphaAndVis_flagOn_doesNothing() { + mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, true); + mController.init(); + mController.onViewAttached(); + updateStateToKeyguard(); + + mKeyguardStatusBarView.setVisibility(View.GONE); + mKeyguardStatusBarView.setAlpha(0.456f); + + mController.updateViewState(0.789f, View.VISIBLE); + + assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.GONE); + assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(0.456f); + } + + @Test + public void setAlpha_flagOn_doesNothing() { + mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, true); + mController.init(); + mController.onViewAttached(); + updateStateToKeyguard(); + + mKeyguardStatusBarView.setAlpha(0.456f); + + mController.setAlpha(0.123f); + + assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(0.456f); + } + + @Test + public void setDozing_flagOn_doesNothing() { + mFeatureFlags.set(Flags.MIGRATE_KEYGUARD_STATUS_BAR_VIEW, true); + mController.init(); + mController.onViewAttached(); + updateStateToKeyguard(); + assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE); + + mController.setDozing(true); + mController.updateViewState(); + + // setDozing(true) should typically cause the view to hide. But since the flag is on, we + // should ignore these set dozing calls and stay the same visibility. + assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test public void setAlpha_explicitAlpha_setsExplicitAlpha() { mController.onViewAttached(); updateStateToKeyguard(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt new file mode 100644 index 000000000000..e3bee5369eb7 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt @@ -0,0 +1,102 @@ +/* + * 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.ui.viewmodel + +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository +import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.flags.FakeFeatureFlagsClassic +import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.shared.model.StatusBarState +import com.android.systemui.scene.SceneTestUtils +import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags +import com.android.systemui.shade.data.repository.FakeShadeRepository +import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.util.mockito.mock +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest +import org.junit.Test + +@SmallTest +class KeyguardStatusBarViewModelTest : SysuiTestCase() { + private val testScope = TestScope() + private val keyguardRepository = FakeKeyguardRepository() + private val keyguardInteractor = + KeyguardInteractor( + keyguardRepository, + mock<CommandQueue>(), + FakeFeatureFlagsClassic(), + FakeSceneContainerFlags(), + FakeKeyguardBouncerRepository(), + FakeConfigurationRepository(), + FakeShadeRepository() + ) { + SceneTestUtils(this).sceneInteractor() + } + + private val underTest = + KeyguardStatusBarViewModel( + testScope.backgroundScope, + keyguardInteractor, + ) + + @Test + fun isVisible_dozing_false() = + testScope.runTest { + val latest by collectLastValue(underTest.isVisible) + keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD) + + keyguardRepository.setIsDozing(true) + + assertThat(latest).isFalse() + } + + @Test + fun isVisible_statusBarStateShade_false() = + testScope.runTest { + val latest by collectLastValue(underTest.isVisible) + + keyguardRepository.setStatusBarState(StatusBarState.SHADE) + + assertThat(latest).isFalse() + } + + @Test + fun isVisible_statusBarStateShadeLocked_false() = + testScope.runTest { + val latest by collectLastValue(underTest.isVisible) + + keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED) + + assertThat(latest).isFalse() + } + + @Test + fun isVisible_statusBarStateKeyguard_andNotDozing_true() = + testScope.runTest { + val latest by collectLastValue(underTest.isVisible) + + keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD) + keyguardRepository.setIsDozing(false) + + assertThat(latest).isTrue() + } +} |