Seed color setting to override theme color from WPPG
Bug: 242332478 Fixes: 266700158 Test: atest KeyguardClockSwitchScreenshotTest Change-Id: I2887054bec077f63001a08318b7077f4fc11b5f8
This commit is contained in:
@@ -21,15 +21,14 @@ import android.os.Handler
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import androidx.annotation.OpenForTesting
|
||||
import com.android.internal.annotations.Keep
|
||||
import com.android.systemui.plugins.ClockController
|
||||
import com.android.systemui.plugins.ClockId
|
||||
import com.android.systemui.plugins.ClockMetadata
|
||||
import com.android.systemui.plugins.ClockProvider
|
||||
import com.android.systemui.plugins.ClockProviderPlugin
|
||||
import com.android.systemui.plugins.ClockSettings
|
||||
import com.android.systemui.plugins.PluginListener
|
||||
import com.android.systemui.plugins.PluginManager
|
||||
import org.json.JSONObject
|
||||
|
||||
private val TAG = ClockRegistry::class.simpleName
|
||||
private const val DEBUG = true
|
||||
@@ -64,34 +63,54 @@ open class ClockRegistry(
|
||||
disconnectClocks(plugin)
|
||||
}
|
||||
|
||||
open var currentClockId: ClockId
|
||||
open var settings: ClockSettings?
|
||||
get() {
|
||||
return try {
|
||||
try {
|
||||
val json = Settings.Secure.getString(
|
||||
context.contentResolver,
|
||||
Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE
|
||||
)
|
||||
if (json == null || json.isEmpty()) {
|
||||
return fallbackClockId
|
||||
return null
|
||||
}
|
||||
ClockSetting.deserialize(json).clockId
|
||||
return ClockSettings.deserialize(json)
|
||||
} catch (ex: Exception) {
|
||||
Log.e(TAG, "Failed to parse clock setting", ex)
|
||||
fallbackClockId
|
||||
Log.e(TAG, "Failed to parse clock settings", ex)
|
||||
return null
|
||||
}
|
||||
}
|
||||
set(value) {
|
||||
protected set(value) {
|
||||
try {
|
||||
val json = ClockSetting.serialize(ClockSetting(value, System.currentTimeMillis()))
|
||||
val json = if (value != null) {
|
||||
value._applied_timestamp = System.currentTimeMillis()
|
||||
ClockSettings.serialize(value)
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
Settings.Secure.putString(
|
||||
context.contentResolver,
|
||||
Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, json
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
Log.e(TAG, "Failed to set clock setting", ex)
|
||||
Log.e(TAG, "Failed to set clock settings", ex)
|
||||
}
|
||||
}
|
||||
|
||||
private fun mutateSetting(mutator: (ClockSettings) -> Unit) {
|
||||
val settings = this.settings ?: ClockSettings()
|
||||
mutator(settings)
|
||||
this.settings = settings
|
||||
}
|
||||
|
||||
var currentClockId: ClockId
|
||||
get() = settings?.clockId ?: fallbackClockId
|
||||
set(value) { mutateSetting { it.clockId = value } }
|
||||
|
||||
var seedColor: Int?
|
||||
get() = settings?.seedColor
|
||||
set(value) { mutateSetting { it.seedColor = value } }
|
||||
|
||||
init {
|
||||
connectClocks(defaultClockProvider)
|
||||
if (!availableClocks.containsKey(DEFAULT_CLOCK_ID)) {
|
||||
@@ -194,36 +213,16 @@ open class ClockRegistry(
|
||||
return createClock(DEFAULT_CLOCK_ID)!!
|
||||
}
|
||||
|
||||
private fun createClock(clockId: ClockId): ClockController? =
|
||||
availableClocks[clockId]?.provider?.createClock(clockId)
|
||||
private fun createClock(clockId: ClockId): ClockController? {
|
||||
val settings = this.settings ?: ClockSettings()
|
||||
if (clockId != settings.clockId) {
|
||||
settings.clockId = clockId
|
||||
}
|
||||
return availableClocks[clockId]?.provider?.createClock(settings)
|
||||
}
|
||||
|
||||
private data class ClockInfo(
|
||||
val metadata: ClockMetadata,
|
||||
val provider: ClockProvider
|
||||
)
|
||||
|
||||
@Keep
|
||||
data class ClockSetting(
|
||||
val clockId: ClockId,
|
||||
val _applied_timestamp: Long?
|
||||
) {
|
||||
companion object {
|
||||
private val KEY_CLOCK_ID = "clockId"
|
||||
private val KEY_TIMESTAMP = "_applied_timestamp"
|
||||
|
||||
fun serialize(setting: ClockSetting): String {
|
||||
return JSONObject()
|
||||
.put(KEY_CLOCK_ID, setting.clockId)
|
||||
.put(KEY_TIMESTAMP, setting._applied_timestamp)
|
||||
.toString()
|
||||
}
|
||||
|
||||
fun deserialize(jsonStr: String): ClockSetting {
|
||||
val json = JSONObject(jsonStr)
|
||||
return ClockSetting(
|
||||
json.getString(KEY_CLOCK_ID),
|
||||
if (!json.isNull(KEY_TIMESTAMP)) json.getLong(KEY_TIMESTAMP) else null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.android.systemui.plugins.ClockController
|
||||
import com.android.systemui.plugins.ClockEvents
|
||||
import com.android.systemui.plugins.ClockFaceController
|
||||
import com.android.systemui.plugins.ClockFaceEvents
|
||||
import com.android.systemui.plugins.ClockSettings
|
||||
import com.android.systemui.plugins.log.LogBuffer
|
||||
import java.io.PrintWriter
|
||||
import java.util.Locale
|
||||
@@ -46,6 +47,7 @@ class DefaultClockController(
|
||||
ctx: Context,
|
||||
private val layoutInflater: LayoutInflater,
|
||||
private val resources: Resources,
|
||||
private val settings: ClockSettings?,
|
||||
) : ClockController {
|
||||
override val smallClock: DefaultClockFaceController
|
||||
override val largeClock: LargeClockFaceController
|
||||
@@ -66,12 +68,14 @@ class DefaultClockController(
|
||||
smallClock =
|
||||
DefaultClockFaceController(
|
||||
layoutInflater.inflate(R.layout.clock_default_small, parent, false)
|
||||
as AnimatableClockView
|
||||
as AnimatableClockView,
|
||||
settings?.seedColor
|
||||
)
|
||||
largeClock =
|
||||
LargeClockFaceController(
|
||||
layoutInflater.inflate(R.layout.clock_default_large, parent, false)
|
||||
as AnimatableClockView
|
||||
as AnimatableClockView,
|
||||
settings?.seedColor
|
||||
)
|
||||
clocks = listOf(smallClock.view, largeClock.view)
|
||||
|
||||
@@ -91,6 +95,7 @@ class DefaultClockController(
|
||||
|
||||
open inner class DefaultClockFaceController(
|
||||
override val view: AnimatableClockView,
|
||||
val seedColor: Int?,
|
||||
) : ClockFaceController {
|
||||
|
||||
// MAGENTA is a placeholder, and will be assigned correctly in initialize
|
||||
@@ -105,6 +110,9 @@ class DefaultClockController(
|
||||
}
|
||||
|
||||
init {
|
||||
if (seedColor != null) {
|
||||
currentColor = seedColor
|
||||
}
|
||||
view.setColors(currentColor, currentColor)
|
||||
}
|
||||
|
||||
@@ -132,7 +140,9 @@ class DefaultClockController(
|
||||
|
||||
fun updateColor() {
|
||||
val color =
|
||||
if (isRegionDark) {
|
||||
if (seedColor != null) {
|
||||
seedColor
|
||||
} else if (isRegionDark) {
|
||||
resources.getColor(android.R.color.system_accent1_100)
|
||||
} else {
|
||||
resources.getColor(android.R.color.system_accent2_600)
|
||||
@@ -152,7 +162,8 @@ class DefaultClockController(
|
||||
|
||||
inner class LargeClockFaceController(
|
||||
view: AnimatableClockView,
|
||||
) : DefaultClockFaceController(view) {
|
||||
seedColor: Int?,
|
||||
) : DefaultClockFaceController(view, seedColor) {
|
||||
override fun recomputePadding(targetRegion: Rect?) {
|
||||
// We center the view within the targetRegion instead of within the parent
|
||||
// view by computing the difference and adding that to the padding.
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.android.systemui.plugins.ClockController
|
||||
import com.android.systemui.plugins.ClockId
|
||||
import com.android.systemui.plugins.ClockMetadata
|
||||
import com.android.systemui.plugins.ClockProvider
|
||||
import com.android.systemui.plugins.ClockSettings
|
||||
|
||||
private val TAG = DefaultClockProvider::class.simpleName
|
||||
const val DEFAULT_CLOCK_NAME = "Default Clock"
|
||||
@@ -36,12 +37,12 @@ class DefaultClockProvider constructor(
|
||||
override fun getClocks(): List<ClockMetadata> =
|
||||
listOf(ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME))
|
||||
|
||||
override fun createClock(id: ClockId): ClockController {
|
||||
if (id != DEFAULT_CLOCK_ID) {
|
||||
throw IllegalArgumentException("$id is unsupported by $TAG")
|
||||
override fun createClock(settings: ClockSettings): ClockController {
|
||||
if (settings.clockId != DEFAULT_CLOCK_ID) {
|
||||
throw IllegalArgumentException("${settings.clockId} is unsupported by $TAG")
|
||||
}
|
||||
|
||||
return DefaultClockController(ctx, layoutInflater, resources)
|
||||
return DefaultClockController(ctx, layoutInflater, resources, settings)
|
||||
}
|
||||
|
||||
override fun getClockThumbnail(id: ClockId): Drawable? {
|
||||
|
||||
@@ -17,11 +17,13 @@ import android.content.res.Resources
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import com.android.internal.annotations.Keep
|
||||
import com.android.systemui.plugins.annotations.ProvidesInterface
|
||||
import com.android.systemui.plugins.log.LogBuffer
|
||||
import java.io.PrintWriter
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
import org.json.JSONObject
|
||||
|
||||
/** Identifies a clock design */
|
||||
typealias ClockId = String
|
||||
@@ -41,7 +43,13 @@ interface ClockProvider {
|
||||
fun getClocks(): List<ClockMetadata>
|
||||
|
||||
/** Initializes and returns the target clock design */
|
||||
fun createClock(id: ClockId): ClockController
|
||||
@Deprecated("Use overload with ClockSettings")
|
||||
fun createClock(id: ClockId): ClockController {
|
||||
return createClock(ClockSettings(id, null, null))
|
||||
}
|
||||
|
||||
/** Initializes and returns the target clock design */
|
||||
fun createClock(settings: ClockSettings): ClockController
|
||||
|
||||
/** A static thumbnail for rendering in some examples */
|
||||
fun getClockThumbnail(id: ClockId): Drawable?
|
||||
@@ -62,7 +70,11 @@ interface ClockController {
|
||||
val animations: ClockAnimations
|
||||
|
||||
/** Initializes various rendering parameters. If never called, provides reasonable defaults. */
|
||||
fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) {
|
||||
fun initialize(
|
||||
resources: Resources,
|
||||
dozeFraction: Float,
|
||||
foldFraction: Float,
|
||||
) {
|
||||
events.onColorPaletteChanged(resources)
|
||||
animations.doze(dozeFraction)
|
||||
animations.fold(foldFraction)
|
||||
@@ -167,3 +179,34 @@ data class ClockMetadata(
|
||||
val clockId: ClockId,
|
||||
val name: String,
|
||||
)
|
||||
|
||||
/** Structure for keeping clock-specific settings */
|
||||
@Keep
|
||||
data class ClockSettings(
|
||||
var clockId: ClockId? = null,
|
||||
var seedColor: Int? = null,
|
||||
var _applied_timestamp: Long? = null,
|
||||
) {
|
||||
companion object {
|
||||
private val KEY_CLOCK_ID = "clockId"
|
||||
private val KEY_SEED_COLOR = "seedColor"
|
||||
private val KEY_TIMESTAMP = "_applied_timestamp"
|
||||
|
||||
fun serialize(setting: ClockSettings): String {
|
||||
return JSONObject()
|
||||
.put(KEY_CLOCK_ID, setting.clockId)
|
||||
.put(KEY_SEED_COLOR, setting.seedColor)
|
||||
.put(KEY_TIMESTAMP, setting._applied_timestamp)
|
||||
.toString()
|
||||
}
|
||||
|
||||
fun deserialize(jsonStr: String): ClockSettings {
|
||||
val json = JSONObject(jsonStr)
|
||||
return ClockSettings(
|
||||
json.getString(KEY_CLOCK_ID),
|
||||
if (!json.isNull(KEY_SEED_COLOR)) json.getInt(KEY_SEED_COLOR) else null,
|
||||
if (!json.isNull(KEY_TIMESTAMP)) json.getLong(KEY_TIMESTAMP) else null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.android.systemui.plugins.ClockController
|
||||
import com.android.systemui.plugins.ClockId
|
||||
import com.android.systemui.plugins.ClockMetadata
|
||||
import com.android.systemui.plugins.ClockProviderPlugin
|
||||
import com.android.systemui.plugins.ClockSettings
|
||||
import com.android.systemui.plugins.PluginListener
|
||||
import com.android.systemui.plugins.PluginManager
|
||||
import com.android.systemui.util.mockito.argumentCaptor
|
||||
@@ -59,7 +60,7 @@ class ClockRegistryTest : SysuiTestCase() {
|
||||
private lateinit var pluginListener: PluginListener<ClockProviderPlugin>
|
||||
private lateinit var registry: ClockRegistry
|
||||
|
||||
private var settingValue: String = ""
|
||||
private var settingValue: ClockSettings? = null
|
||||
|
||||
companion object {
|
||||
private fun failFactory(): ClockController {
|
||||
@@ -79,7 +80,8 @@ class ClockRegistryTest : SysuiTestCase() {
|
||||
private val thumbnailCallbacks = mutableMapOf<ClockId, () -> Drawable?>()
|
||||
|
||||
override fun getClocks() = metadata
|
||||
override fun createClock(id: ClockId): ClockController = createCallbacks[id]!!()
|
||||
override fun createClock(settings: ClockSettings): ClockController =
|
||||
createCallbacks[settings.clockId!!]!!()
|
||||
override fun getClockThumbnail(id: ClockId): Drawable? = thumbnailCallbacks[id]!!()
|
||||
|
||||
fun addClock(
|
||||
@@ -110,7 +112,7 @@ class ClockRegistryTest : SysuiTestCase() {
|
||||
userHandle = UserHandle.USER_ALL,
|
||||
defaultClockProvider = fakeDefaultProvider
|
||||
) {
|
||||
override var currentClockId: ClockId
|
||||
override var settings: ClockSettings?
|
||||
get() = settingValue
|
||||
set(value) { settingValue = value }
|
||||
}
|
||||
@@ -185,7 +187,7 @@ class ClockRegistryTest : SysuiTestCase() {
|
||||
.addClock("clock_1", "clock 1")
|
||||
.addClock("clock_2", "clock 2")
|
||||
|
||||
settingValue = "clock_3"
|
||||
settingValue = ClockSettings("clock_3", null, null)
|
||||
val plugin2 = FakeClockPlugin()
|
||||
.addClock("clock_3", "clock 3", { mockClock })
|
||||
.addClock("clock_4", "clock 4")
|
||||
@@ -203,7 +205,7 @@ class ClockRegistryTest : SysuiTestCase() {
|
||||
.addClock("clock_1", "clock 1")
|
||||
.addClock("clock_2", "clock 2")
|
||||
|
||||
settingValue = "clock_3"
|
||||
settingValue = ClockSettings("clock_3", null, null)
|
||||
val plugin2 = FakeClockPlugin()
|
||||
.addClock("clock_3", "clock 3")
|
||||
.addClock("clock_4", "clock 4")
|
||||
@@ -222,7 +224,7 @@ class ClockRegistryTest : SysuiTestCase() {
|
||||
.addClock("clock_1", "clock 1")
|
||||
.addClock("clock_2", "clock 2")
|
||||
|
||||
settingValue = "clock_3"
|
||||
settingValue = ClockSettings("clock_3", null, null)
|
||||
val plugin2 = FakeClockPlugin()
|
||||
.addClock("clock_3", "clock 3", { mockClock })
|
||||
.addClock("clock_4", "clock 4")
|
||||
@@ -242,8 +244,8 @@ class ClockRegistryTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun jsonDeserialization_gotExpectedObject() {
|
||||
val expected = ClockRegistry.ClockSetting("ID", 500)
|
||||
val actual = ClockRegistry.ClockSetting.deserialize("""{
|
||||
val expected = ClockSettings("ID", null, 500)
|
||||
val actual = ClockSettings.deserialize("""{
|
||||
"clockId":"ID",
|
||||
"_applied_timestamp":500
|
||||
}""")
|
||||
@@ -252,15 +254,15 @@ class ClockRegistryTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun jsonDeserialization_noTimestamp_gotExpectedObject() {
|
||||
val expected = ClockRegistry.ClockSetting("ID", null)
|
||||
val actual = ClockRegistry.ClockSetting.deserialize("{\"clockId\":\"ID\"}")
|
||||
val expected = ClockSettings("ID", null, null)
|
||||
val actual = ClockSettings.deserialize("{\"clockId\":\"ID\"}")
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun jsonDeserialization_nullTimestamp_gotExpectedObject() {
|
||||
val expected = ClockRegistry.ClockSetting("ID", null)
|
||||
val actual = ClockRegistry.ClockSetting.deserialize("""{
|
||||
val expected = ClockSettings("ID", null, null)
|
||||
val actual = ClockSettings.deserialize("""{
|
||||
"clockId":"ID",
|
||||
"_applied_timestamp":null
|
||||
}""")
|
||||
@@ -269,22 +271,22 @@ class ClockRegistryTest : SysuiTestCase() {
|
||||
|
||||
@Test(expected = JSONException::class)
|
||||
fun jsonDeserialization_noId_threwException() {
|
||||
val expected = ClockRegistry.ClockSetting("ID", 500)
|
||||
val actual = ClockRegistry.ClockSetting.deserialize("{\"_applied_timestamp\":500}")
|
||||
val expected = ClockSettings("ID", null, 500)
|
||||
val actual = ClockSettings.deserialize("{\"_applied_timestamp\":500}")
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun jsonSerialization_gotExpectedString() {
|
||||
val expected = "{\"clockId\":\"ID\",\"_applied_timestamp\":500}"
|
||||
val actual = ClockRegistry.ClockSetting.serialize( ClockRegistry.ClockSetting("ID", 500))
|
||||
val actual = ClockSettings.serialize(ClockSettings("ID", null, 500))
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun jsonSerialization_noTimestamp_gotExpectedString() {
|
||||
val expected = "{\"clockId\":\"ID\"}"
|
||||
val actual = ClockRegistry.ClockSetting.serialize( ClockRegistry.ClockSetting("ID", null))
|
||||
val actual = ClockSettings.serialize(ClockSettings("ID", null, null))
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user