Seed color setting to override theme color from WPPG

Bug: 242332478
Fixes: 266700158
Test: atest KeyguardClockSwitchScreenshotTest
Change-Id: I2887054bec077f63001a08318b7077f4fc11b5f8
This commit is contained in:
Hawkwood Glazier
2023-01-25 17:44:37 +00:00
parent 9e4022e403
commit cd549151ac
5 changed files with 120 additions and 64 deletions

View File

@@ -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)
}
}
}
}

View File

@@ -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.

View File

@@ -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? {

View File

@@ -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
)
}
}
}

View File

@@ -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)
}
}