1 package com.android.systemui.plugins.clocks 2 3 import android.os.Bundle 4 import android.util.Log 5 import android.view.View 6 import androidx.annotation.VisibleForTesting 7 import androidx.core.text.util.LocalePreferences 8 9 typealias WeatherTouchAction = (View) -> Unit 10 11 data class WeatherData( 12 val description: String, 13 val state: WeatherStateIcon, 14 val useCelsius: Boolean, 15 val temperature: Int, 16 val touchAction: WeatherTouchAction? = null, 17 ) { 18 companion object { 19 const val DEBUG = true 20 private const val TAG = "WeatherData" 21 @VisibleForTesting const val DESCRIPTION_KEY = "description" 22 @VisibleForTesting const val STATE_KEY = "state" 23 @VisibleForTesting const val USE_CELSIUS_KEY = "use_celsius" 24 @VisibleForTesting const val TEMPERATURE_KEY = "temperature" 25 private const val INVALID_WEATHER_ICON_STATE = -1 26 fromBundlenull27 fun fromBundle(extras: Bundle, touchAction: WeatherTouchAction? = null): WeatherData? { 28 val description = extras.getString(DESCRIPTION_KEY) 29 val state = 30 WeatherStateIcon.fromInt(extras.getInt(STATE_KEY, INVALID_WEATHER_ICON_STATE)) 31 val temperature = readIntFromBundle(extras, TEMPERATURE_KEY) 32 if ( 33 description == null || 34 state == null || 35 !extras.containsKey(USE_CELSIUS_KEY) || 36 temperature == null 37 ) { 38 if (DEBUG) { 39 Log.w(TAG, "Weather data did not parse from $extras") 40 } 41 return null 42 } else { 43 val result = 44 WeatherData( 45 description = description, 46 state = state, 47 useCelsius = extras.getBoolean(USE_CELSIUS_KEY), 48 temperature = temperature, 49 touchAction = touchAction 50 ) 51 if (DEBUG) { 52 Log.i(TAG, "Weather data parsed $result from $extras") 53 } 54 return result 55 } 56 } 57 readIntFromBundlenull58 private fun readIntFromBundle(extras: Bundle, key: String): Int? { 59 try { 60 return extras.getString(key)?.toInt() 61 } catch (e: Exception) { 62 return null 63 } 64 } 65 getPlaceholderWeatherDatanull66 fun getPlaceholderWeatherData(): WeatherData { 67 return getPlaceholderWeatherData( 68 LocalePreferences.getTemperatureUnit() == LocalePreferences.TemperatureUnit.CELSIUS 69 ) 70 } 71 72 private const val DESCRIPTION_PLACEHODLER = "" 73 private const val TEMPERATURE_FAHRENHEIT_PLACEHOLDER = 58 74 private const val TEMPERATURE_CELSIUS_PLACEHOLDER = 21 75 private val WEATHERICON_PLACEHOLDER = WeatherData.WeatherStateIcon.MOSTLY_SUNNY 76 getPlaceholderWeatherDatanull77 fun getPlaceholderWeatherData(useCelsius: Boolean): WeatherData { 78 return WeatherData( 79 description = DESCRIPTION_PLACEHODLER, 80 state = WEATHERICON_PLACEHOLDER, 81 temperature = 82 if (useCelsius) TEMPERATURE_CELSIUS_PLACEHOLDER 83 else TEMPERATURE_FAHRENHEIT_PLACEHOLDER, 84 useCelsius = useCelsius, 85 ) 86 } 87 } 88 89 // Values for WeatherStateIcon must stay in sync with go/g3-WeatherStateIcon 90 enum class WeatherStateIcon(val id: Int) { 91 UNKNOWN_ICON(0), 92 93 // Clear, day & night. 94 SUNNY(1), 95 CLEAR_NIGHT(2), 96 97 // Mostly clear, day & night. 98 MOSTLY_SUNNY(3), 99 MOSTLY_CLEAR_NIGHT(4), 100 101 // Partly cloudy, day & night. 102 PARTLY_CLOUDY(5), 103 PARTLY_CLOUDY_NIGHT(6), 104 105 // Mostly cloudy, day & night. 106 MOSTLY_CLOUDY_DAY(7), 107 MOSTLY_CLOUDY_NIGHT(8), 108 CLOUDY(9), 109 HAZE_FOG_DUST_SMOKE(10), 110 DRIZZLE(11), 111 HEAVY_RAIN(12), 112 SHOWERS_RAIN(13), 113 114 // Scattered showers, day & night. 115 SCATTERED_SHOWERS_DAY(14), 116 SCATTERED_SHOWERS_NIGHT(15), 117 118 // Isolated scattered thunderstorms, day & night. 119 ISOLATED_SCATTERED_TSTORMS_DAY(16), 120 ISOLATED_SCATTERED_TSTORMS_NIGHT(17), 121 STRONG_TSTORMS(18), 122 BLIZZARD(19), 123 BLOWING_SNOW(20), 124 FLURRIES(21), 125 HEAVY_SNOW(22), 126 127 // Scattered snow showers, day & night. 128 SCATTERED_SNOW_SHOWERS_DAY(23), 129 SCATTERED_SNOW_SHOWERS_NIGHT(24), 130 SNOW_SHOWERS_SNOW(25), 131 MIXED_RAIN_HAIL_RAIN_SLEET(26), 132 SLEET_HAIL(27), 133 TORNADO(28), 134 TROPICAL_STORM_HURRICANE(29), 135 WINDY_BREEZY(30), 136 WINTRY_MIX_RAIN_SNOW(31); 137 138 companion object { <lambda>null139 fun fromInt(value: Int) = values().firstOrNull { it.id == value } 140 } 141 } 142 toStringnull143 override fun toString(): String { 144 val unit = if (useCelsius) "C" else "F" 145 return "$state (\"$description\") $temperature°$unit" 146 } 147 } 148