summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt2
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/Weather.kt85
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt107
-rw-r--r--packages/SystemUI/src/com/android/keyguard/ClockEventController.kt8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt231
8 files changed, 361 insertions, 109 deletions
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index 1c2f38beb867..ab4aca569bd4 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -113,7 +113,7 @@ interface ClockEvents {
fun onColorPaletteChanged(resources: Resources) {}
/** Call whenever the weather data should update */
- fun onWeatherDataChanged(data: Weather) {}
+ fun onWeatherDataChanged(data: WeatherData) {}
}
/** Methods which trigger various clock animations */
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/Weather.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/Weather.kt
deleted file mode 100644
index 302f17556bc7..000000000000
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/Weather.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.android.systemui.plugins
-
-import android.os.Bundle
-
-class Weather(val conditions: WeatherStateIcon, val temperature: Int, val isCelsius: Boolean) {
- companion object {
- private const val TAG = "Weather"
- private const val WEATHER_STATE_ICON_KEY = "weather_state_icon_extra_key"
- private const val TEMPERATURE_VALUE_KEY = "temperature_value_extra_key"
- private const val TEMPERATURE_UNIT_KEY = "temperature_unit_extra_key"
- private const val INVALID_TEMPERATURE = Int.MIN_VALUE
-
- fun fromBundle(extras: Bundle): Weather? {
- val icon =
- WeatherStateIcon.fromInt(
- extras.getInt(WEATHER_STATE_ICON_KEY, WeatherStateIcon.UNKNOWN_ICON.id)
- )
- if (icon == null || icon == WeatherStateIcon.UNKNOWN_ICON) {
- return null
- }
- val temperature = extras.getInt(TEMPERATURE_VALUE_KEY, INVALID_TEMPERATURE)
- if (temperature == INVALID_TEMPERATURE) {
- return null
- }
- return Weather(icon, temperature, extras.getBoolean(TEMPERATURE_UNIT_KEY))
- }
- }
-
- enum class WeatherStateIcon(val id: Int) {
- UNKNOWN_ICON(0),
-
- // Clear, day & night.
- SUNNY(1),
- CLEAR_NIGHT(2),
-
- // Mostly clear, day & night.
- MOSTLY_SUNNY(3),
- MOSTLY_CLEAR_NIGHT(4),
-
- // Partly cloudy, day & night.
- PARTLY_CLOUDY(5),
- PARTLY_CLOUDY_NIGHT(6),
-
- // Mostly cloudy, day & night.
- MOSTLY_CLOUDY_DAY(7),
- MOSTLY_CLOUDY_NIGHT(8),
- CLOUDY(9),
- HAZE_FOG_DUST_SMOKE(10),
- DRIZZLE(11),
- HEAVY_RAIN(12),
- SHOWERS_RAIN(13),
-
- // Scattered showers, day & night.
- SCATTERED_SHOWERS_DAY(14),
- SCATTERED_SHOWERS_NIGHT(15),
-
- // Isolated scattered thunderstorms, day & night.
- ISOLATED_SCATTERED_TSTORMS_DAY(16),
- ISOLATED_SCATTERED_TSTORMS_NIGHT(17),
- STRONG_TSTORMS(18),
- BLIZZARD(19),
- BLOWING_SNOW(20),
- FLURRIES(21),
- HEAVY_SNOW(22),
-
- // Scattered snow showers, day & night.
- SCATTERED_SNOW_SHOWERS_DAY(23),
- SCATTERED_SNOW_SHOWERS_NIGHT(24),
- SNOW_SHOWERS_SNOW(25),
- MIXED_RAIN_HAIL_RAIN_SLEET(26),
- SLEET_HAIL(27),
- TORNADO(28),
- TROPICAL_STORM_HURRICANE(29),
- WINDY_BREEZY(30),
- WINTRY_MIX_RAIN_SNOW(31);
-
- companion object {
- fun fromInt(value: Int) = values().firstOrNull { it.id == value }
- }
- }
-
- override fun toString(): String {
- return "$conditions $temperature${if (isCelsius) "C" else "F"}"
- }
-}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt
new file mode 100644
index 000000000000..52dfc55c105d
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt
@@ -0,0 +1,107 @@
+package com.android.systemui.plugins
+
+import android.os.Bundle
+import androidx.annotation.VisibleForTesting
+
+class WeatherData
+private constructor(
+ val description: String,
+ val state: WeatherStateIcon,
+ val useCelsius: Boolean,
+ val temperature: Int,
+) {
+ companion object {
+ private const val TAG = "WeatherData"
+ @VisibleForTesting const val DESCRIPTION_KEY = "description"
+ @VisibleForTesting const val STATE_KEY = "state"
+ @VisibleForTesting const val USE_CELSIUS_KEY = "use_celsius"
+ @VisibleForTesting const val TEMPERATURE_KEY = "temperature"
+ private const val INVALID_WEATHER_ICON_STATE = -1
+
+ fun fromBundle(extras: Bundle): WeatherData? {
+ val description = extras.getString(DESCRIPTION_KEY)
+ val state =
+ WeatherStateIcon.fromInt(extras.getInt(STATE_KEY, INVALID_WEATHER_ICON_STATE))
+ val temperature = readIntFromBundle(extras, TEMPERATURE_KEY)
+ return if (
+ description == null ||
+ state == null ||
+ !extras.containsKey(USE_CELSIUS_KEY) ||
+ temperature == null
+ )
+ null
+ else
+ WeatherData(
+ description = description,
+ state = state,
+ useCelsius = extras.getBoolean(USE_CELSIUS_KEY),
+ temperature = temperature
+ )
+ }
+
+ private fun readIntFromBundle(extras: Bundle, key: String): Int? =
+ try {
+ extras.getString(key).toInt()
+ } catch (e: Exception) {
+ null
+ }
+ }
+
+ enum class WeatherStateIcon(val id: Int) {
+ UNKNOWN_ICON(0),
+
+ // Clear, day & night.
+ SUNNY(1),
+ CLEAR_NIGHT(2),
+
+ // Mostly clear, day & night.
+ MOSTLY_SUNNY(3),
+ MOSTLY_CLEAR_NIGHT(4),
+
+ // Partly cloudy, day & night.
+ PARTLY_CLOUDY(5),
+ PARTLY_CLOUDY_NIGHT(6),
+
+ // Mostly cloudy, day & night.
+ MOSTLY_CLOUDY_DAY(7),
+ MOSTLY_CLOUDY_NIGHT(8),
+ CLOUDY(9),
+ HAZE_FOG_DUST_SMOKE(10),
+ DRIZZLE(11),
+ HEAVY_RAIN(12),
+ SHOWERS_RAIN(13),
+
+ // Scattered showers, day & night.
+ SCATTERED_SHOWERS_DAY(14),
+ SCATTERED_SHOWERS_NIGHT(15),
+
+ // Isolated scattered thunderstorms, day & night.
+ ISOLATED_SCATTERED_TSTORMS_DAY(16),
+ ISOLATED_SCATTERED_TSTORMS_NIGHT(17),
+ STRONG_TSTORMS(18),
+ BLIZZARD(19),
+ BLOWING_SNOW(20),
+ FLURRIES(21),
+ HEAVY_SNOW(22),
+
+ // Scattered snow showers, day & night.
+ SCATTERED_SNOW_SHOWERS_DAY(23),
+ SCATTERED_SNOW_SHOWERS_NIGHT(24),
+ SNOW_SHOWERS_SNOW(25),
+ MIXED_RAIN_HAIL_RAIN_SLEET(26),
+ SLEET_HAIL(27),
+ TORNADO(28),
+ TROPICAL_STORM_HURRICANE(29),
+ WINDY_BREEZY(30),
+ WINTRY_MIX_RAIN_SNOW(31);
+
+ companion object {
+ fun fromInt(value: Int) = values().firstOrNull { it.id == value }
+ }
+ }
+
+ override fun toString(): String {
+ val unit = if (useCelsius) "C" else "F"
+ return "$state (\"$description\") $temperature°$unit"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 1254e1ee3311..92ee37310130 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -48,7 +48,7 @@ import com.android.systemui.plugins.ClockTickRate
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel.DEBUG
import com.android.systemui.shared.regionsampling.RegionSampler
-import com.android.systemui.plugins.Weather
+import com.android.systemui.plugins.WeatherData
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -291,10 +291,8 @@ constructor(
clock?.events?.onTimeFormatChanged(DateFormat.is24HourFormat(context))
}
- override fun onWeatherDataChanged(data: Weather?) {
- if (data != null) {
- clock?.events?.onWeatherDataChanged(data)
- }
+ override fun onWeatherDataChanged(data: WeatherData) {
+ clock?.events?.onWeatherDataChanged(data)
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index be9264dbfcf3..d1bd486a4ede 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -148,7 +148,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.dump.DumpsysTableLogger;
import com.android.systemui.log.SessionTracker;
-import com.android.systemui.plugins.Weather;
+import com.android.systemui.plugins.WeatherData;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.TaskStackChangeListener;
@@ -3285,12 +3285,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
/**
* @param data the weather data (temp, conditions, unit) for weather clock to use
*/
- public void sendWeatherData(Weather data) {
+ public void sendWeatherData(WeatherData data) {
mHandler.post(()-> {
handleWeatherDataUpdate(data); });
}
- private void handleWeatherDataUpdate(Weather data) {
+ private void handleWeatherDataUpdate(WeatherData data) {
Assert.isMainThread();
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 0da799e0964d..38f3e5065eec 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -23,7 +23,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.settingslib.fuelgauge.BatteryStatus;
-import com.android.systemui.plugins.Weather;
+import com.android.systemui.plugins.WeatherData;
import com.android.systemui.statusbar.KeyguardIndicationController;
import java.util.TimeZone;
@@ -61,7 +61,7 @@ public class KeyguardUpdateMonitorCallback {
/**
* Called when receive new weather data.
*/
- public void onWeatherDataChanged(Weather data) { }
+ public void onWeatherDataChanged(WeatherData data) { }
/**
* Called when the carrier PLMN or SPN changes.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 6ef6165bcbb3..29510d00a8d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -52,18 +52,19 @@ import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.WeatherData
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.DATE_SMARTSPACE_DATA_PLUGIN
import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.WEATHER_SMARTSPACE_DATA_PLUGIN
-import com.android.systemui.plugins.Weather
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.util.concurrency.Execution
import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.time.SystemClock
import java.io.PrintWriter
import java.time.Instant
import java.util.Optional
@@ -81,6 +82,7 @@ constructor(
private val smartspaceManager: SmartspaceManager,
private val activityStarter: ActivityStarter,
private val falsingManager: FalsingManager,
+ private val systemClock: SystemClock,
private val secureSettings: SecureSettings,
private val userTracker: UserTracker,
private val contentResolver: ContentResolver,
@@ -152,6 +154,18 @@ constructor(
// The weather data plugin takes unfiltered targets and performs the filtering internally.
weatherPlugin?.onTargetsAvailable(targets)
+ val now = Instant.ofEpochMilli(systemClock.currentTimeMillis())
+ val weatherTarget = targets.find { t ->
+ t.featureType == SmartspaceTarget.FEATURE_WEATHER &&
+ now.isAfter(Instant.ofEpochMilli(t.creationTimeMillis)) &&
+ now.isBefore(Instant.ofEpochMilli(t.expiryTimeMillis))
+ }
+ if (weatherTarget != null) {
+ val weatherData = WeatherData.fromBundle(weatherTarget.baseAction.extras)
+ if (weatherData != null) {
+ keyguardUpdateMonitor.sendWeatherData(weatherData)
+ }
+ }
val filteredTargets = targets.filter(::filterSmartspaceTarget)
plugin?.onTargetsAvailable(filteredTargets)
@@ -173,17 +187,6 @@ constructor(
}
isContentUpdatedOnce = true
}
-
- val now = Instant.now()
- val weatherTarget = targets.find { t ->
- t.featureType == SmartspaceTarget.FEATURE_WEATHER &&
- now.isAfter(Instant.ofEpochMilli(t.creationTimeMillis)) &&
- now.isBefore(Instant.ofEpochMilli(t.expiryTimeMillis))
- }
- if (weatherTarget != null) {
- val weatherData = Weather.fromBundle(weatherTarget.baseAction.extras)
- keyguardUpdateMonitor.sendWeatherData(weatherData)
- }
}
private val userTrackerCallback = object : UserTracker.Callback {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index d6225c6748f3..8fa0d652705a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.lockscreen
+import android.app.smartspace.SmartspaceAction
import android.app.smartspace.SmartspaceManager
import android.app.smartspace.SmartspaceSession
import android.app.smartspace.SmartspaceSession.OnTargetsAvailableListener
@@ -26,6 +27,7 @@ import android.content.pm.UserInfo
import android.database.ContentObserver
import android.graphics.drawable.Drawable
import android.net.Uri
+import android.os.Bundle
import android.os.Handler
import android.os.UserHandle
import android.provider.Settings
@@ -43,6 +45,7 @@ import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.WeatherData
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener
import com.android.systemui.settings.UserTracker
@@ -54,6 +57,7 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceP
import com.android.systemui.util.concurrency.FakeExecution
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argThat
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.settings.SecureSettings
@@ -69,6 +73,7 @@ import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import java.util.Optional
@@ -76,6 +81,13 @@ import java.util.concurrent.Executor
@SmallTest
class LockscreenSmartspaceControllerTest : SysuiTestCase() {
+ companion object {
+ const val SMARTSPACE_TIME_TOO_EARLY = 1000L
+ const val SMARTSPACE_TIME_JUST_RIGHT = 4000L
+ const val SMARTSPACE_TIME_TOO_LATE = 9000L
+ const val SMARTSPACE_CREATION_TIME = 1234L
+ const val SMARTSPACE_EXPIRY_TIME = 5678L
+ }
@Mock
private lateinit var featureFlags: FeatureFlags
@Mock
@@ -224,6 +236,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
smartspaceManager,
activityStarter,
falsingManager,
+ clock,
secureSettings,
userTracker,
contentResolver,
@@ -529,6 +542,190 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
}
@Test
+ fun testSessionListener_ifWeatherExtraMissing_thenWeatherDataNotSent() {
+ connectSession()
+ clock.setCurrentTimeMillis(SMARTSPACE_TIME_JUST_RIGHT)
+ // WHEN we receive a list of targets
+ val targets = listOf(
+ makeTarget(1, userHandlePrimary, isSensitive = true),
+ makeTarget(2, userHandlePrimary, featureType = SmartspaceTarget.FEATURE_WEATHER)
+
+ )
+ sessionListener.onTargetsAvailable(targets)
+ verify(keyguardUpdateMonitor, times(0)).sendWeatherData(any())
+ }
+
+ @Test
+ fun testSessionListener_ifWeatherExtraIsMissingValues_thenWeatherDataNotSent() {
+ connectSession()
+
+ clock.setCurrentTimeMillis(SMARTSPACE_TIME_JUST_RIGHT)
+ // WHEN we receive a list of targets
+ val targets = listOf(
+ makeTarget(1, userHandlePrimary, isSensitive = true),
+ makeWeatherTargetWithExtras(
+ id = 2,
+ userHandle = userHandlePrimary,
+ description = null,
+ state = WeatherData.WeatherStateIcon.SUNNY.id,
+ temperature = "32",
+ useCelsius = null)
+
+ )
+
+ sessionListener.onTargetsAvailable(targets)
+
+ verify(keyguardUpdateMonitor, times(0)).sendWeatherData(any())
+ }
+
+ @Test
+ fun testSessionListener_ifTooEarly_thenWeatherDataNotSent() {
+ connectSession()
+
+ clock.setCurrentTimeMillis(SMARTSPACE_TIME_TOO_EARLY)
+ // WHEN we receive a list of targets
+ val targets = listOf(
+ makeWeatherTargetWithExtras(
+ id = 1,
+ userHandle = userHandleManaged,
+ description = "Sunny",
+ state = WeatherData.WeatherStateIcon.SUNNY.id,
+ temperature = "32",
+ useCelsius = false)
+ )
+ sessionListener.onTargetsAvailable(targets)
+ verify(keyguardUpdateMonitor, times(0)).sendWeatherData(any())
+ }
+
+ @Test
+ fun testSessionListener_ifOnTime_thenWeatherDataSent() {
+ connectSession()
+
+ clock.setCurrentTimeMillis(SMARTSPACE_TIME_JUST_RIGHT)
+ // WHEN we receive a list of targets
+ val targets = listOf(
+ makeWeatherTargetWithExtras(
+ id = 1,
+ userHandle = userHandleManaged,
+ description = "Snow Showers",
+ state = WeatherData.WeatherStateIcon.SNOW_SHOWERS_SNOW.id,
+ temperature = "-1",
+ useCelsius = false)
+ )
+ sessionListener.onTargetsAvailable(targets)
+ verify(keyguardUpdateMonitor).sendWeatherData(argThat { w ->
+ w.description == "Snow Showers" &&
+ w.state == WeatherData.WeatherStateIcon.SNOW_SHOWERS_SNOW &&
+ w.temperature == -1 && !w.useCelsius
+ })
+ }
+
+ @Test
+ fun testSessionListener_ifTooLate_thenWeatherDataNotSent() {
+ connectSession()
+
+ clock.setCurrentTimeMillis(SMARTSPACE_TIME_TOO_LATE)
+ // WHEN we receive a list of targets
+ val targets = listOf(
+ makeWeatherTargetWithExtras(
+ id = 1,
+ userHandle = userHandleManaged,
+ description = "Sunny",
+ state = WeatherData.WeatherStateIcon.SUNNY.id,
+ temperature = "72",
+ useCelsius = false)
+ )
+ sessionListener.onTargetsAvailable(targets)
+ verify(keyguardUpdateMonitor, times(0)).sendWeatherData(any())
+ }
+
+ @Test
+ fun testSessionListener_onlyFirstWeatherDataSent() {
+ connectSession()
+
+ clock.setCurrentTimeMillis(SMARTSPACE_TIME_JUST_RIGHT)
+ // WHEN we receive a list of targets
+ val targets = listOf(
+ makeWeatherTargetWithExtras(
+ id = 1,
+ userHandle = userHandleManaged,
+ description = "Sunny",
+ state = WeatherData.WeatherStateIcon.SUNNY.id,
+ temperature = "72",
+ useCelsius = false),
+ makeWeatherTargetWithExtras(
+ id = 2,
+ userHandle = userHandleManaged,
+ description = "Showers",
+ state = WeatherData.WeatherStateIcon.SHOWERS_RAIN.id,
+ temperature = "62",
+ useCelsius = true)
+ )
+ sessionListener.onTargetsAvailable(targets)
+ verify(keyguardUpdateMonitor).sendWeatherData(argThat { w ->
+ w.description == "Sunny" &&
+ w.state == WeatherData.WeatherStateIcon.SUNNY &&
+ w.temperature == 72 && !w.useCelsius
+ })
+ }
+
+ @Test
+ fun testSessionListener_ifDecouplingEnabled_weatherDataUpdates() {
+ `when`(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(true)
+ connectSession()
+
+ clock.setCurrentTimeMillis(SMARTSPACE_TIME_JUST_RIGHT)
+ // WHEN we receive a list of targets
+ val targets = listOf(
+ makeTarget(1, userHandlePrimary, isSensitive = true),
+ makeTarget(2, userHandlePrimary),
+ makeTarget(3, userHandleManaged),
+ makeWeatherTargetWithExtras(
+ id = 4,
+ userHandle = userHandlePrimary,
+ description = "Flurries",
+ state = WeatherData.WeatherStateIcon.FLURRIES.id,
+ temperature = "0",
+ useCelsius = true)
+ )
+
+ sessionListener.onTargetsAvailable(targets)
+
+ verify(keyguardUpdateMonitor).sendWeatherData(argThat { w ->
+ w.description == "Flurries" &&
+ w.state == WeatherData.WeatherStateIcon.FLURRIES &&
+ w.temperature == 0 && w.useCelsius
+ })
+ }
+
+ @Test
+ fun testSessionListener_ifDecouplingDisabled_weatherDataUpdates() {
+ `when`(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(false)
+ connectSession()
+
+ clock.setCurrentTimeMillis(SMARTSPACE_TIME_JUST_RIGHT)
+ // WHEN we receive a list of targets
+ val targets = listOf(
+ makeWeatherTargetWithExtras(
+ id = 1,
+ userHandle = userHandlePrimary,
+ description = "Sunny",
+ state = WeatherData.WeatherStateIcon.SUNNY.id,
+ temperature = "32",
+ useCelsius = false),
+ makeTarget(2, userHandlePrimary, isSensitive = true)
+ )
+
+ sessionListener.onTargetsAvailable(targets)
+
+ verify(keyguardUpdateMonitor).sendWeatherData(argThat { w ->
+ w.description == "Sunny" &&
+ w.state == WeatherData.WeatherStateIcon.SUNNY &&
+ w.temperature == 32 && !w.useCelsius
+ })
+ }
+
+ @Test
fun testSettingsAreReloaded() {
// GIVEN a connected session where the privacy settings later flip to false
connectSession()
@@ -740,7 +937,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
return userInfo
}
- fun makeTarget(
+ private fun makeTarget(
id: Int,
userHandle: UserHandle,
isSensitive: Boolean = false,
@@ -755,6 +952,38 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
.build()
}
+ private fun makeWeatherTargetWithExtras(
+ id: Int,
+ userHandle: UserHandle,
+ description: String?,
+ state: Int?,
+ temperature: String?,
+ useCelsius: Boolean?
+ ): SmartspaceTarget {
+ val mockWeatherBundle = mock(Bundle::class.java).apply {
+ `when`(getString(WeatherData.DESCRIPTION_KEY)).thenReturn(description)
+ if (state != null)
+ `when`(getInt(eq(WeatherData.STATE_KEY), any())).thenReturn(state)
+ `when`(getString(WeatherData.TEMPERATURE_KEY)).thenReturn(temperature)
+ `when`(containsKey(WeatherData.USE_CELSIUS_KEY)).thenReturn(useCelsius != null)
+ if (useCelsius != null)
+ `when`(getBoolean(WeatherData.USE_CELSIUS_KEY)).thenReturn(useCelsius)
+ }
+
+ val mockBaseAction = mock(SmartspaceAction::class.java)
+ `when`(mockBaseAction.extras).thenReturn(mockWeatherBundle)
+ return SmartspaceTarget.Builder(
+ "targetWithWeatherExtras$id",
+ ComponentName("testpackage", "testclass$id"),
+ userHandle)
+ .setSensitive(false)
+ .setFeatureType(SmartspaceTarget.FEATURE_WEATHER)
+ .setBaseAction(mockBaseAction)
+ .setExpiryTimeMillis(SMARTSPACE_EXPIRY_TIME)
+ .setCreationTimeMillis(SMARTSPACE_CREATION_TIME)
+ .build()
+ }
+
private fun setAllowPrivateNotifications(user: UserHandle, value: Boolean) {
`when`(secureSettings.getIntForUser(
eq(PRIVATE_LOCKSCREEN_SETTING),