Merge "Add standalone weather view to lockscreen if decoupling isenabled." into tm-qpr-dev am: 7e9ff1ef7b
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21062126 Change-Id: Ifc4eb005555b1baefd6b19e74e40fe594d59e33f Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -88,7 +88,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
|||||||
private final ClockRegistry.ClockChangeListener mClockChangedListener;
|
private final ClockRegistry.ClockChangeListener mClockChangedListener;
|
||||||
|
|
||||||
private ViewGroup mStatusArea;
|
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 View mSmartspaceView;
|
||||||
|
|
||||||
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
|
||||||
@@ -192,10 +194,17 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
|||||||
|
|
||||||
if (mSmartspaceController.isEnabled()) {
|
if (mSmartspaceController.isEnabled()) {
|
||||||
View ksv = mView.findViewById(R.id.keyguard_slice_view);
|
View ksv = mView.findViewById(R.id.keyguard_slice_view);
|
||||||
int ksvIndex = mStatusArea.indexOfChild(ksv);
|
int viewIndex = mStatusArea.indexOfChild(ksv);
|
||||||
ksv.setVisibility(View.GONE);
|
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(
|
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) {
|
private void addSmartspaceView(int index) {
|
||||||
mSmartspaceView = mSmartspaceController.buildAndConnectView(mView);
|
mSmartspaceView = mSmartspaceController.buildAndConnectView(mView);
|
||||||
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
|
||||||
|
|||||||
@@ -107,6 +107,8 @@ import com.android.wm.shell.bubbles.Bubbles;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import javax.inject.Named;
|
||||||
|
|
||||||
import dagger.Binds;
|
import dagger.Binds;
|
||||||
import dagger.BindsOptionalOf;
|
import dagger.BindsOptionalOf;
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
@@ -214,6 +216,10 @@ public abstract class SystemUIModule {
|
|||||||
@BindsOptionalOf
|
@BindsOptionalOf
|
||||||
abstract BcSmartspaceConfigPlugin optionalBcSmartspaceConfigPlugin();
|
abstract BcSmartspaceConfigPlugin optionalBcSmartspaceConfigPlugin();
|
||||||
|
|
||||||
|
@BindsOptionalOf
|
||||||
|
@Named(SmartspaceModule.WEATHER_SMARTSPACE_DATA_PLUGIN)
|
||||||
|
abstract BcSmartspaceDataPlugin optionalWeatherSmartspaceConfigPlugin();
|
||||||
|
|
||||||
@BindsOptionalOf
|
@BindsOptionalOf
|
||||||
abstract Recents optionalRecents();
|
abstract Recents optionalRecents();
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package com.android.systemui.smartspace.dagger
|
|||||||
import com.android.systemui.plugins.BcSmartspaceDataPlugin
|
import com.android.systemui.plugins.BcSmartspaceDataPlugin
|
||||||
import com.android.systemui.smartspace.SmartspacePrecondition
|
import com.android.systemui.smartspace.SmartspacePrecondition
|
||||||
import com.android.systemui.smartspace.SmartspaceTargetFilter
|
import com.android.systemui.smartspace.SmartspaceTargetFilter
|
||||||
import com.android.systemui.smartspace.filters.LockscreenAndDreamTargetFilter
|
|
||||||
import com.android.systemui.smartspace.preconditions.LockscreenPrecondition
|
import com.android.systemui.smartspace.preconditions.LockscreenPrecondition
|
||||||
import dagger.Binds
|
import dagger.Binds
|
||||||
import dagger.BindsOptionalOf
|
import dagger.BindsOptionalOf
|
||||||
@@ -34,11 +33,6 @@ abstract class SmartspaceModule {
|
|||||||
*/
|
*/
|
||||||
const val DREAM_SMARTSPACE_DATA_PLUGIN = "dreams_smartspace_data_plugin"
|
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.
|
* The dream smartspace target filter.
|
||||||
*/
|
*/
|
||||||
@@ -48,6 +42,11 @@ abstract class SmartspaceModule {
|
|||||||
* The precondition for dream smartspace
|
* The precondition for dream smartspace
|
||||||
*/
|
*/
|
||||||
const val DREAM_SMARTSPACE_PRECONDITION = "dream_smartspace_precondition"
|
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
|
@BindsOptionalOf
|
||||||
@@ -58,12 +57,6 @@ abstract class SmartspaceModule {
|
|||||||
@Named(DREAM_SMARTSPACE_DATA_PLUGIN)
|
@Named(DREAM_SMARTSPACE_DATA_PLUGIN)
|
||||||
abstract fun optionalDreamsBcSmartspaceDataPlugin(): BcSmartspaceDataPlugin?
|
abstract fun optionalDreamsBcSmartspaceDataPlugin(): BcSmartspaceDataPlugin?
|
||||||
|
|
||||||
@Binds
|
|
||||||
@Named(LOCKSCREEN_SMARTSPACE_TARGET_FILTER)
|
|
||||||
abstract fun provideLockscreenSmartspaceTargetFilter(
|
|
||||||
filter: LockscreenAndDreamTargetFilter?
|
|
||||||
): SmartspaceTargetFilter?
|
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@Named(DREAM_SMARTSPACE_PRECONDITION)
|
@Named(DREAM_SMARTSPACE_PRECONDITION)
|
||||||
abstract fun bindSmartspacePrecondition(
|
abstract fun bindSmartspacePrecondition(
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController
|
|||||||
import com.android.systemui.settings.UserTracker
|
import com.android.systemui.settings.UserTracker
|
||||||
import com.android.systemui.shared.regionsampling.RegionSampler
|
import com.android.systemui.shared.regionsampling.RegionSampler
|
||||||
import com.android.systemui.shared.regionsampling.UpdateColorCallback
|
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.phone.KeyguardBypassController
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||||
import com.android.systemui.statusbar.policy.DeviceProvisionedController
|
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.Optional
|
||||||
import java.util.concurrent.Executor
|
import java.util.concurrent.Executor
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Named
|
||||||
|
|
||||||
/** Controller for managing the smartspace view on the lockscreen */
|
/** Controller for managing the smartspace view on the lockscreen */
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
@@ -82,6 +84,8 @@ constructor(
|
|||||||
@Main private val uiExecutor: Executor,
|
@Main private val uiExecutor: Executor,
|
||||||
@Background private val bgExecutor: Executor,
|
@Background private val bgExecutor: Executor,
|
||||||
@Main private val handler: Handler,
|
@Main private val handler: Handler,
|
||||||
|
@Named(WEATHER_SMARTSPACE_DATA_PLUGIN)
|
||||||
|
optionalWeatherPlugin: Optional<BcSmartspaceDataPlugin>,
|
||||||
optionalPlugin: Optional<BcSmartspaceDataPlugin>,
|
optionalPlugin: Optional<BcSmartspaceDataPlugin>,
|
||||||
optionalConfigPlugin: Optional<BcSmartspaceConfigPlugin>,
|
optionalConfigPlugin: Optional<BcSmartspaceConfigPlugin>,
|
||||||
) {
|
) {
|
||||||
@@ -90,6 +94,7 @@ constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var session: SmartspaceSession? = null
|
private var session: SmartspaceSession? = null
|
||||||
|
private val weatherPlugin: BcSmartspaceDataPlugin? = optionalWeatherPlugin.orElse(null)
|
||||||
private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
|
private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
|
||||||
private val configPlugin: BcSmartspaceConfigPlugin? = optionalConfigPlugin.orElse(null)
|
private val configPlugin: BcSmartspaceConfigPlugin? = optionalConfigPlugin.orElse(null)
|
||||||
|
|
||||||
@@ -131,6 +136,10 @@ constructor(
|
|||||||
|
|
||||||
private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets ->
|
private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets ->
|
||||||
execution.assertIsMainThread()
|
execution.assertIsMainThread()
|
||||||
|
|
||||||
|
// The weather data plugin takes unfiltered targets and performs the filtering internally.
|
||||||
|
weatherPlugin?.onTargetsAvailable(targets)
|
||||||
|
|
||||||
val filteredTargets = targets.filter(::filterSmartspaceTarget)
|
val filteredTargets = targets.filter(::filterSmartspaceTarget)
|
||||||
plugin?.onTargetsAvailable(filteredTargets)
|
plugin?.onTargetsAvailable(filteredTargets)
|
||||||
if (!isContentUpdatedOnce) {
|
if (!isContentUpdatedOnce) {
|
||||||
@@ -209,11 +218,37 @@ constructor(
|
|||||||
return plugin != null
|
return plugin != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isDateWeatherDecoupled(): Boolean {
|
||||||
|
execution.assertIsMainThread()
|
||||||
|
|
||||||
|
return featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED) &&
|
||||||
|
weatherPlugin != null
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateBypassEnabled() {
|
private fun updateBypassEnabled() {
|
||||||
val bypassEnabled = bypassController.bypassEnabled
|
val bypassEnabled = bypassController.bypassEnabled
|
||||||
smartspaceViews.forEach { it.setKeyguardBypassEnabled(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.
|
* Constructs the smartspace view and connects it to the smartspace service.
|
||||||
*/
|
*/
|
||||||
@@ -224,17 +259,17 @@ constructor(
|
|||||||
throw RuntimeException("Cannot build view when not enabled")
|
throw RuntimeException("Cannot build view when not enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
val view = buildView(parent)
|
val view = buildView(parent, plugin, configPlugin)
|
||||||
connectSession()
|
connectSession()
|
||||||
|
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestSmartspaceUpdate() {
|
private fun buildView(
|
||||||
session?.requestSmartspaceUpdate()
|
parent: ViewGroup,
|
||||||
}
|
plugin: BcSmartspaceDataPlugin?,
|
||||||
|
configPlugin: BcSmartspaceConfigPlugin? = null
|
||||||
private fun buildView(parent: ViewGroup): View? {
|
): View? {
|
||||||
if (plugin == null) {
|
if (plugin == null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -242,7 +277,7 @@ constructor(
|
|||||||
val ssView = plugin.getView(parent)
|
val ssView = plugin.getView(parent)
|
||||||
ssView.setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
|
ssView.setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
|
||||||
ssView.registerDataProvider(plugin)
|
ssView.registerDataProvider(plugin)
|
||||||
ssView.registerConfigProvider(configPlugin)
|
configPlugin?.let { ssView.registerConfigProvider(it) }
|
||||||
|
|
||||||
ssView.setIntentStarter(object : BcSmartspaceDataPlugin.IntentStarter {
|
ssView.setIntentStarter(object : BcSmartspaceDataPlugin.IntentStarter {
|
||||||
override fun startIntent(view: View, intent: Intent, showOnLockscreen: Boolean) {
|
override fun startIntent(view: View, intent: Intent, showOnLockscreen: Boolean) {
|
||||||
@@ -273,7 +308,8 @@ constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun connectSession() {
|
private fun connectSession() {
|
||||||
if (plugin == null || session != null || smartspaceViews.isEmpty()) {
|
if (weatherPlugin == null && plugin == null) return
|
||||||
|
if (session != null || smartspaceViews.isEmpty()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,14 +346,20 @@ constructor(
|
|||||||
statusBarStateController.addCallback(statusBarStateListener)
|
statusBarStateController.addCallback(statusBarStateListener)
|
||||||
bypassController.registerOnBypassStateChangedListener(bypassStateChangedListener)
|
bypassController.registerOnBypassStateChangedListener(bypassStateChangedListener)
|
||||||
|
|
||||||
plugin.registerSmartspaceEventNotifier {
|
weatherPlugin?.registerSmartspaceEventNotifier { e -> session?.notifySmartspaceEvent(e) }
|
||||||
e -> session?.notifySmartspaceEvent(e)
|
plugin?.registerSmartspaceEventNotifier { e -> session?.notifySmartspaceEvent(e) }
|
||||||
}
|
|
||||||
|
|
||||||
updateBypassEnabled()
|
updateBypassEnabled()
|
||||||
reloadSmartspace()
|
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.
|
* Disconnects the smartspace view from the smartspace service and cleans up any resources.
|
||||||
*/
|
*/
|
||||||
@@ -341,9 +383,13 @@ constructor(
|
|||||||
bypassController.unregisterOnBypassStateChangedListener(bypassStateChangedListener)
|
bypassController.unregisterOnBypassStateChangedListener(bypassStateChangedListener)
|
||||||
session = null
|
session = null
|
||||||
|
|
||||||
|
weatherPlugin?.registerSmartspaceEventNotifier(null)
|
||||||
|
weatherPlugin?.onTargetsAvailable(emptyList())
|
||||||
|
|
||||||
plugin?.registerSmartspaceEventNotifier(null)
|
plugin?.registerSmartspaceEventNotifier(null)
|
||||||
plugin?.onTargetsAvailable(emptyList())
|
plugin?.onTargetsAvailable(emptyList())
|
||||||
Log.d(TAG, "Ending smartspace session for lockscreen")
|
|
||||||
|
Log.d(TAG, "Ended smartspace session for lockscreen")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addListener(listener: SmartspaceTargetListener) {
|
fun addListener(listener: SmartspaceTargetListener) {
|
||||||
@@ -357,8 +403,11 @@ constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun filterSmartspaceTarget(t: SmartspaceTarget): Boolean {
|
private fun filterSmartspaceTarget(t: SmartspaceTarget): Boolean {
|
||||||
|
if (isDateWeatherDecoupled()) {
|
||||||
|
return t.featureType != SmartspaceTarget.FEATURE_WEATHER
|
||||||
|
}
|
||||||
if (!showNotifications) {
|
if (!showNotifications) {
|
||||||
return t.getFeatureType() == SmartspaceTarget.FEATURE_WEATHER
|
return t.featureType == SmartspaceTarget.FEATURE_WEATHER
|
||||||
}
|
}
|
||||||
return when (t.userHandle) {
|
return when (t.userHandle) {
|
||||||
userTracker.userHandle -> {
|
userTracker.userHandle -> {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import android.widget.FrameLayout
|
|||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.flags.FeatureFlags
|
import com.android.systemui.flags.FeatureFlags
|
||||||
|
import com.android.systemui.flags.Flags
|
||||||
import com.android.systemui.plugins.ActivityStarter
|
import com.android.systemui.plugins.ActivityStarter
|
||||||
import com.android.systemui.plugins.BcSmartspaceConfigPlugin
|
import com.android.systemui.plugins.BcSmartspaceConfigPlugin
|
||||||
import com.android.systemui.plugins.BcSmartspaceDataPlugin
|
import com.android.systemui.plugins.BcSmartspaceDataPlugin
|
||||||
@@ -111,6 +112,9 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
@Mock
|
@Mock
|
||||||
private lateinit var handler: Handler
|
private lateinit var handler: Handler
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private lateinit var weatherPlugin: BcSmartspaceDataPlugin
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private lateinit var plugin: BcSmartspaceDataPlugin
|
private lateinit var plugin: BcSmartspaceDataPlugin
|
||||||
|
|
||||||
@@ -151,6 +155,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
KeyguardBypassController.OnBypassStateChangedListener
|
KeyguardBypassController.OnBypassStateChangedListener
|
||||||
private lateinit var deviceProvisionedListener: DeviceProvisionedListener
|
private lateinit var deviceProvisionedListener: DeviceProvisionedListener
|
||||||
|
|
||||||
|
private lateinit var weatherSmartspaceView: SmartspaceView
|
||||||
private lateinit var smartspaceView: SmartspaceView
|
private lateinit var smartspaceView: SmartspaceView
|
||||||
|
|
||||||
private val clock = FakeSystemClock()
|
private val clock = FakeSystemClock()
|
||||||
@@ -176,16 +181,22 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
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))
|
`when`(secureSettings.getUriFor(PRIVATE_LOCKSCREEN_SETTING))
|
||||||
.thenReturn(fakePrivateLockscreenSettingUri)
|
.thenReturn(fakePrivateLockscreenSettingUri)
|
||||||
`when`(secureSettings.getUriFor(NOTIF_ON_LOCKSCREEN_SETTING))
|
`when`(secureSettings.getUriFor(NOTIF_ON_LOCKSCREEN_SETTING))
|
||||||
.thenReturn(fakeNotifOnLockscreenSettingUri)
|
.thenReturn(fakeNotifOnLockscreenSettingUri)
|
||||||
`when`(smartspaceManager.createSmartspaceSession(any())).thenReturn(smartspaceSession)
|
`when`(smartspaceManager.createSmartspaceSession(any())).thenReturn(smartspaceSession)
|
||||||
|
`when`(weatherPlugin.getView(any())).thenReturn(
|
||||||
|
createWeatherSmartspaceView(), createWeatherSmartspaceView())
|
||||||
`when`(plugin.getView(any())).thenReturn(createSmartspaceView(), createSmartspaceView())
|
`when`(plugin.getView(any())).thenReturn(createSmartspaceView(), createSmartspaceView())
|
||||||
`when`(userTracker.userProfiles).thenReturn(userList)
|
`when`(userTracker.userProfiles).thenReturn(userList)
|
||||||
`when`(statusBarStateController.dozeAmount).thenReturn(0.5f)
|
`when`(statusBarStateController.dozeAmount).thenReturn(0.5f)
|
||||||
`when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true)
|
`when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
|
||||||
`when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(true)
|
`when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
|
||||||
|
|
||||||
setActiveUser(userHandlePrimary)
|
setActiveUser(userHandlePrimary)
|
||||||
setAllowPrivateNotifications(userHandlePrimary, true)
|
setAllowPrivateNotifications(userHandlePrimary, true)
|
||||||
@@ -210,6 +221,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
executor,
|
executor,
|
||||||
bgExecutor,
|
bgExecutor,
|
||||||
handler,
|
handler,
|
||||||
|
Optional.of(weatherPlugin),
|
||||||
Optional.of(plugin),
|
Optional.of(plugin),
|
||||||
Optional.of(configPlugin),
|
Optional.of(configPlugin),
|
||||||
)
|
)
|
||||||
@@ -218,11 +230,22 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
deviceProvisionedListener = deviceProvisionedCaptor.value
|
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
|
@Test
|
||||||
fun connectOnlyAfterDeviceIsProvisioned() {
|
fun testBuildAndConnectView_connectsOnlyAfterDeviceIsProvisioned() {
|
||||||
// GIVEN an unprovisioned device and an attempt to connect
|
// GIVEN an unprovisioned device and an attempt to connect
|
||||||
`when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(false)
|
`when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(false)
|
||||||
`when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(false)
|
`when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
|
||||||
|
|
||||||
// WHEN a connection attempt is made and view is attached
|
// WHEN a connection attempt is made and view is attached
|
||||||
val view = controller.buildAndConnectView(fakeParent)
|
val view = controller.buildAndConnectView(fakeParent)
|
||||||
@@ -232,8 +255,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
verify(smartspaceManager, never()).createSmartspaceSession(any())
|
verify(smartspaceManager, never()).createSmartspaceSession(any())
|
||||||
|
|
||||||
// WHEN it does become provisioned
|
// WHEN it does become provisioned
|
||||||
`when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true)
|
`when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
|
||||||
`when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(true)
|
`when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
|
||||||
deviceProvisionedListener.onUserSetupChanged()
|
deviceProvisionedListener.onUserSetupChanged()
|
||||||
|
|
||||||
// THEN the session is created
|
// THEN the session is created
|
||||||
@@ -243,7 +266,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testListenersAreRegistered() {
|
fun testAddListener_registersListenersForPlugin() {
|
||||||
// GIVEN a listener is added after a session is created
|
// GIVEN a listener is added after a session is created
|
||||||
connectSession()
|
connectSession()
|
||||||
|
|
||||||
@@ -252,10 +275,12 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
|
|
||||||
// THEN the listener is registered to the underlying plugin
|
// THEN the listener is registered to the underlying plugin
|
||||||
verify(plugin).registerListener(controllerListener)
|
verify(plugin).registerListener(controllerListener)
|
||||||
|
// The listener is registered only for the plugin, not the weather plugin.
|
||||||
|
verify(weatherPlugin, never()).registerListener(any())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testEarlyRegisteredListenersAreAttachedAfterConnected() {
|
fun testAddListener_earlyRegisteredListenersAreAttachedAfterConnected() {
|
||||||
// GIVEN a listener that is registered before the session is created
|
// GIVEN a listener that is registered before the session is created
|
||||||
controller.addListener(controllerListener)
|
controller.addListener(controllerListener)
|
||||||
|
|
||||||
@@ -264,10 +289,12 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
|
|
||||||
// THEN the listener is subsequently registered
|
// THEN the listener is subsequently registered
|
||||||
verify(plugin).registerListener(controllerListener)
|
verify(plugin).registerListener(controllerListener)
|
||||||
|
// The listener is registered only for the plugin, not the weather plugin.
|
||||||
|
verify(weatherPlugin, never()).registerListener(any())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testEmptyListIsEmittedAndNotifierRemovedAfterDisconnect() {
|
fun testDisconnect_emitsEmptyListAndRemovesNotifier() {
|
||||||
// GIVEN a registered listener on an active session
|
// GIVEN a registered listener on an active session
|
||||||
connectSession()
|
connectSession()
|
||||||
clearInvocations(plugin)
|
clearInvocations(plugin)
|
||||||
@@ -279,10 +306,12 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
// THEN the listener receives an empty list of targets and unregisters the notifier
|
// THEN the listener receives an empty list of targets and unregisters the notifier
|
||||||
verify(plugin).onTargetsAvailable(emptyList())
|
verify(plugin).onTargetsAvailable(emptyList())
|
||||||
verify(plugin).registerSmartspaceEventNotifier(null)
|
verify(plugin).registerSmartspaceEventNotifier(null)
|
||||||
|
verify(weatherPlugin).onTargetsAvailable(emptyList())
|
||||||
|
verify(weatherPlugin).registerSmartspaceEventNotifier(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testUserChangeReloadsSmartspace() {
|
fun testUserChange_reloadsSmartspace() {
|
||||||
// GIVEN a connected smartspace session
|
// GIVEN a connected smartspace session
|
||||||
connectSession()
|
connectSession()
|
||||||
|
|
||||||
@@ -294,7 +323,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSettingsChangeReloadsSmartspace() {
|
fun testSettingsChange_reloadsSmartspace() {
|
||||||
// GIVEN a connected smartspace session
|
// GIVEN a connected smartspace session
|
||||||
connectSession()
|
connectSession()
|
||||||
|
|
||||||
@@ -306,7 +335,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testThemeChangeUpdatesTextColor() {
|
fun testThemeChange_updatesTextColor() {
|
||||||
// GIVEN a connected smartspace session
|
// GIVEN a connected smartspace session
|
||||||
connectSession()
|
connectSession()
|
||||||
|
|
||||||
@@ -318,7 +347,22 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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
|
// GIVEN a connected smartspace session
|
||||||
connectSession()
|
connectSession()
|
||||||
|
|
||||||
@@ -330,7 +374,22 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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
|
// GIVEN a connected smartspace session
|
||||||
connectSession()
|
connectSession()
|
||||||
`when`(keyguardBypassController.bypassEnabled).thenReturn(true)
|
`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
|
@Test
|
||||||
fun testSettingsAreReloaded() {
|
fun testSettingsAreReloaded() {
|
||||||
// GIVEN a connected session where the privacy settings later flip to false
|
// GIVEN a connected session where the privacy settings later flip to false
|
||||||
@@ -514,6 +594,16 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
verify(smartspaceView2).registerConfigProvider(configPlugin)
|
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
|
@Test
|
||||||
fun testViewGetInitializedWithBypassEnabledState() {
|
fun testViewGetInitializedWithBypassEnabledState() {
|
||||||
// GIVEN keyguard bypass is enabled.
|
// GIVEN keyguard bypass is enabled.
|
||||||
@@ -531,8 +621,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
fun testConnectAttemptBeforeInitializationShouldNotCreateSession() {
|
fun testConnectAttemptBeforeInitializationShouldNotCreateSession() {
|
||||||
// GIVEN an uninitalized smartspaceView
|
// GIVEN an uninitalized smartspaceView
|
||||||
// WHEN the device is provisioned
|
// WHEN the device is provisioned
|
||||||
`when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true)
|
`when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
|
||||||
`when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(true)
|
`when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
|
||||||
deviceProvisionedListener.onDeviceProvisionedChanged()
|
deviceProvisionedListener.onDeviceProvisionedChanged()
|
||||||
|
|
||||||
// THEN no calls to createSmartspaceSession should occur
|
// THEN no calls to createSmartspaceSession should occur
|
||||||
@@ -542,9 +632,23 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun connectSession() {
|
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)
|
val view = controller.buildAndConnectView(fakeParent)
|
||||||
smartspaceView = view as SmartspaceView
|
smartspaceView = view as SmartspaceView
|
||||||
|
fakeParent.addView(view)
|
||||||
controller.stateChangeListener.onViewAttachedToWindow(view)
|
controller.stateChangeListener.onViewAttachedToWindow(view)
|
||||||
|
|
||||||
verify(smartspaceView).setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
|
verify(smartspaceView).setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
|
||||||
@@ -554,6 +658,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
.addOnTargetsAvailableListener(any(), capture(sessionListenerCaptor))
|
.addOnTargetsAvailableListener(any(), capture(sessionListenerCaptor))
|
||||||
sessionListener = sessionListenerCaptor.value
|
sessionListener = sessionListenerCaptor.value
|
||||||
|
|
||||||
|
verify(smartspaceManager).createSmartspaceSession(any())
|
||||||
|
|
||||||
verify(userTracker).addCallback(capture(userTrackerCaptor), any())
|
verify(userTracker).addCallback(capture(userTrackerCaptor), any())
|
||||||
userListener = userTrackerCaptor.value
|
userListener = userTrackerCaptor.value
|
||||||
|
|
||||||
@@ -578,9 +684,11 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
|
|
||||||
verify(smartspaceView).setPrimaryTextColor(anyInt())
|
verify(smartspaceView).setPrimaryTextColor(anyInt())
|
||||||
verify(smartspaceView).setDozeAmount(0.5f)
|
verify(smartspaceView).setDozeAmount(0.5f)
|
||||||
clearInvocations(view)
|
|
||||||
|
|
||||||
fakeParent.addView(view)
|
if (controller.isDateWeatherDecoupled()) {
|
||||||
|
clearInvocations(weatherSmartspaceView)
|
||||||
|
}
|
||||||
|
clearInvocations(smartspaceView)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setActiveUser(userHandle: UserHandle) {
|
private fun setActiveUser(userHandle: UserHandle) {
|
||||||
@@ -626,6 +734,31 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
|
|||||||
).thenReturn(if (value) 1 else 0)
|
).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 {
|
private fun createSmartspaceView(): SmartspaceView {
|
||||||
return spy(object : View(context), SmartspaceView {
|
return spy(object : View(context), SmartspaceView {
|
||||||
override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) {
|
override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) {
|
||||||
|
|||||||
Reference in New Issue
Block a user