Add standalone weather view to lockscreen if decoupling isenabled.

At the same time, filters the WEATHER target for the existing
BcSmartspaceView.

The standalone weather view is also controlled via
LockscreenSmartspaceController, alongside the existing BcSmartspaceView.
Together they replace the keyguard_slice_view when the SMARTSPACE flag
is set. Note: keyguard_slice_view is the "legacy" smart space prior to
the introduction of BcSmartspace.

Reusing LockscreenSmartspaceController to control the new view has other
advantages as well.
  1. We can keep just one SmartspaceSession and one session listener.
  2. We can reuse all the existing logic. For example, the logic to
     update the text color when the theme changes, or via region
     sampling.

Also: cleaned up the unused @Named(LOCKSCREEN_SMARTSPACE_TARGET_FILTER)
from SmartspaceModule.kt.

Bug: 261752855
Bug: 265840309
Test: manual
Test: atest LockscreenSmartspaceControllerTest
Change-Id: Ib19b3178f3f7208693de973d0c7ff20ae4310e0a
This commit is contained in:
Xiaowen Lei
2023-01-20 21:05:16 -08:00
parent c3bab253a7
commit a5170d5dd8
5 changed files with 250 additions and 48 deletions

View File

@@ -88,7 +88,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private final ClockRegistry.ClockChangeListener mClockChangedListener;
private ViewGroup mStatusArea;
// If set will replace keyguard_slice_view
// If the SMARTSPACE flag is set, keyguard_slice_view is replaced by the following views.
private View mWeatherView;
private View mSmartspaceView;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@@ -192,10 +194,17 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
if (mSmartspaceController.isEnabled()) {
View ksv = mView.findViewById(R.id.keyguard_slice_view);
int ksvIndex = mStatusArea.indexOfChild(ksv);
int viewIndex = mStatusArea.indexOfChild(ksv);
ksv.setVisibility(View.GONE);
addSmartspaceView(ksvIndex);
// TODO(b/261757708): add content observer for the Settings toggle and add/remove
// weather according to the Settings.
if (mSmartspaceController.isDateWeatherDecoupled()) {
addWeatherView(viewIndex);
viewIndex += 1;
}
addSmartspaceView(viewIndex);
}
mSecureSettings.registerContentObserverForUser(
@@ -237,6 +246,18 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
}
}
private void addWeatherView(int index) {
mWeatherView = mSmartspaceController.buildAndConnectWeatherView(mView);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
MATCH_PARENT, WRAP_CONTENT);
mStatusArea.addView(mWeatherView, index, lp);
int startPadding = getContext().getResources().getDimensionPixelSize(
R.dimen.below_clock_padding_start);
int endPadding = getContext().getResources().getDimensionPixelSize(
R.dimen.below_clock_padding_end);
mWeatherView.setPaddingRelative(startPadding, 0, endPadding, 0);
}
private void addSmartspaceView(int index) {
mSmartspaceView = mSmartspaceController.buildAndConnectView(mView);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(

View File

@@ -107,6 +107,8 @@ import com.android.wm.shell.bubbles.Bubbles;
import java.util.Optional;
import java.util.concurrent.Executor;
import javax.inject.Named;
import dagger.Binds;
import dagger.BindsOptionalOf;
import dagger.Module;
@@ -214,6 +216,10 @@ public abstract class SystemUIModule {
@BindsOptionalOf
abstract BcSmartspaceConfigPlugin optionalBcSmartspaceConfigPlugin();
@BindsOptionalOf
@Named(SmartspaceModule.WEATHER_SMARTSPACE_DATA_PLUGIN)
abstract BcSmartspaceDataPlugin optionalWeatherSmartspaceConfigPlugin();
@BindsOptionalOf
abstract Recents optionalRecents();

View File

@@ -18,7 +18,6 @@ package com.android.systemui.smartspace.dagger
import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.smartspace.SmartspacePrecondition
import com.android.systemui.smartspace.SmartspaceTargetFilter
import com.android.systemui.smartspace.filters.LockscreenAndDreamTargetFilter
import com.android.systemui.smartspace.preconditions.LockscreenPrecondition
import dagger.Binds
import dagger.BindsOptionalOf
@@ -34,11 +33,6 @@ abstract class SmartspaceModule {
*/
const val DREAM_SMARTSPACE_DATA_PLUGIN = "dreams_smartspace_data_plugin"
/**
* The lockscreen smartspace target filter.
*/
const val LOCKSCREEN_SMARTSPACE_TARGET_FILTER = "lockscreen_smartspace_target_filter"
/**
* The dream smartspace target filter.
*/
@@ -48,6 +42,11 @@ abstract class SmartspaceModule {
* The precondition for dream smartspace
*/
const val DREAM_SMARTSPACE_PRECONDITION = "dream_smartspace_precondition"
/**
* The BcSmartspaceDataPlugin for the standalone weather.
*/
const val WEATHER_SMARTSPACE_DATA_PLUGIN = "weather_smartspace_data_plugin"
}
@BindsOptionalOf
@@ -58,12 +57,6 @@ abstract class SmartspaceModule {
@Named(DREAM_SMARTSPACE_DATA_PLUGIN)
abstract fun optionalDreamsBcSmartspaceDataPlugin(): BcSmartspaceDataPlugin?
@Binds
@Named(LOCKSCREEN_SMARTSPACE_TARGET_FILTER)
abstract fun provideLockscreenSmartspaceTargetFilter(
filter: LockscreenAndDreamTargetFilter?
): SmartspaceTargetFilter?
@Binds
@Named(DREAM_SMARTSPACE_PRECONDITION)
abstract fun bindSmartspacePrecondition(

View File

@@ -52,6 +52,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.regionsampling.RegionSampler
import com.android.systemui.shared.regionsampling.UpdateColorCallback
import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.WEATHER_SMARTSPACE_DATA_PLUGIN
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -60,6 +61,7 @@ import com.android.systemui.util.settings.SecureSettings
import java.util.Optional
import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Named
/** Controller for managing the smartspace view on the lockscreen */
@SysUISingleton
@@ -82,6 +84,8 @@ constructor(
@Main private val uiExecutor: Executor,
@Background private val bgExecutor: Executor,
@Main private val handler: Handler,
@Named(WEATHER_SMARTSPACE_DATA_PLUGIN)
optionalWeatherPlugin: Optional<BcSmartspaceDataPlugin>,
optionalPlugin: Optional<BcSmartspaceDataPlugin>,
optionalConfigPlugin: Optional<BcSmartspaceConfigPlugin>,
) {
@@ -90,6 +94,7 @@ constructor(
}
private var session: SmartspaceSession? = null
private val weatherPlugin: BcSmartspaceDataPlugin? = optionalWeatherPlugin.orElse(null)
private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
private val configPlugin: BcSmartspaceConfigPlugin? = optionalConfigPlugin.orElse(null)
@@ -131,6 +136,10 @@ constructor(
private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets ->
execution.assertIsMainThread()
// The weather data plugin takes unfiltered targets and performs the filtering internally.
weatherPlugin?.onTargetsAvailable(targets)
val filteredTargets = targets.filter(::filterSmartspaceTarget)
plugin?.onTargetsAvailable(filteredTargets)
if (!isContentUpdatedOnce) {
@@ -209,11 +218,37 @@ constructor(
return plugin != null
}
fun isDateWeatherDecoupled(): Boolean {
execution.assertIsMainThread()
return featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED) &&
weatherPlugin != null
}
private fun updateBypassEnabled() {
val bypassEnabled = bypassController.bypassEnabled
smartspaceViews.forEach { it.setKeyguardBypassEnabled(bypassEnabled) }
}
/**
* Constructs the weather view and connects it to the smartspace service.
*/
fun buildAndConnectWeatherView(parent: ViewGroup): View? {
execution.assertIsMainThread()
if (!isEnabled()) {
throw RuntimeException("Cannot build view when not enabled")
}
if (!isDateWeatherDecoupled()) {
throw RuntimeException("Cannot build weather view when not decoupled")
}
val view = buildView(parent, weatherPlugin)
connectSession()
return view
}
/**
* Constructs the smartspace view and connects it to the smartspace service.
*/
@@ -224,17 +259,17 @@ constructor(
throw RuntimeException("Cannot build view when not enabled")
}
val view = buildView(parent)
val view = buildView(parent, plugin, configPlugin)
connectSession()
return view
}
fun requestSmartspaceUpdate() {
session?.requestSmartspaceUpdate()
}
private fun buildView(parent: ViewGroup): View? {
private fun buildView(
parent: ViewGroup,
plugin: BcSmartspaceDataPlugin?,
configPlugin: BcSmartspaceConfigPlugin? = null
): View? {
if (plugin == null) {
return null
}
@@ -242,7 +277,7 @@ constructor(
val ssView = plugin.getView(parent)
ssView.setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
ssView.registerDataProvider(plugin)
ssView.registerConfigProvider(configPlugin)
configPlugin?.let { ssView.registerConfigProvider(it) }
ssView.setIntentStarter(object : BcSmartspaceDataPlugin.IntentStarter {
override fun startIntent(view: View, intent: Intent, showOnLockscreen: Boolean) {
@@ -273,7 +308,8 @@ constructor(
}
private fun connectSession() {
if (plugin == null || session != null || smartspaceViews.isEmpty()) {
if (weatherPlugin == null && plugin == null) return
if (session != null || smartspaceViews.isEmpty()) {
return
}
@@ -310,14 +346,20 @@ constructor(
statusBarStateController.addCallback(statusBarStateListener)
bypassController.registerOnBypassStateChangedListener(bypassStateChangedListener)
plugin.registerSmartspaceEventNotifier {
e -> session?.notifySmartspaceEvent(e)
}
weatherPlugin?.registerSmartspaceEventNotifier { e -> session?.notifySmartspaceEvent(e) }
plugin?.registerSmartspaceEventNotifier { e -> session?.notifySmartspaceEvent(e) }
updateBypassEnabled()
reloadSmartspace()
}
/**
* Requests the smartspace session for an update.
*/
fun requestSmartspaceUpdate() {
session?.requestSmartspaceUpdate()
}
/**
* Disconnects the smartspace view from the smartspace service and cleans up any resources.
*/
@@ -341,9 +383,13 @@ constructor(
bypassController.unregisterOnBypassStateChangedListener(bypassStateChangedListener)
session = null
weatherPlugin?.registerSmartspaceEventNotifier(null)
weatherPlugin?.onTargetsAvailable(emptyList())
plugin?.registerSmartspaceEventNotifier(null)
plugin?.onTargetsAvailable(emptyList())
Log.d(TAG, "Ending smartspace session for lockscreen")
Log.d(TAG, "Ended smartspace session for lockscreen")
}
fun addListener(listener: SmartspaceTargetListener) {
@@ -357,8 +403,11 @@ constructor(
}
private fun filterSmartspaceTarget(t: SmartspaceTarget): Boolean {
if (isDateWeatherDecoupled()) {
return t.featureType != SmartspaceTarget.FEATURE_WEATHER
}
if (!showNotifications) {
return t.getFeatureType() == SmartspaceTarget.FEATURE_WEATHER
return t.featureType == SmartspaceTarget.FEATURE_WEATHER
}
return when (t.userHandle) {
userTracker.userHandle -> {

View File

@@ -34,6 +34,7 @@ import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.BcSmartspaceConfigPlugin
import com.android.systemui.plugins.BcSmartspaceDataPlugin
@@ -111,6 +112,9 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
@Mock
private lateinit var handler: Handler
@Mock
private lateinit var weatherPlugin: BcSmartspaceDataPlugin
@Mock
private lateinit var plugin: BcSmartspaceDataPlugin
@@ -151,6 +155,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
KeyguardBypassController.OnBypassStateChangedListener
private lateinit var deviceProvisionedListener: DeviceProvisionedListener
private lateinit var weatherSmartspaceView: SmartspaceView
private lateinit var smartspaceView: SmartspaceView
private val clock = FakeSystemClock()
@@ -176,16 +181,22 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
// Todo(b/261760571): flip the flag value here when feature is launched, and update relevant
// tests.
`when`(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(false)
`when`(secureSettings.getUriFor(PRIVATE_LOCKSCREEN_SETTING))
.thenReturn(fakePrivateLockscreenSettingUri)
`when`(secureSettings.getUriFor(NOTIF_ON_LOCKSCREEN_SETTING))
.thenReturn(fakeNotifOnLockscreenSettingUri)
`when`(smartspaceManager.createSmartspaceSession(any())).thenReturn(smartspaceSession)
`when`(weatherPlugin.getView(any())).thenReturn(
createWeatherSmartspaceView(), createWeatherSmartspaceView())
`when`(plugin.getView(any())).thenReturn(createSmartspaceView(), createSmartspaceView())
`when`(userTracker.userProfiles).thenReturn(userList)
`when`(statusBarStateController.dozeAmount).thenReturn(0.5f)
`when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true)
`when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(true)
`when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
`when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
setActiveUser(userHandlePrimary)
setAllowPrivateNotifications(userHandlePrimary, true)
@@ -210,6 +221,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
executor,
bgExecutor,
handler,
Optional.of(weatherPlugin),
Optional.of(plugin),
Optional.of(configPlugin),
)
@@ -218,11 +230,22 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
deviceProvisionedListener = deviceProvisionedCaptor.value
}
@Test(expected = RuntimeException::class)
fun testBuildAndConnectWeatherView_throwsIfDecouplingDisabled() {
// GIVEN the feature flag is disabled
`when`(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(false)
// WHEN we try to build the view
controller.buildAndConnectWeatherView(fakeParent)
// THEN an exception is thrown
}
@Test
fun connectOnlyAfterDeviceIsProvisioned() {
fun testBuildAndConnectView_connectsOnlyAfterDeviceIsProvisioned() {
// GIVEN an unprovisioned device and an attempt to connect
`when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(false)
`when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(false)
`when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(false)
`when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
// WHEN a connection attempt is made and view is attached
val view = controller.buildAndConnectView(fakeParent)
@@ -232,8 +255,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
verify(smartspaceManager, never()).createSmartspaceSession(any())
// WHEN it does become provisioned
`when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true)
`when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(true)
`when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
`when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
deviceProvisionedListener.onUserSetupChanged()
// THEN the session is created
@@ -243,7 +266,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
}
@Test
fun testListenersAreRegistered() {
fun testAddListener_registersListenersForPlugin() {
// GIVEN a listener is added after a session is created
connectSession()
@@ -252,10 +275,12 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
// THEN the listener is registered to the underlying plugin
verify(plugin).registerListener(controllerListener)
// The listener is registered only for the plugin, not the weather plugin.
verify(weatherPlugin, never()).registerListener(any())
}
@Test
fun testEarlyRegisteredListenersAreAttachedAfterConnected() {
fun testAddListener_earlyRegisteredListenersAreAttachedAfterConnected() {
// GIVEN a listener that is registered before the session is created
controller.addListener(controllerListener)
@@ -264,10 +289,12 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
// THEN the listener is subsequently registered
verify(plugin).registerListener(controllerListener)
// The listener is registered only for the plugin, not the weather plugin.
verify(weatherPlugin, never()).registerListener(any())
}
@Test
fun testEmptyListIsEmittedAndNotifierRemovedAfterDisconnect() {
fun testDisconnect_emitsEmptyListAndRemovesNotifier() {
// GIVEN a registered listener on an active session
connectSession()
clearInvocations(plugin)
@@ -279,10 +306,12 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
// THEN the listener receives an empty list of targets and unregisters the notifier
verify(plugin).onTargetsAvailable(emptyList())
verify(plugin).registerSmartspaceEventNotifier(null)
verify(weatherPlugin).onTargetsAvailable(emptyList())
verify(weatherPlugin).registerSmartspaceEventNotifier(null)
}
@Test
fun testUserChangeReloadsSmartspace() {
fun testUserChange_reloadsSmartspace() {
// GIVEN a connected smartspace session
connectSession()
@@ -294,7 +323,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
}
@Test
fun testSettingsChangeReloadsSmartspace() {
fun testSettingsChange_reloadsSmartspace() {
// GIVEN a connected smartspace session
connectSession()
@@ -306,7 +335,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
}
@Test
fun testThemeChangeUpdatesTextColor() {
fun testThemeChange_updatesTextColor() {
// GIVEN a connected smartspace session
connectSession()
@@ -318,7 +347,22 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
}
@Test
fun testDozeAmountChangeUpdatesView() {
fun testThemeChange_ifDecouplingEnabled_updatesTextColor() {
`when`(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(true)
// GIVEN a connected smartspace session
connectSession()
// WHEN the theme changes
configChangeListener.onThemeChanged()
// We update the new text color to match the wallpaper color
verify(weatherSmartspaceView).setPrimaryTextColor(anyInt())
verify(smartspaceView).setPrimaryTextColor(anyInt())
}
@Test
fun testDozeAmountChange_updatesView() {
// GIVEN a connected smartspace session
connectSession()
@@ -330,7 +374,22 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
}
@Test
fun testKeyguardBypassEnabledUpdatesView() {
fun testDozeAmountChange_ifDecouplingEnabled_updatesViews() {
`when`(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(true)
// GIVEN a connected smartspace session
connectSession()
// WHEN the doze amount changes
statusBarStateListener.onDozeAmountChanged(0.1f, 0.7f)
// We pass that along to the view
verify(weatherSmartspaceView).setDozeAmount(0.7f)
verify(smartspaceView).setDozeAmount(0.7f)
}
@Test
fun testKeyguardBypassEnabled_updatesView() {
// GIVEN a connected smartspace session
connectSession()
`when`(keyguardBypassController.bypassEnabled).thenReturn(true)
@@ -424,6 +483,27 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
)))
}
@Test
fun testSessionListener_ifDecouplingEnabled_weatherTargetIsFilteredOut() {
`when`(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(true)
connectSession()
// WHEN we receive a list of targets
val targets = listOf(
makeTarget(1, userHandlePrimary, isSensitive = true),
makeTarget(2, userHandlePrimary),
makeTarget(3, userHandleManaged),
makeTarget(4, userHandlePrimary, featureType = SmartspaceTarget.FEATURE_WEATHER)
)
sessionListener.onTargetsAvailable(targets)
// THEN all non-sensitive content is still shown
verify(plugin).onTargetsAvailable(eq(listOf(targets[0], targets[1], targets[2])))
// No filtering is applied for the weather plugin
verify(weatherPlugin).onTargetsAvailable(eq(targets))
}
@Test
fun testSettingsAreReloaded() {
// GIVEN a connected session where the privacy settings later flip to false
@@ -514,6 +594,16 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
verify(smartspaceView2).registerConfigProvider(configPlugin)
}
@Test
fun testWeatherViewUsesSameSession() {
`when`(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(true)
// GIVEN a connected session
connectSession()
// No checks is needed here, since connectSession() already checks internally that
// createSmartspaceSession is invoked only once.
}
@Test
fun testViewGetInitializedWithBypassEnabledState() {
// GIVEN keyguard bypass is enabled.
@@ -531,8 +621,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
fun testConnectAttemptBeforeInitializationShouldNotCreateSession() {
// GIVEN an uninitalized smartspaceView
// WHEN the device is provisioned
`when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true)
`when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(true)
`when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
`when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
deviceProvisionedListener.onDeviceProvisionedChanged()
// THEN no calls to createSmartspaceSession should occur
@@ -542,9 +632,23 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
}
private fun connectSession() {
if (controller.isDateWeatherDecoupled()) {
val weatherView = controller.buildAndConnectWeatherView(fakeParent)
weatherSmartspaceView = weatherView as SmartspaceView
fakeParent.addView(weatherView)
controller.stateChangeListener.onViewAttachedToWindow(weatherView)
verify(weatherSmartspaceView).setUiSurface(
BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
verify(weatherSmartspaceView).registerDataProvider(weatherPlugin)
verify(weatherSmartspaceView).setPrimaryTextColor(anyInt())
verify(weatherSmartspaceView).setDozeAmount(0.5f)
}
val view = controller.buildAndConnectView(fakeParent)
smartspaceView = view as SmartspaceView
fakeParent.addView(view)
controller.stateChangeListener.onViewAttachedToWindow(view)
verify(smartspaceView).setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
@@ -554,6 +658,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
.addOnTargetsAvailableListener(any(), capture(sessionListenerCaptor))
sessionListener = sessionListenerCaptor.value
verify(smartspaceManager).createSmartspaceSession(any())
verify(userTracker).addCallback(capture(userTrackerCaptor), any())
userListener = userTrackerCaptor.value
@@ -578,9 +684,11 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
verify(smartspaceView).setPrimaryTextColor(anyInt())
verify(smartspaceView).setDozeAmount(0.5f)
clearInvocations(view)
fakeParent.addView(view)
if (controller.isDateWeatherDecoupled()) {
clearInvocations(weatherSmartspaceView)
}
clearInvocations(smartspaceView)
}
private fun setActiveUser(userHandle: UserHandle) {
@@ -626,6 +734,31 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
).thenReturn(if (value) 1 else 0)
}
// Separate function for the weather view, which doesn't implement all functions in interface.
private fun createWeatherSmartspaceView(): SmartspaceView {
return spy(object : View(context), SmartspaceView {
override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) {
}
override fun setPrimaryTextColor(color: Int) {
}
override fun setIsDreaming(isDreaming: Boolean) {
}
override fun setUiSurface(uiSurface: String) {
}
override fun setDozeAmount(amount: Float) {
}
override fun setIntentStarter(intentStarter: BcSmartspaceDataPlugin.IntentStarter?) {
}
override fun setFalsingManager(falsingManager: FalsingManager?) {
}
})
}
private fun createSmartspaceView(): SmartspaceView {
return spy(object : View(context), SmartspaceView {
override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) {