diff options
| author | 2023-07-14 17:11:16 +0000 | |
|---|---|---|
| committer | 2023-07-14 17:11:16 +0000 | |
| commit | 4894e35f11ce45f1b6166745d743af5685ff132c (patch) | |
| tree | 49c6090c17cf804c9f299be686c376bb288dd68e | |
| parent | ca108697a3185876aac6a4b90d7fd866072431cd (diff) | |
| parent | f2337c5f8cb23542d8923378e11913a67e3d5633 (diff) | |
Merge "[CS] 2/N: Define WallpaperRepository.wallpaperSupportsAmbientMode." into udc-qpr-dev
12 files changed, 562 insertions, 13 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java index f68bd49230d9..35cf4a1ecf0a 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java @@ -71,6 +71,7 @@ import com.android.systemui.statusbar.policy.IndividualSensorPrivacyControllerIm import com.android.systemui.statusbar.policy.SensorPrivacyController; import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl; import com.android.systemui.volume.dagger.VolumeModule; +import com.android.systemui.wallpapers.dagger.WallpaperModule; import dagger.Binds; import dagger.Module; @@ -106,6 +107,7 @@ import javax.inject.Named; StatusBarEventsModule.class, StartCentralSurfacesModule.class, VolumeModule.class, + WallpaperModule.class, KeyboardShortcutsModule.class }) public abstract class ReferenceSystemUIModule { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt index b1f513d0945c..a560accfff68 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt @@ -51,6 +51,7 @@ import com.android.systemui.shortcut.ShortcutKeyDispatcher import com.android.systemui.statusbar.notification.InstantAppNotifier import com.android.systemui.statusbar.phone.KeyguardLiftController import com.android.systemui.statusbar.phone.LockscreenWallpaper +import com.android.systemui.statusbar.phone.ScrimController import com.android.systemui.stylus.StylusUsiPowerStartable import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator import com.android.systemui.theme.ThemeOverlayController @@ -59,6 +60,7 @@ import com.android.systemui.usb.StorageNotification import com.android.systemui.util.NotificationChannels import com.android.systemui.util.StartBinderLoggerModule import com.android.systemui.volume.VolumeUI +import com.android.systemui.wallpapers.dagger.WallpaperModule import com.android.systemui.wmshell.WMShell import dagger.Binds import dagger.Module @@ -72,6 +74,7 @@ import dagger.multibindings.IntoMap MultiUserUtilsModule::class, StartControlsStartableModule::class, StartBinderLoggerModule::class, + WallpaperModule::class, ]) abstract class SystemUICoreStartableModule { /** Inject into AuthController. */ @@ -316,4 +319,9 @@ abstract class SystemUICoreStartableModule { @IntoMap @ClassKey(LockscreenWallpaper::class) abstract fun bindLockscreenWallpaper(impl: LockscreenWallpaper): CoreStartable + + @Binds + @IntoMap + @ClassKey(ScrimController::class) + abstract fun bindScrimController(impl: ScrimController): CoreStartable } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 62e98f934888..0a7ee52fba46 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -3550,6 +3550,10 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } }; + /** + * @deprecated See {@link com.android.systemui.wallpapers.data.repository.WallpaperRepository} + * instead. + */ private final BroadcastReceiver mWallpaperChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -3569,7 +3573,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { && (info != null && info.supportsAmbientMode()); mNotificationShadeWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode); - mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode); mKeyguardViewMediator.setWallpaperSupportsAmbientMode(supportsAmbientMode); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 3cd09a61e12a..e82ac59b6746 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -48,6 +48,7 @@ import com.android.keyguard.BouncerPanelExpansionCalculator; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.settingslib.Utils; +import com.android.systemui.CoreStartable; import com.android.systemui.DejankUtils; import com.android.systemui.Dumpable; import com.android.systemui.R; @@ -69,8 +70,10 @@ import com.android.systemui.statusbar.notification.stack.ViewState; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.AlarmTimeout; +import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.wakelock.DelayedWakeLock; import com.android.systemui.util.wakelock.WakeLock; +import com.android.systemui.wallpapers.data.repository.WallpaperRepository; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -87,7 +90,8 @@ import kotlinx.coroutines.CoroutineDispatcher; * security method gets shown). */ @SysUISingleton -public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dumpable { +public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dumpable, + CoreStartable { static final String TAG = "ScrimController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -205,6 +209,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump private final KeyguardVisibilityCallback mKeyguardVisibilityCallback; private final Handler mHandler; private final Executor mMainExecutor; + private final JavaAdapter mJavaAdapter; private final ScreenOffAnimationController mScreenOffAnimationController; private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @@ -264,6 +269,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump private boolean mKeyguardOccluded; private KeyguardTransitionInteractor mKeyguardTransitionInteractor; + private final WallpaperRepository mWallpaperRepository; private CoroutineDispatcher mMainDispatcher; private boolean mIsBouncerToGoneTransitionRunning = false; private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel; @@ -293,11 +299,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump DockManager dockManager, ConfigurationController configurationController, @Main Executor mainExecutor, + JavaAdapter javaAdapter, ScreenOffAnimationController screenOffAnimationController, KeyguardUnlockAnimationController keyguardUnlockAnimationController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel, KeyguardTransitionInteractor keyguardTransitionInteractor, + WallpaperRepository wallpaperRepository, @Main CoroutineDispatcher mainDispatcher, LargeScreenShadeInterpolator largeScreenShadeInterpolator) { mScrimStateListener = lightBarController::setScrimState; @@ -310,6 +318,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump mKeyguardVisibilityCallback = new KeyguardVisibilityCallback(); mHandler = handler; mMainExecutor = mainExecutor; + mJavaAdapter = javaAdapter; mScreenOffAnimationController = screenOffAnimationController; mTimeTicker = new AlarmTimeout(alarmManager, this::onHideWallpaperTimeout, "hide_aod_wallpaper", mHandler); @@ -341,9 +350,17 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump mColors = new GradientColors(); mPrimaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel; mKeyguardTransitionInteractor = keyguardTransitionInteractor; + mWallpaperRepository = wallpaperRepository; mMainDispatcher = mainDispatcher; } + @Override + public void start() { + mJavaAdapter.alwaysCollectFlow( + mWallpaperRepository.getWallpaperSupportsAmbientMode(), + this::setWallpaperSupportsAmbientMode); + } + /** * Attach the controller to the supplied views. */ @@ -1531,7 +1548,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump pw.println(mState.getMaxLightRevealScrimAlpha()); } - public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) { + private void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) { mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode; ScrimState[] states = ScrimState.values(); for (int i = 0; i < states.length; i++) { diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java index 5e489b0f38ac..82589d3ea1d4 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java @@ -27,6 +27,7 @@ import com.android.systemui.recents.RecentsModule; import com.android.systemui.statusbar.dagger.CentralSurfacesDependenciesModule; import com.android.systemui.statusbar.notification.dagger.NotificationsModule; import com.android.systemui.statusbar.notification.row.NotificationRowModule; +import com.android.systemui.wallpapers.dagger.NoopWallpaperModule; import dagger.Subcomponent; @@ -39,6 +40,7 @@ import dagger.Subcomponent; DefaultComponentBinder.class, DependencyProvider.class, KeyguardModule.class, + NoopWallpaperModule.class, NotificationRowModule.class, NotificationsModule.class, RecentsModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/dagger/NoopWallpaperModule.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/dagger/NoopWallpaperModule.kt new file mode 100644 index 000000000000..baf88b0d9cbb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/dagger/NoopWallpaperModule.kt @@ -0,0 +1,30 @@ +/* + * 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.wallpapers.dagger + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.wallpapers.data.repository.NoopWallpaperRepository +import com.android.systemui.wallpapers.data.repository.WallpaperRepository +import dagger.Binds +import dagger.Module + +@Module +interface NoopWallpaperModule { + @Binds + @SysUISingleton + fun bindWallpaperRepository(impl: NoopWallpaperRepository): WallpaperRepository +} diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/dagger/WallpaperModule.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/dagger/WallpaperModule.kt new file mode 100644 index 000000000000..1b899784038e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/dagger/WallpaperModule.kt @@ -0,0 +1,30 @@ +/* + * 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.wallpapers.dagger + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.wallpapers.data.repository.WallpaperRepository +import com.android.systemui.wallpapers.data.repository.WallpaperRepositoryImpl +import dagger.Binds +import dagger.Module + +@Module +interface WallpaperModule { + @Binds + @SysUISingleton + fun bindWallpaperRepository(impl: WallpaperRepositoryImpl): WallpaperRepository +} diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt new file mode 100644 index 000000000000..a64058968581 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt @@ -0,0 +1,33 @@ +/* + * 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.wallpapers.data.repository + +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow + +/** + * A no-op implementation of [WallpaperRepository]. + * + * Used for variants of SysUI that do not support wallpaper but require other SysUI classes that + * have a wallpaper dependency. + */ +@SysUISingleton +class NoopWallpaperRepository @Inject constructor() : WallpaperRepository { + override val wallpaperSupportsAmbientMode = MutableStateFlow(false).asStateFlow() +} diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt new file mode 100644 index 000000000000..48895ffcacb9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt @@ -0,0 +1,105 @@ +/* + * 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.wallpapers.data.repository + +import android.app.WallpaperManager +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.UserHandle +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.user.data.model.SelectedUserModel +import com.android.systemui.user.data.model.SelectionStatus +import com.android.systemui.user.data.repository.UserRepository +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn + +/** A repository storing information about the current wallpaper. */ +interface WallpaperRepository { + /** Emits true if the current user's current wallpaper supports ambient mode. */ + val wallpaperSupportsAmbientMode: StateFlow<Boolean> +} + +@SysUISingleton +class WallpaperRepositoryImpl +@Inject +constructor( + @Application scope: CoroutineScope, + broadcastDispatcher: BroadcastDispatcher, + userRepository: UserRepository, + private val wallpaperManager: WallpaperManager, + context: Context, +) : WallpaperRepository { + private val deviceSupportsAodWallpaper = + context.resources.getBoolean(com.android.internal.R.bool.config_dozeSupportsAodWallpaper) + + private val wallpaperChanged: Flow<Unit> = + broadcastDispatcher + .broadcastFlow( + IntentFilter(Intent.ACTION_WALLPAPER_CHANGED), + user = UserHandle.ALL, + ) + // The `combine` defining `wallpaperSupportsAmbientMode` will not run until both of the + // input flows emit at least once. Since this flow is an input flow, it needs to emit + // when it starts up to ensure that the `combine` will run if the user changes before we + // receive a ACTION_WALLPAPER_CHANGED intent. + // Note that the `selectedUser` flow does *not* need to emit on start because + // [UserRepository.selectedUser] is a state flow which will automatically emit a value + // on start. + .onStart { emit(Unit) } + + private val selectedUser: Flow<SelectedUserModel> = + userRepository.selectedUser + // Only update the wallpaper status once the user selection has finished. + .filter { it.selectionStatus == SelectionStatus.SELECTION_COMPLETE } + + override val wallpaperSupportsAmbientMode: StateFlow<Boolean> = + if (!wallpaperManager.isWallpaperSupported || !deviceSupportsAodWallpaper) { + MutableStateFlow(false).asStateFlow() + } else { + combine(wallpaperChanged, selectedUser) { _, selectedUser -> + doesWallpaperSupportAmbientMode(selectedUser) + } + .stateIn( + scope, + // Always be listening for wallpaper changes. + SharingStarted.Eagerly, + initialValue = + doesWallpaperSupportAmbientMode(userRepository.selectedUser.value), + ) + } + + private fun doesWallpaperSupportAmbientMode(selectedUser: SelectedUserModel): Boolean { + return wallpaperManager + .getWallpaperInfoForUser( + selectedUser.userInfo.id, + ) + // If WallpaperInfo is null, it's ImageWallpaper which never supports ambient mode. + ?.supportsAmbientMode() == true + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index 33c77cc3e250..0dc1d9a4b177 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -59,6 +59,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.colorextraction.ColorExtractor.GradientColors; import com.android.keyguard.BouncerPanelExpansionCalculator; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.TestScopeProvider; import com.android.systemui.DejankUtils; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.ShadeInterpolation; @@ -76,9 +77,11 @@ import com.android.systemui.shade.transition.LinearLargeScreenShadeInterpolator; import com.android.systemui.statusbar.policy.FakeConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.util.wakelock.DelayedWakeLock; import com.android.systemui.utils.os.FakeHandler; +import com.android.systemui.wallpapers.data.repository.FakeWallpaperRepository; import com.google.common.truth.Expect; @@ -99,6 +102,7 @@ import java.util.HashSet; import java.util.Map; import kotlinx.coroutines.CoroutineDispatcher; +import kotlinx.coroutines.test.TestScope; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @@ -112,6 +116,9 @@ public class ScrimControllerTest extends SysuiTestCase { private final LargeScreenShadeInterpolator mLinearLargeScreenShadeInterpolator = new LinearLargeScreenShadeInterpolator(); + private final TestScope mTestScope = TestScopeProvider.getTestScope(); + private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope()); + private ScrimController mScrimController; private ScrimView mScrimBehind; private ScrimView mNotificationsScrim; @@ -135,6 +142,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel; @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor; + private final FakeWallpaperRepository mWallpaperRepository = new FakeWallpaperRepository(); @Mock private CoroutineDispatcher mMainDispatcher; @Mock private TypedArray mMockTypedArray; @@ -272,19 +280,25 @@ public class ScrimControllerTest extends SysuiTestCase { mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()), + mJavaAdapter, mScreenOffAnimationController, mKeyguardUnlockAnimationController, mStatusBarKeyguardViewManager, mPrimaryBouncerToGoneTransitionViewModel, mKeyguardTransitionInteractor, + mWallpaperRepository, mMainDispatcher, mLinearLargeScreenShadeInterpolator); + mScrimController.start(); mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible); mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront); mScrimController.setAnimatorListener(mAnimatorListener); mScrimController.setHasBackdrop(false); - mScrimController.setWallpaperSupportsAmbientMode(false); + + mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(false); + mTestScope.getTestScheduler().runCurrent(); + mScrimController.transitionTo(ScrimState.KEYGUARD); finishAnimationsImmediately(); } @@ -385,7 +399,9 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void transitionToAod_withAodWallpaper() { - mScrimController.setWallpaperSupportsAmbientMode(true); + mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true); + mTestScope.getTestScheduler().runCurrent(); + mScrimController.transitionTo(ScrimState.AOD); finishAnimationsImmediately(); @@ -407,7 +423,9 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void transitionToAod_withAodWallpaperAndLockScreenWallpaper() { mScrimController.setHasBackdrop(true); - mScrimController.setWallpaperSupportsAmbientMode(true); + mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true); + mTestScope.getTestScheduler().runCurrent(); + mScrimController.transitionTo(ScrimState.AOD); finishAnimationsImmediately(); @@ -424,7 +442,9 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void setHasBackdrop_withAodWallpaperAndAlbumArt() { - mScrimController.setWallpaperSupportsAmbientMode(true); + mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true); + mTestScope.getTestScheduler().runCurrent(); + mScrimController.transitionTo(ScrimState.AOD); finishAnimationsImmediately(); mScrimController.setHasBackdrop(true); @@ -537,7 +557,9 @@ public class ScrimControllerTest extends SysuiTestCase { // Pre-condition // Need to go to AoD first because PULSING doesn't change // the back scrim opacity - otherwise it would hide AoD wallpapers. - mScrimController.setWallpaperSupportsAmbientMode(false); + mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(false); + mTestScope.getTestScheduler().runCurrent(); + mScrimController.transitionTo(ScrimState.AOD); finishAnimationsImmediately(); assertScrimAlpha(Map.of( @@ -965,18 +987,22 @@ public class ScrimControllerTest extends SysuiTestCase { mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()), + mJavaAdapter, mScreenOffAnimationController, mKeyguardUnlockAnimationController, mStatusBarKeyguardViewManager, mPrimaryBouncerToGoneTransitionViewModel, mKeyguardTransitionInteractor, + mWallpaperRepository, mMainDispatcher, mLinearLargeScreenShadeInterpolator); + mScrimController.start(); mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible); mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront); mScrimController.setAnimatorListener(mAnimatorListener); mScrimController.setHasBackdrop(false); - mScrimController.setWallpaperSupportsAmbientMode(false); + mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(false); + mTestScope.getTestScheduler().runCurrent(); mScrimController.transitionTo(ScrimState.KEYGUARD); finishAnimationsImmediately(); @@ -1101,7 +1127,9 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void testWillHideAodWallpaper() { - mScrimController.setWallpaperSupportsAmbientMode(true); + mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true); + mTestScope.getTestScheduler().runCurrent(); + mScrimController.transitionTo(ScrimState.AOD); verify(mAlarmManager).setExact(anyInt(), anyLong(), any(), any(), any()); mScrimController.transitionTo(ScrimState.KEYGUARD); @@ -1112,7 +1140,8 @@ public class ScrimControllerTest extends SysuiTestCase { public void testWillHideDockedWallpaper() { mAlwaysOnEnabled = false; when(mDockManager.isDocked()).thenReturn(true); - mScrimController.setWallpaperSupportsAmbientMode(true); + mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true); + mTestScope.getTestScheduler().runCurrent(); mScrimController.transitionTo(ScrimState.AOD); @@ -1161,7 +1190,9 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void testHidesShowWhenLockedActivity() { - mScrimController.setWallpaperSupportsAmbientMode(true); + mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true); + mTestScope.getTestScheduler().runCurrent(); + mScrimController.setKeyguardOccluded(true); mScrimController.transitionTo(ScrimState.AOD); finishAnimationsImmediately(); @@ -1178,7 +1209,9 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void testHidesShowWhenLockedActivity_whenAlreadyInAod() { - mScrimController.setWallpaperSupportsAmbientMode(true); + mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true); + mTestScope.getTestScheduler().runCurrent(); + mScrimController.transitionTo(ScrimState.AOD); finishAnimationsImmediately(); assertScrimAlpha(Map.of( diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt new file mode 100644 index 000000000000..6fc36b08250b --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt @@ -0,0 +1,24 @@ +/* + * 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.wallpapers.data.repository + +import kotlinx.coroutines.flow.MutableStateFlow + +/** Fake implementation of the wallpaper repository. */ +class FakeWallpaperRepository : WallpaperRepository { + override val wallpaperSupportsAmbientMode = MutableStateFlow(false) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt new file mode 100644 index 000000000000..132b9b4a02e1 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt @@ -0,0 +1,262 @@ +/* + * 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.wallpapers.data.repository + +import android.app.WallpaperInfo +import android.app.WallpaperManager +import android.content.Intent +import android.content.pm.UserInfo +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.user.data.model.SelectedUserModel +import com.android.systemui.user.data.model.SelectionStatus +import com.android.systemui.user.data.repository.FakeUserRepository +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test + +@SmallTest +@OptIn(ExperimentalCoroutinesApi::class) +class WallpaperRepositoryImplTest : SysuiTestCase() { + + private val testScope = TestScope(StandardTestDispatcher()) + private val userRepository = FakeUserRepository() + private val wallpaperManager: WallpaperManager = mock() + + private val underTest: WallpaperRepositoryImpl by lazy { + WallpaperRepositoryImpl( + testScope.backgroundScope, + fakeBroadcastDispatcher, + userRepository, + wallpaperManager, + context, + ) + } + + @Before + fun setUp() { + whenever(wallpaperManager.isWallpaperSupported).thenReturn(true) + context.orCreateTestableResources.addOverride( + com.android.internal.R.bool.config_dozeSupportsAodWallpaper, + true, + ) + } + + @Test + fun wallpaperSupportsAmbientMode_nullInfo_false() = + testScope.runTest { + val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) + + whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(null) + + fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + + assertThat(latest).isFalse() + } + + @Test + fun wallpaperSupportsAmbientMode_infoDoesNotSupport_false() = + testScope.runTest { + val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) + + whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(UNSUPPORTED_WP) + + fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + + assertThat(latest).isFalse() + } + + @Test + fun wallpaperSupportsAmbientMode_infoSupports_true() = + testScope.runTest { + val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) + + whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(SUPPORTED_WP) + + fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + + assertThat(latest).isTrue() + } + + @Test + fun wallpaperSupportsAmbientMode_initialValueIsFetched_true() = + testScope.runTest { + whenever(wallpaperManager.getWallpaperInfoForUser(USER_WITH_SUPPORTED_WP.id)) + .thenReturn(SUPPORTED_WP) + userRepository.setUserInfos(listOf(USER_WITH_SUPPORTED_WP)) + userRepository.setSelectedUserInfo(USER_WITH_SUPPORTED_WP) + + // WHEN the repo initially starts up (underTest is lazy), then it fetches the current + // value for the wallpaper + assertThat(underTest.wallpaperSupportsAmbientMode.value).isTrue() + } + + @Test + fun wallpaperSupportsAmbientMode_initialValueIsFetched_false() = + testScope.runTest { + whenever(wallpaperManager.getWallpaperInfoForUser(USER_WITH_UNSUPPORTED_WP.id)) + .thenReturn(UNSUPPORTED_WP) + userRepository.setUserInfos(listOf(USER_WITH_UNSUPPORTED_WP)) + userRepository.setSelectedUserInfo(USER_WITH_UNSUPPORTED_WP) + + // WHEN the repo initially starts up (underTest is lazy), then it fetches the current + // value for the wallpaper + assertThat(underTest.wallpaperSupportsAmbientMode.value).isFalse() + } + + @Test + fun wallpaperSupportsAmbientMode_updatesOnUserChanged() = + testScope.runTest { + val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) + + whenever(wallpaperManager.getWallpaperInfoForUser(USER_WITH_SUPPORTED_WP.id)) + .thenReturn(SUPPORTED_WP) + whenever(wallpaperManager.getWallpaperInfoForUser(USER_WITH_UNSUPPORTED_WP.id)) + .thenReturn(UNSUPPORTED_WP) + userRepository.setUserInfos(listOf(USER_WITH_SUPPORTED_WP, USER_WITH_UNSUPPORTED_WP)) + + // WHEN a user with supported wallpaper is selected + userRepository.setSelectedUserInfo(USER_WITH_SUPPORTED_WP) + + // THEN it's true + assertThat(latest).isTrue() + + // WHEN the user is switched to a user with unsupported wallpaper + userRepository.setSelectedUserInfo(USER_WITH_UNSUPPORTED_WP) + + // THEN it's false + assertThat(latest).isFalse() + } + + @Test + fun wallpaperSupportsAmbientMode_doesNotUpdateOnUserChanging() = + testScope.runTest { + val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) + + whenever(wallpaperManager.getWallpaperInfoForUser(USER_WITH_SUPPORTED_WP.id)) + .thenReturn(SUPPORTED_WP) + whenever(wallpaperManager.getWallpaperInfoForUser(USER_WITH_UNSUPPORTED_WP.id)) + .thenReturn(UNSUPPORTED_WP) + userRepository.setUserInfos(listOf(USER_WITH_SUPPORTED_WP, USER_WITH_UNSUPPORTED_WP)) + + // WHEN a user with supported wallpaper is selected + userRepository.setSelectedUserInfo(USER_WITH_SUPPORTED_WP) + + // THEN it's true + assertThat(latest).isTrue() + + // WHEN the user has started switching to a user with unsupported wallpaper but hasn't + // finished yet + userRepository.selectedUser.value = + SelectedUserModel(USER_WITH_UNSUPPORTED_WP, SelectionStatus.SELECTION_IN_PROGRESS) + + // THEN it still matches the old user + assertThat(latest).isTrue() + } + + @Test + fun wallpaperSupportsAmbientMode_updatesOnIntent() = + testScope.runTest { + val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) + + val info: WallpaperInfo = mock() + whenever(info.supportsAmbientMode()).thenReturn(false) + whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(info) + + assertThat(latest).isFalse() + + // WHEN the info now supports ambient mode and a broadcast is sent + whenever(info.supportsAmbientMode()).thenReturn(true) + fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + + // THEN the flow updates + assertThat(latest).isTrue() + } + + @Test + fun wallpaperSupportsAmbientMode_wallpaperNotSupported_alwaysFalse() = + testScope.runTest { + whenever(wallpaperManager.isWallpaperSupported).thenReturn(false) + + val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) + assertThat(latest).isFalse() + + // Even WHEN the current wallpaper *does* support ambient mode + whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(SUPPORTED_WP) + + fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + + // THEN the value is still false because wallpaper isn't supported + assertThat(latest).isFalse() + } + + @Test + fun wallpaperSupportsAmbientMode_deviceDoesNotSupportAmbientWallpaper_alwaysFalse() = + testScope.runTest { + context.orCreateTestableResources.addOverride( + com.android.internal.R.bool.config_dozeSupportsAodWallpaper, + false + ) + + val latest by collectLastValue(underTest.wallpaperSupportsAmbientMode) + assertThat(latest).isFalse() + + // Even WHEN the current wallpaper *does* support ambient mode + whenever(wallpaperManager.getWallpaperInfoForUser(any())).thenReturn(SUPPORTED_WP) + + fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(Intent.ACTION_WALLPAPER_CHANGED), + ) + + // THEN the value is still false because the device doesn't support it + assertThat(latest).isFalse() + } + + private companion object { + val USER_WITH_UNSUPPORTED_WP = UserInfo(/* id= */ 3, /* name= */ "user3", /* flags= */ 0) + val UNSUPPORTED_WP = + mock<WallpaperInfo>().apply { whenever(this.supportsAmbientMode()).thenReturn(false) } + + val USER_WITH_SUPPORTED_WP = UserInfo(/* id= */ 4, /* name= */ "user4", /* flags= */ 0) + val SUPPORTED_WP = + mock<WallpaperInfo>().apply { whenever(this.supportsAmbientMode()).thenReturn(true) } + } +} |