Merge "[CS] 2/N: Define WallpaperRepository.wallpaperSupportsAmbientMode." into main

This commit is contained in:
Caitlin Shkuratov
2023-07-13 17:06:21 +00:00
committed by Android (Google) Code Review
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

@@ -3565,6 +3565,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) {
@@ -3584,7 +3588,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;
@@ -71,8 +72,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;
@@ -89,7 +92,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);
@@ -207,6 +211,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;
@@ -268,6 +273,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;
@@ -297,11 +303,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,
FeatureFlags featureFlags) {
@@ -317,6 +325,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);
@@ -348,9 +357,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.
*/
@@ -1551,7 +1568,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;
@@ -77,9 +78,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;
@@ -100,6 +103,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)
@@ -113,6 +117,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;
@@ -136,6 +143,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;
@@ -274,20 +282,26 @@ public class ScrimControllerTest extends SysuiTestCase {
mDockManager,
mConfigurationController,
new FakeExecutor(new FakeSystemClock()),
mJavaAdapter,
mScreenOffAnimationController,
mKeyguardUnlockAnimationController,
mStatusBarKeyguardViewManager,
mPrimaryBouncerToGoneTransitionViewModel,
mKeyguardTransitionInteractor,
mWallpaperRepository,
mMainDispatcher,
mLinearLargeScreenShadeInterpolator,
mFeatureFlags);
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();
}
@@ -388,7 +402,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();
@@ -410,7 +426,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();
@@ -427,7 +445,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);
@@ -540,7 +560,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(
@@ -968,19 +990,23 @@ public class ScrimControllerTest extends SysuiTestCase {
mDockManager,
mConfigurationController,
new FakeExecutor(new FakeSystemClock()),
mJavaAdapter,
mScreenOffAnimationController,
mKeyguardUnlockAnimationController,
mStatusBarKeyguardViewManager,
mPrimaryBouncerToGoneTransitionViewModel,
mKeyguardTransitionInteractor,
mWallpaperRepository,
mMainDispatcher,
mLinearLargeScreenShadeInterpolator,
mFeatureFlags);
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();
@@ -1105,7 +1131,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);
@@ -1116,7 +1144,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);
@@ -1165,7 +1194,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();
@@ -1182,7 +1213,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) }
}
}