[CS] 2/N: Define WallpaperRepository.wallpaperSupportsAmbientMode.

This will replace CentralSurfacesImpl.mWallpaperChangedReceiver. This CL
moves ScrimController to the new repo; other controllers will be moved
in future CLs.

Reasoning around NoopWallpaperRepository: Previously,
CentralSurfacesImpl was the only class calling
ScrimController.setWallpaperSupportsAmbientMode. CentralSurfacesImpl is
only included in AOSP SysUI and SysUIGo. So, the new WallpaperRepository
should also only be enabled for AOSP SysUI and SysUIGo. However,
ScrimController is included in *more* than just those two variants.
NoopWallpaperRepository should be used for those variants to ensure that
they can still use ScrimController and also still *not* pay attention to
wallpaper changes.

Bug: 277762009
Bug: 277764509
Test: manual: verify via logging that WallpaperRepository re-calcuates
supportsAmbientMode at the same pace as CentralSurfacesImpl with the
same values. Specifically verify the value is re-calcuated whenever the
wallpaper is changed or the user is switched.
Test: manual: switch users *without first switching the wallpaper* and
verify via logging that the repository re-fetches supportsAmbientMode.
(This specifically tests that the `wallpaperChanged` flow uses `.onStart
{ emit(Unit) }`, which was missing in the first iteration of this CL.)

Test: atest WallpaperRepositoryImplTest ScrimControllerTest
Change-Id: Icb69f842c52c19d89857218d07077ad90d83c1e6
Merged-In: Icb69f842c52c19d89857218d07077ad90d83c1e6
This commit is contained in:
Caitlin Shkuratov
2023-06-26 21:15:23 +00:00
parent ca293169ca
commit f2337c5f8c
12 changed files with 562 additions and 13 deletions

View File

@@ -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 {

View File

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

View File

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

View File

@@ -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++) {

View File

@@ -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,

View File

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

View File

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

View File

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

View File

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

View File

@@ -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(

View File

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

View File

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