summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockDesign.kt6
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt25
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt127
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt53
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt61
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt54
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt308
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt2
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt110
9 files changed, 387 insertions, 359 deletions
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockDesign.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockDesign.kt
index f5e843234095..bcf055bd2c40 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockDesign.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockDesign.kt
@@ -166,12 +166,6 @@ data class FontTextStyle(
// A color literal like `#FF00FF` or a color resource like `@android:color/system_accent1_100`
val fillColorDark: String? = null,
override val fontSizeScale: Float? = null,
- /**
- * use `wdth` for width, `wght` for weight, 'opsz' for optical size single quote for tag name,
- * and no quote for value separate different axis with `,` e.g. "'wght' 1000, 'wdth' 108, 'opsz'
- * 90"
- */
- var fontVariation: String? = null,
// used when alternate in one font file is needed
var fontFeatureSettings: String? = null,
val renderType: RenderType = RenderType.STROKE_TEXT,
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index 9da3022fc0d8..12b20a53df81 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -44,6 +44,7 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
+import org.json.JSONObject
private val KEY_TIMESTAMP = "appliedTimestamp"
private val KNOWN_PLUGINS =
@@ -299,7 +300,7 @@ open class ClockRegistry(
)
}
- ClockSettings.deserialize(json)
+ ClockSettings.fromJson(JSONObject(json))
} catch (ex: Exception) {
logger.e("Failed to parse clock settings", ex)
null
@@ -312,21 +313,24 @@ open class ClockRegistry(
assert.isNotMainThread()
try {
- value?.metadata?.put(KEY_TIMESTAMP, System.currentTimeMillis())
+ val json =
+ value?.let {
+ it.metadata.put(KEY_TIMESTAMP, System.currentTimeMillis())
+ ClockSettings.toJson(it)
+ } ?: ""
- val json = ClockSettings.serialize(value)
if (handleAllUsers) {
Settings.Secure.putStringForUser(
context.contentResolver,
Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
- json,
+ json.toString(),
ActivityManager.getCurrentUser(),
)
} else {
Settings.Secure.putString(
context.contentResolver,
Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
- json,
+ json.toString(),
)
}
} catch (ex: Exception) {
@@ -557,14 +561,15 @@ open class ClockRegistry(
}
fun getClocks(): List<ClockMetadata> {
- if (!isEnabled) {
- return listOf(availableClocks[DEFAULT_CLOCK_ID]!!.metadata)
- }
+ if (!isEnabled) return listOf(availableClocks[DEFAULT_CLOCK_ID]!!.metadata)
return availableClocks.map { (_, clock) -> clock.metadata }
}
- fun getClockPickerConfig(clockId: ClockId): ClockPickerConfig? =
- availableClocks[clockId]?.provider?.getClockPickerConfig(clockId)
+ fun getClockPickerConfig(clockId: ClockId): ClockPickerConfig? {
+ val clockSettings =
+ settings?.let { if (clockId == it.clockId) it else null } ?: ClockSettings(clockId)
+ return availableClocks[clockId]?.provider?.getClockPickerConfig(clockSettings)
+ }
fun createExampleClock(clockId: ClockId): ClockController? = createClock(clockId)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
index d70d61ca8888..9b3c9bfbab01 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
@@ -19,10 +19,9 @@ import android.view.LayoutInflater
import com.android.systemui.customization.R
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.core.LogcatOnlyMessageBuffer
-import com.android.systemui.plugins.clocks.AxisType
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockFontAxis
-import com.android.systemui.plugins.clocks.ClockId
+import com.android.systemui.plugins.clocks.ClockFontAxisSetting
import com.android.systemui.plugins.clocks.ClockMessageBuffers
import com.android.systemui.plugins.clocks.ClockMetadata
import com.android.systemui.plugins.clocks.ClockPickerConfig
@@ -61,7 +60,15 @@ class DefaultClockProvider(
messageBuffers?.infraMessageBuffer ?: LogcatOnlyMessageBuffer(LogLevel.INFO)
val assets = AssetLoader(ctx, ctx, "clocks/", buffer)
assets.setSeedColor(settings.seedColor, null)
- FlexClockController(ctx, resources, assets, FLEX_DESIGN, messageBuffers)
+ val fontAxes = ClockFontAxis.merge(FlexClockController.FONT_AXES, settings.axes)
+ FlexClockController(
+ ctx,
+ resources,
+ settings.copy(axes = fontAxes.map { it.toSetting() }),
+ assets,
+ FLEX_DESIGN,
+ messageBuffers,
+ )
} else {
DefaultClockController(
ctx,
@@ -75,11 +82,14 @@ class DefaultClockProvider(
}
}
- override fun getClockPickerConfig(id: ClockId): ClockPickerConfig {
- if (id != DEFAULT_CLOCK_ID) {
- throw IllegalArgumentException("$id is unsupported by $TAG")
+ override fun getClockPickerConfig(settings: ClockSettings): ClockPickerConfig {
+ if (settings.clockId != DEFAULT_CLOCK_ID) {
+ throw IllegalArgumentException("${settings.clockId} is unsupported by $TAG")
}
+ val fontAxes =
+ if (!isClockReactiveVariantsEnabled) listOf()
+ else ClockFontAxis.merge(FlexClockController.FONT_AXES, settings.axes)
return ClockPickerConfig(
DEFAULT_CLOCK_ID,
resources.getString(R.string.clock_default_name),
@@ -87,52 +97,28 @@ class DefaultClockProvider(
// TODO(b/352049256): Update placeholder to actual resource
resources.getDrawable(R.drawable.clock_default_thumbnail, null),
isReactiveToTone = true,
- // TODO(b/364673969): Populate the rest of this
- axes =
- if (isClockReactiveVariantsEnabled)
- listOf(
- ClockFontAxis(
- key = "wght",
- type = AxisType.Float,
- minValue = 1f,
- currentValue = 400f,
- maxValue = 1000f,
- name = "Weight",
- description = "Glyph Weight",
- ),
- ClockFontAxis(
- key = "wdth",
- type = AxisType.Float,
- minValue = 25f,
- currentValue = 100f,
- maxValue = 151f,
- name = "Width",
- description = "Glyph Width",
- ),
- ClockFontAxis(
- key = "ROND",
- type = AxisType.Boolean,
- minValue = 0f,
- currentValue = 0f,
- maxValue = 100f,
- name = "Round",
- description = "Glyph Roundness",
- ),
- ClockFontAxis(
- key = "slnt",
- type = AxisType.Boolean,
- minValue = 0f,
- currentValue = 0f,
- maxValue = -10f,
- name = "Slant",
- description = "Glyph Slant",
- ),
- )
- else listOf(),
+ axes = fontAxes,
)
}
companion object {
+ // TODO(b/364681643): Variations for retargetted DIGITAL_CLOCK_FLEX
+ val LEGACY_FLEX_LS_VARIATION =
+ listOf(
+ ClockFontAxisSetting("wght", 600f),
+ ClockFontAxisSetting("wdth", 100f),
+ ClockFontAxisSetting("ROND", 100f),
+ ClockFontAxisSetting("slnt", 0f),
+ )
+
+ val LEGACY_FLEX_AOD_VARIATION =
+ listOf(
+ ClockFontAxisSetting("wght", 74f),
+ ClockFontAxisSetting("wdth", 43f),
+ ClockFontAxisSetting("ROND", 100f),
+ ClockFontAxisSetting("slnt", 0f),
+ )
+
val FLEX_DESIGN = run {
val largeLayer =
listOf(
@@ -144,16 +130,9 @@ class DefaultClockProvider(
DigitalHandLayer(
layerBounds = LayerBounds.FIT,
timespec = DigitalTimespec.FIRST_DIGIT,
- style =
- FontTextStyle(
- lineHeight = 147.25f,
- fontVariation =
- "'wght' 603, 'wdth' 100, 'opsz' 144, 'ROND' 100, 'slnt' 0",
- ),
+ style = FontTextStyle(lineHeight = 147.25f),
aodStyle =
FontTextStyle(
- fontVariation =
- "'wght' 74, 'wdth' 43, 'opsz' 144, 'ROND' 100, 'slnt' 0",
fillColorLight = "#FFFFFFFF",
outlineColor = "#00000000",
renderType = RenderType.CHANGE_WEIGHT,
@@ -170,16 +149,9 @@ class DefaultClockProvider(
DigitalHandLayer(
layerBounds = LayerBounds.FIT,
timespec = DigitalTimespec.SECOND_DIGIT,
- style =
- FontTextStyle(
- lineHeight = 147.25f,
- fontVariation =
- "'wght' 603, 'wdth' 100, 'opsz' 144, 'ROND' 100, 'slnt' 0",
- ),
+ style = FontTextStyle(lineHeight = 147.25f),
aodStyle =
FontTextStyle(
- fontVariation =
- "'wght' 74, 'wdth' 43, 'opsz' 144, 'ROND' 100, 'slnt' 0",
fillColorLight = "#FFFFFFFF",
outlineColor = "#00000000",
renderType = RenderType.CHANGE_WEIGHT,
@@ -196,16 +168,9 @@ class DefaultClockProvider(
DigitalHandLayer(
layerBounds = LayerBounds.FIT,
timespec = DigitalTimespec.FIRST_DIGIT,
- style =
- FontTextStyle(
- lineHeight = 147.25f,
- fontVariation =
- "'wght' 603, 'wdth' 100, 'opsz' 144, 'ROND' 100, 'slnt' 0",
- ),
+ style = FontTextStyle(lineHeight = 147.25f),
aodStyle =
FontTextStyle(
- fontVariation =
- "'wght' 74, 'wdth' 43, 'opsz' 144, 'ROND' 100, 'slnt' 0",
fillColorLight = "#FFFFFFFF",
outlineColor = "#00000000",
renderType = RenderType.CHANGE_WEIGHT,
@@ -222,16 +187,9 @@ class DefaultClockProvider(
DigitalHandLayer(
layerBounds = LayerBounds.FIT,
timespec = DigitalTimespec.SECOND_DIGIT,
- style =
- FontTextStyle(
- lineHeight = 147.25f,
- fontVariation =
- "'wght' 603, 'wdth' 100, 'opsz' 144, 'ROND' 100, 'slnt' 0",
- ),
+ style = FontTextStyle(lineHeight = 147.25f),
aodStyle =
FontTextStyle(
- fontVariation =
- "'wght' 74, 'wdth' 43, 'opsz' 144, 'ROND' 100, 'slnt' 0",
fillColorLight = "#FFFFFFFF",
outlineColor = "#00000000",
renderType = RenderType.CHANGE_WEIGHT,
@@ -254,16 +212,9 @@ class DefaultClockProvider(
DigitalHandLayer(
layerBounds = LayerBounds.FIT,
timespec = DigitalTimespec.TIME_FULL_FORMAT,
- style =
- FontTextStyle(
- fontVariation =
- "'wght' 600, 'wdth' 100, 'opsz' 144, 'ROND' 100, 'slnt' 0",
- fontSizeScale = 0.98f,
- ),
+ style = FontTextStyle(fontSizeScale = 0.98f),
aodStyle =
FontTextStyle(
- fontVariation =
- "'wght' 133, 'wdth' 43, 'opsz' 144, 'ROND' 100, 'slnt' 0",
fillColorLight = "#FFFFFFFF",
outlineColor = "#00000000",
renderType = RenderType.CHANGE_WEIGHT,
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
index d8fd77682570..6c627e27a19b 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
@@ -20,11 +20,14 @@ import android.content.Context
import android.content.res.Resources
import com.android.systemui.customization.R
import com.android.systemui.plugins.clocks.AlarmData
+import com.android.systemui.plugins.clocks.AxisType
import com.android.systemui.plugins.clocks.ClockConfig
import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.plugins.clocks.ClockEvents
+import com.android.systemui.plugins.clocks.ClockFontAxis
import com.android.systemui.plugins.clocks.ClockFontAxisSetting
import com.android.systemui.plugins.clocks.ClockMessageBuffers
+import com.android.systemui.plugins.clocks.ClockSettings
import com.android.systemui.plugins.clocks.ThemeConfig
import com.android.systemui.plugins.clocks.WeatherData
import com.android.systemui.plugins.clocks.ZenData
@@ -37,6 +40,7 @@ import java.util.TimeZone
class FlexClockController(
private val ctx: Context,
private val resources: Resources,
+ private val settings: ClockSettings,
private val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources
val design: ClockDesign, // TODO(b/364680879): Remove when done inlining
val messageBuffers: ClockMessageBuffers?,
@@ -114,13 +118,16 @@ class FlexClockController(
}
override fun onFontAxesChanged(axes: List<ClockFontAxisSetting>) {
- smallClock.events.onFontAxesChanged(axes)
- largeClock.events.onFontAxesChanged(axes)
+ val fontAxes = ClockFontAxis.merge(FONT_AXES, axes).map { it.toSetting() }
+ smallClock.events.onFontAxesChanged(fontAxes)
+ largeClock.events.onFontAxesChanged(fontAxes)
}
}
override fun initialize(isDarkTheme: Boolean, dozeFraction: Float, foldFraction: Float) {
val theme = ThemeConfig(isDarkTheme, assets.seedColor)
+ events.onFontAxesChanged(settings.axes)
+
smallClock.run {
events.onThemeChanged(theme)
animations.doze(dozeFraction)
@@ -137,4 +144,46 @@ class FlexClockController(
}
override fun dump(pw: PrintWriter) {}
+
+ companion object {
+ val FONT_AXES =
+ listOf(
+ ClockFontAxis(
+ key = "wght",
+ type = AxisType.Float,
+ minValue = 1f,
+ currentValue = 400f,
+ maxValue = 1000f,
+ name = "Weight",
+ description = "Glyph Weight",
+ ),
+ ClockFontAxis(
+ key = "wdth",
+ type = AxisType.Float,
+ minValue = 25f,
+ currentValue = 100f,
+ maxValue = 151f,
+ name = "Width",
+ description = "Glyph Width",
+ ),
+ ClockFontAxis(
+ key = "ROND",
+ type = AxisType.Boolean,
+ minValue = 0f,
+ currentValue = 0f,
+ maxValue = 100f,
+ name = "Round",
+ description = "Glyph Roundness",
+ ),
+ ClockFontAxis(
+ key = "slnt",
+ type = AxisType.Boolean,
+ minValue = 0f,
+ currentValue = 0f,
+ maxValue = -10f,
+ name = "Slant",
+ description = "Glyph Slant",
+ ),
+ )
+ }
}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
index edcee9de5a46..0b55a6e3ffa1 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
@@ -19,7 +19,6 @@ package com.android.systemui.shared.clocks.view
import android.content.Context
import android.graphics.Canvas
import android.graphics.Point
-import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
@@ -28,7 +27,6 @@ import com.android.systemui.customization.R
import com.android.systemui.log.core.MessageBuffer
import com.android.systemui.shared.clocks.AssetLoader
import com.android.systemui.shared.clocks.DigitTranslateAnimator
-import com.android.systemui.shared.clocks.FontTextStyle
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
@@ -52,65 +50,6 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me
)
}
- private var prevX = 0f
- private var prevY = 0f
- private var isDown = false
-
- private var wght = 603f
- private var wdth = 100f
-
- private val MAX_WGHT = 950f
- private val MIN_WGHT = 50f
- private val WGHT_SCALE = 0.5f
-
- private val MAX_WDTH = 150f
- private val MIN_WDTH = 0f
- private val WDTH_SCALE = 0.2f
-
- override fun onTouchEvent(evt: MotionEvent): Boolean {
- if (!isReactiveTouchInteractionEnabled) {
- return super.onTouchEvent(evt)
- }
-
- when (evt.action) {
- MotionEvent.ACTION_DOWN -> {
- isDown = true
- prevX = evt.x
- prevY = evt.y
- return true
- }
-
- MotionEvent.ACTION_MOVE -> {
- if (!isDown) {
- return super.onTouchEvent(evt)
- }
-
- wdth = clamp(wdth + (evt.x - prevX) * WDTH_SCALE, MIN_WDTH, MAX_WDTH)
- wght = clamp(wght + (evt.y - prevY) * WGHT_SCALE, MIN_WGHT, MAX_WGHT)
- prevX = evt.x
- prevY = evt.y
-
- val fvar = "'wght' $wght, 'wdth' $wdth, 'opsz' 144, 'ROND' 100"
- digitalClockTextViewMap.forEach { (_, view) ->
- val textStyle = view.textStyle as FontTextStyle
- textStyle.fontVariation = fvar
- view.applyStyles(assets, textStyle, view.aodStyle)
- }
-
- requestLayout()
- invalidate()
- return true
- }
-
- MotionEvent.ACTION_UP -> {
- isDown = false
- return true
- }
- }
-
- return super.onTouchEvent(evt)
- }
-
override fun addView(child: View?) {
super.addView(child)
(child as SimpleDigitalClockTextView).digitTranslateAnimator =
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
index 0dacce104334..c0899e3006a6 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
@@ -65,6 +65,9 @@ open class SimpleDigitalClockTextView(
val lockScreenPaint = TextPaint()
override lateinit var textStyle: FontTextStyle
lateinit var aodStyle: FontTextStyle
+
+ private var lsFontVariation = ClockFontAxisSetting.toFVar(DEFAULT_LS_VARIATION)
+ private var aodFontVariation = ClockFontAxisSetting.toFVar(DEFAULT_AOD_VARIATION)
private val parser = DimensionParser(ctx)
var maxSingleDigitHeight = -1
var maxSingleDigitWidth = -1
@@ -142,18 +145,10 @@ open class SimpleDigitalClockTextView(
}
override fun updateAxes(axes: List<ClockFontAxisSetting>) {
- val sb = StringBuilder()
- sb.append("'opsz' 144")
-
- for (axis in axes) {
- if (sb.length > 0) sb.append(", ")
- sb.append("'${axis.key}' ${axis.value.toInt()}")
- }
-
- val fvar = sb.toString()
- lockScreenPaint.typeface = typefaceCache.getTypefaceForVariant(fvar)
+ lsFontVariation = ClockFontAxisSetting.toFVar(axes + OPTICAL_SIZE_AXIS)
+ lockScreenPaint.typeface = typefaceCache.getTypefaceForVariant(lsFontVariation)
typeface = lockScreenPaint.typeface
- textAnimator.setTextStyle(fvar = fvar, animate = true)
+ textAnimator.setTextStyle(fvar = lsFontVariation, animate = true)
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
recomputeMaxSingleDigitSizes()
requestLayout()
@@ -287,15 +282,12 @@ open class SimpleDigitalClockTextView(
}
override fun animateDoze(isDozing: Boolean, isAnimated: Boolean) {
- if (!this::textAnimator.isInitialized) {
- return
- }
- val fvar = if (isDozing) aodStyle.fontVariation else textStyle.fontVariation
+ if (!this::textAnimator.isInitialized) return
textAnimator.setTextStyle(
animate = isAnimated && isAnimationEnabled,
color = if (isDozing) AOD_COLOR else lockscreenColor,
textSize = if (isDozing) aodFontSizePx else lockScreenPaint.textSize,
- fvar = fvar,
+ fvar = if (isDozing) aodFontVariation else lsFontVariation,
duration = aodStyle.transitionDuration,
interpolator = aodDozingInterpolator,
)
@@ -308,14 +300,15 @@ open class SimpleDigitalClockTextView(
return
}
logger.d("animateCharge()")
- val middleFvar = if (dozeFraction == 0F) aodStyle.fontVariation else textStyle.fontVariation
- val endFvar = if (dozeFraction == 0F) textStyle.fontVariation else aodStyle.fontVariation
val startAnimPhase2 = Runnable {
- textAnimator.setTextStyle(fvar = endFvar, animate = isAnimationEnabled)
+ textAnimator.setTextStyle(
+ fvar = if (dozeFraction == 0F) lsFontVariation else aodFontVariation,
+ animate = isAnimationEnabled,
+ )
updateTextBoundsForTextAnimator()
}
textAnimator.setTextStyle(
- fvar = middleFvar,
+ fvar = if (dozeFraction == 0F) aodFontVariation else lsFontVariation,
animate = isAnimationEnabled,
onAnimationEnd = startAnimPhase2,
)
@@ -444,7 +437,7 @@ open class SimpleDigitalClockTextView(
val typefaceName = "fonts/" + textStyle.fontFamily
setTypefaceCache(assets.typefaceCache.getVariantCache(typefaceName))
lockScreenPaint.strokeJoin = Paint.Join.ROUND
- lockScreenPaint.typeface = typefaceCache.getTypefaceForVariant(textStyle.fontVariation)
+ lockScreenPaint.typeface = typefaceCache.getTypefaceForVariant(lsFontVariation)
textStyle.fontFeatureSettings?.let {
lockScreenPaint.fontFeatureSettings = it
fontFeatureSettings = it
@@ -515,7 +508,7 @@ open class SimpleDigitalClockTextView(
textAnimator.textInterpolator.targetPaint.set(lockScreenPaint)
textAnimator.textInterpolator.onTargetPaintModified()
textAnimator.setTextStyle(
- fvar = textStyle.fontVariation,
+ fvar = lsFontVariation,
textSize = lockScreenPaint.textSize,
color = lockscreenColor,
animate = false,
@@ -555,5 +548,22 @@ open class SimpleDigitalClockTextView(
companion object {
val AOD_STROKE_WIDTH = "2dp"
val AOD_COLOR = Color.WHITE
+ val OPTICAL_SIZE_AXIS = ClockFontAxisSetting("opsz", 144f)
+ val DEFAULT_LS_VARIATION =
+ listOf(
+ OPTICAL_SIZE_AXIS,
+ ClockFontAxisSetting("wght", 400f),
+ ClockFontAxisSetting("wdth", 100f),
+ ClockFontAxisSetting("ROND", 0f),
+ ClockFontAxisSetting("slnt", 0f),
+ )
+ val DEFAULT_AOD_VARIATION =
+ listOf(
+ OPTICAL_SIZE_AXIS,
+ ClockFontAxisSetting("wght", 200f),
+ ClockFontAxisSetting("wdth", 100f),
+ ClockFontAxisSetting("ROND", 0f),
+ ClockFontAxisSetting("slnt", 0f),
+ )
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index 022825a48de3..f4a43a454a6f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -22,19 +22,20 @@ import android.graphics.drawable.Drawable
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.PluginLifecycleManager
+import com.android.systemui.plugins.PluginListener
+import com.android.systemui.plugins.PluginManager
import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.plugins.clocks.ClockFontAxisSetting
import com.android.systemui.plugins.clocks.ClockId
import com.android.systemui.plugins.clocks.ClockMessageBuffers
import com.android.systemui.plugins.clocks.ClockMetadata
import com.android.systemui.plugins.clocks.ClockPickerConfig
import com.android.systemui.plugins.clocks.ClockProviderPlugin
import com.android.systemui.plugins.clocks.ClockSettings
-import com.android.systemui.plugins.PluginLifecycleManager
-import com.android.systemui.plugins.PluginListener
-import com.android.systemui.plugins.PluginManager
+import com.android.systemui.util.ThreadAssert
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.ThreadAssert
import java.util.function.BiConsumer
import junit.framework.Assert.assertEquals
import junit.framework.Assert.fail
@@ -42,6 +43,8 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestCoroutineScheduler
import kotlinx.coroutines.test.TestScope
+import org.json.JSONArray
+import org.json.JSONObject
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -81,28 +84,32 @@ class ClockRegistryTest : SysuiTestCase() {
return null!!
}
- private fun failPickerConfig(clockId: ClockId): ClockPickerConfig {
- fail("Unexpected call to getClockPickerConfig: $clockId")
+ private fun failPickerConfig(settings: ClockSettings): ClockPickerConfig {
+ fail("Unexpected call to getClockPickerConfig: ${settings.clockId}")
return null!!
}
}
- private class FakeLifecycle(
- private val tag: String,
- private val plugin: ClockProviderPlugin?,
- ) : PluginLifecycleManager<ClockProviderPlugin> {
+ private class FakeLifecycle(private val tag: String, private val plugin: ClockProviderPlugin?) :
+ PluginLifecycleManager<ClockProviderPlugin> {
var onLoad: (() -> Unit)? = null
var onUnload: (() -> Unit)? = null
private var mIsLoaded: Boolean = true
+
override fun isLoaded() = mIsLoaded
+
override fun getPlugin(): ClockProviderPlugin? = if (isLoaded) plugin else null
var mComponentName = ComponentName("Package[$tag]", "Class[$tag]")
+
override fun toString() = "Manager[$tag]"
+
override fun getPackage(): String = mComponentName.getPackageName()
+
override fun getComponentName(): ComponentName = mComponentName
- override fun setLogFunc(func: BiConsumer<String, String>) { }
+
+ override fun setLogFunc(func: BiConsumer<String, String>) {}
override fun loadPlugin() {
if (!mIsLoaded) {
@@ -122,7 +129,7 @@ class ClockRegistryTest : SysuiTestCase() {
private class FakeClockPlugin : ClockProviderPlugin {
private val metadata = mutableListOf<ClockMetadata>()
private val createCallbacks = mutableMapOf<ClockId, (ClockId) -> ClockController>()
- private val pickerConfigs = mutableMapOf<ClockId, (ClockId) -> ClockPickerConfig>()
+ private val pickerConfigs = mutableMapOf<ClockId, (ClockSettings) -> ClockPickerConfig>()
override fun getClocks() = metadata
@@ -132,17 +139,17 @@ class ClockRegistryTest : SysuiTestCase() {
?: throw NotImplementedError("No callback for '$clockId'")
}
- override fun getClockPickerConfig(clockId: ClockId): ClockPickerConfig {
- return pickerConfigs[clockId]?.invoke(clockId)
- ?: throw NotImplementedError("No picker config for '$clockId'")
+ override fun getClockPickerConfig(settings: ClockSettings): ClockPickerConfig {
+ return pickerConfigs[settings.clockId]?.invoke(settings)
+ ?: throw NotImplementedError("No picker config for '${settings.clockId}'")
}
- override fun initialize(buffers: ClockMessageBuffers?) { }
+ override fun initialize(buffers: ClockMessageBuffers?) {}
fun addClock(
id: ClockId,
create: (ClockId) -> ClockController = ::failFactory,
- getPickerConfig: (ClockId) -> ClockPickerConfig = ::failPickerConfig
+ getPickerConfig: (ClockSettings) -> ClockPickerConfig = ::failPickerConfig,
): FakeClockPlugin {
metadata.add(ClockMetadata(id))
createCallbacks[id] = create
@@ -158,29 +165,32 @@ class ClockRegistryTest : SysuiTestCase() {
scope = TestScope(dispatcher)
pickerConfig = ClockPickerConfig("CLOCK_ID", "NAME", "DESC", mockThumbnail)
- fakeDefaultProvider = FakeClockPlugin()
- .addClock(DEFAULT_CLOCK_ID, { mockDefaultClock }, { pickerConfig })
+ fakeDefaultProvider =
+ FakeClockPlugin().addClock(DEFAULT_CLOCK_ID, { mockDefaultClock }, { pickerConfig })
whenever(mockContext.contentResolver).thenReturn(mockContentResolver)
val captor = argumentCaptor<PluginListener<ClockProviderPlugin>>()
- registry = object : ClockRegistry(
- mockContext,
- mockPluginManager,
- scope = scope.backgroundScope,
- mainDispatcher = dispatcher,
- bgDispatcher = dispatcher,
- isEnabled = true,
- handleAllUsers = true,
- defaultClockProvider = fakeDefaultProvider,
- keepAllLoaded = false,
- subTag = "Test",
- assert = mockThreadAssert,
- ) {
- override fun querySettings() { }
- override fun applySettings(value: ClockSettings?) {
- settings = value
+ registry =
+ object :
+ ClockRegistry(
+ mockContext,
+ mockPluginManager,
+ scope = scope.backgroundScope,
+ mainDispatcher = dispatcher,
+ bgDispatcher = dispatcher,
+ isEnabled = true,
+ handleAllUsers = true,
+ defaultClockProvider = fakeDefaultProvider,
+ keepAllLoaded = false,
+ subTag = "Test",
+ assert = mockThreadAssert,
+ ) {
+ override fun querySettings() {}
+
+ override fun applySettings(value: ClockSettings?) {
+ settings = value
+ }
}
- }
registry.registerListeners()
verify(mockPluginManager)
@@ -190,14 +200,10 @@ class ClockRegistryTest : SysuiTestCase() {
@Test
fun pluginRegistration_CorrectState() {
- val plugin1 = FakeClockPlugin()
- .addClock("clock_1")
- .addClock("clock_2")
+ val plugin1 = FakeClockPlugin().addClock("clock_1").addClock("clock_2")
val lifecycle1 = FakeLifecycle("1", plugin1)
- val plugin2 = FakeClockPlugin()
- .addClock("clock_3")
- .addClock("clock_4")
+ val plugin2 = FakeClockPlugin().addClock("clock_3").addClock("clock_4")
val lifecycle2 = FakeLifecycle("2", plugin2)
pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1)
@@ -210,8 +216,8 @@ class ClockRegistryTest : SysuiTestCase() {
ClockMetadata("clock_1"),
ClockMetadata("clock_2"),
ClockMetadata("clock_3"),
- ClockMetadata("clock_4")
- )
+ ClockMetadata("clock_4"),
+ ),
)
}
@@ -223,14 +229,13 @@ class ClockRegistryTest : SysuiTestCase() {
@Test
fun clockIdConflict_ErrorWithoutCrash_unloadDuplicate() {
- val plugin1 = FakeClockPlugin()
- .addClock("clock_1", { mockClock }, { pickerConfig })
- .addClock("clock_2", { mockClock }, { pickerConfig })
+ val plugin1 =
+ FakeClockPlugin()
+ .addClock("clock_1", { mockClock }, { pickerConfig })
+ .addClock("clock_2", { mockClock }, { pickerConfig })
val lifecycle1 = spy(FakeLifecycle("1", plugin1))
- val plugin2 = FakeClockPlugin()
- .addClock("clock_1")
- .addClock("clock_2")
+ val plugin2 = FakeClockPlugin().addClock("clock_1").addClock("clock_2")
val lifecycle2 = spy(FakeLifecycle("2", plugin2))
pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1)
@@ -241,8 +246,8 @@ class ClockRegistryTest : SysuiTestCase() {
setOf(
ClockMetadata(DEFAULT_CLOCK_ID),
ClockMetadata("clock_1"),
- ClockMetadata("clock_2")
- )
+ ClockMetadata("clock_2"),
+ ),
)
assertEquals(registry.createExampleClock("clock_1"), mockClock)
@@ -255,14 +260,10 @@ class ClockRegistryTest : SysuiTestCase() {
@Test
fun createCurrentClock_pluginConnected() {
- val plugin1 = FakeClockPlugin()
- .addClock("clock_1")
- .addClock("clock_2")
+ val plugin1 = FakeClockPlugin().addClock("clock_1").addClock("clock_2")
val lifecycle1 = spy(FakeLifecycle("1", plugin1))
- val plugin2 = FakeClockPlugin()
- .addClock("clock_3", { mockClock })
- .addClock("clock_4")
+ val plugin2 = FakeClockPlugin().addClock("clock_3", { mockClock }).addClock("clock_4")
val lifecycle2 = spy(FakeLifecycle("2", plugin2))
registry.applySettings(ClockSettings("clock_3", null))
@@ -275,14 +276,10 @@ class ClockRegistryTest : SysuiTestCase() {
@Test
fun activeClockId_changeAfterPluginConnected() {
- val plugin1 = FakeClockPlugin()
- .addClock("clock_1")
- .addClock("clock_2")
+ val plugin1 = FakeClockPlugin().addClock("clock_1").addClock("clock_2")
val lifecycle1 = spy(FakeLifecycle("1", plugin1))
- val plugin2 = FakeClockPlugin()
- .addClock("clock_3", { mockClock })
- .addClock("clock_4")
+ val plugin2 = FakeClockPlugin().addClock("clock_3", { mockClock }).addClock("clock_4")
val lifecycle2 = spy(FakeLifecycle("2", plugin2))
registry.applySettings(ClockSettings("clock_3", null))
@@ -296,14 +293,10 @@ class ClockRegistryTest : SysuiTestCase() {
@Test
fun createDefaultClock_pluginDisconnected() {
- val plugin1 = FakeClockPlugin()
- .addClock("clock_1")
- .addClock("clock_2")
+ val plugin1 = FakeClockPlugin().addClock("clock_1").addClock("clock_2")
val lifecycle1 = spy(FakeLifecycle("1", plugin1))
- val plugin2 = FakeClockPlugin()
- .addClock("clock_3")
- .addClock("clock_4")
+ val plugin2 = FakeClockPlugin().addClock("clock_3").addClock("clock_4")
val lifecycle2 = spy(FakeLifecycle("2", plugin2))
registry.applySettings(ClockSettings("clock_3", null))
@@ -317,22 +310,25 @@ class ClockRegistryTest : SysuiTestCase() {
@Test
fun pluginRemoved_clockAndListChanged() {
- val plugin1 = FakeClockPlugin()
- .addClock("clock_1")
- .addClock("clock_2")
+ val plugin1 = FakeClockPlugin().addClock("clock_1").addClock("clock_2")
val lifecycle1 = spy(FakeLifecycle("1", plugin1))
- val plugin2 = FakeClockPlugin()
- .addClock("clock_3", { mockClock })
- .addClock("clock_4")
+ val plugin2 = FakeClockPlugin().addClock("clock_3", { mockClock }).addClock("clock_4")
val lifecycle2 = spy(FakeLifecycle("2", plugin2))
var changeCallCount = 0
var listChangeCallCount = 0
- registry.registerClockChangeListener(object : ClockRegistry.ClockChangeListener {
- override fun onCurrentClockChanged() { changeCallCount++ }
- override fun onAvailableClocksChanged() { listChangeCallCount++ }
- })
+ registry.registerClockChangeListener(
+ object : ClockRegistry.ClockChangeListener {
+ override fun onCurrentClockChanged() {
+ changeCallCount++
+ }
+
+ override fun onAvailableClocksChanged() {
+ listChangeCallCount++
+ }
+ }
+ )
registry.applySettings(ClockSettings("clock_3", null))
scheduler.runCurrent()
@@ -372,16 +368,24 @@ class ClockRegistryTest : SysuiTestCase() {
@Test
fun unknownPluginAttached_clockAndListUnchanged_loadRequested() {
- val lifecycle = FakeLifecycle("", null).apply {
- mComponentName = ComponentName("some.other.package", "SomeClass")
- }
+ val lifecycle =
+ FakeLifecycle("", null).apply {
+ mComponentName = ComponentName("some.other.package", "SomeClass")
+ }
var changeCallCount = 0
var listChangeCallCount = 0
- registry.registerClockChangeListener(object : ClockRegistry.ClockChangeListener {
- override fun onCurrentClockChanged() { changeCallCount++ }
- override fun onAvailableClocksChanged() { listChangeCallCount++ }
- })
+ registry.registerClockChangeListener(
+ object : ClockRegistry.ClockChangeListener {
+ override fun onCurrentClockChanged() {
+ changeCallCount++
+ }
+
+ override fun onAvailableClocksChanged() {
+ listChangeCallCount++
+ }
+ }
+ )
assertEquals(true, pluginListener.onPluginAttached(lifecycle))
scheduler.runCurrent()
@@ -391,22 +395,33 @@ class ClockRegistryTest : SysuiTestCase() {
@Test
fun knownPluginAttached_clockAndListChanged_loadedCurrent() {
- val metroLifecycle = FakeLifecycle("Metro", null).apply {
- mComponentName = ComponentName("com.android.systemui.clocks.metro", "Metro")
- }
- val bignumLifecycle = FakeLifecycle("BigNum", null).apply {
- mComponentName = ComponentName("com.android.systemui.clocks.bignum", "BigNum")
- }
- val calligraphyLifecycle = FakeLifecycle("Calligraphy", null).apply {
- mComponentName = ComponentName("com.android.systemui.clocks.calligraphy", "Calligraphy")
- }
+ val metroLifecycle =
+ FakeLifecycle("Metro", null).apply {
+ mComponentName = ComponentName("com.android.systemui.clocks.metro", "Metro")
+ }
+ val bignumLifecycle =
+ FakeLifecycle("BigNum", null).apply {
+ mComponentName = ComponentName("com.android.systemui.clocks.bignum", "BigNum")
+ }
+ val calligraphyLifecycle =
+ FakeLifecycle("Calligraphy", null).apply {
+ mComponentName =
+ ComponentName("com.android.systemui.clocks.calligraphy", "Calligraphy")
+ }
var changeCallCount = 0
var listChangeCallCount = 0
- registry.registerClockChangeListener(object : ClockRegistry.ClockChangeListener {
- override fun onCurrentClockChanged() { changeCallCount++ }
- override fun onAvailableClocksChanged() { listChangeCallCount++ }
- })
+ registry.registerClockChangeListener(
+ object : ClockRegistry.ClockChangeListener {
+ override fun onCurrentClockChanged() {
+ changeCallCount++
+ }
+
+ override fun onAvailableClocksChanged() {
+ listChangeCallCount++
+ }
+ }
+ )
registry.applySettings(ClockSettings("DIGITAL_CLOCK_CALLIGRAPHY", null))
scheduler.runCurrent()
@@ -466,67 +481,84 @@ class ClockRegistryTest : SysuiTestCase() {
scheduler.runCurrent()
// Verify all plugins were correctly loaded into the registry
- assertEquals(registry.getClocks().toSet(), setOf(
- ClockMetadata("DEFAULT"),
- ClockMetadata("clock_2"),
- ClockMetadata("clock_3"),
- ClockMetadata("clock_4")
- ))
+ assertEquals(
+ registry.getClocks().toSet(),
+ setOf(
+ ClockMetadata("DEFAULT"),
+ ClockMetadata("clock_2"),
+ ClockMetadata("clock_3"),
+ ClockMetadata("clock_4"),
+ ),
+ )
}
@Test
- fun jsonDeserialization_gotExpectedObject() {
- val expected = ClockSettings("ID", null).apply {
- metadata.put("appliedTimestamp", 500)
- }
- val actual = ClockSettings.deserialize("""{
- "clockId":"ID",
- "metadata": {
- "appliedTimestamp":500
- }
- }""")
+ fun jsonDeserialization() {
+ val expected = ClockSettings("ID").apply { metadata.put("appliedTimestamp", 50) }
+ val json = JSONObject("""{"clockId":"ID", "metadata": { "appliedTimestamp":50 } }""")
+ val actual = ClockSettings.fromJson(json)
assertEquals(expected, actual)
}
@Test
- fun jsonDeserialization_noTimestamp_gotExpectedObject() {
- val expected = ClockSettings("ID", null)
- val actual = ClockSettings.deserialize("{\"clockId\":\"ID\"}")
+ fun jsonDeserialization_noTimestamp() {
+ val expected = ClockSettings("ID")
+ val actual = ClockSettings.fromJson(JSONObject("""{"clockId":"ID"}"""))
assertEquals(expected, actual)
}
@Test
- fun jsonDeserialization_nullTimestamp_gotExpectedObject() {
- val expected = ClockSettings("ID", null)
- val actual = ClockSettings.deserialize("""{
- "clockId":"ID",
- "metadata":null
- }""")
+ fun jsonDeserialization_nullTimestamp() {
+ val expected = ClockSettings("ID")
+ val actual = ClockSettings.fromJson(JSONObject("""{"clockId":"ID", "metadata":null}"""))
assertEquals(expected, actual)
}
@Test
fun jsonDeserialization_noId_deserializedEmpty() {
- val expected = ClockSettings(null, null).apply {
- metadata.put("appliedTimestamp", 500)
- }
- val actual = ClockSettings.deserialize("{\"metadata\":{\"appliedTimestamp\":500}}")
+ val expected = ClockSettings().apply { metadata.put("appliedTimestamp", 50) }
+ val actual = ClockSettings.fromJson(JSONObject("""{"metadata":{"appliedTimestamp":50}}"""))
assertEquals(expected, actual)
}
@Test
- fun jsonSerialization_gotExpectedString() {
- val expected = "{\"clockId\":\"ID\",\"metadata\":{\"appliedTimestamp\":500}}"
- val actual = ClockSettings.serialize(ClockSettings("ID", null).apply {
- metadata.put("appliedTimestamp", 500)
- })
+ fun jsonDeserialization_fontAxes() {
+ val expected = ClockSettings(axes = listOf(ClockFontAxisSetting("KEY", 10f)))
+ val json = JSONObject("""{"axes":[{"key":"KEY","value":10}]}""")
+ val actual = ClockSettings.fromJson(json)
assertEquals(expected, actual)
}
@Test
- fun jsonSerialization_noTimestamp_gotExpectedString() {
- val expected = "{\"clockId\":\"ID\",\"metadata\":{}}"
- val actual = ClockSettings.serialize(ClockSettings("ID", null))
- assertEquals(expected, actual)
+ fun jsonSerialization() {
+ val expected =
+ JSONObject().apply {
+ put("clockId", "ID")
+ put("metadata", JSONObject().apply { put("appliedTimestamp", 50) })
+ put("axes", JSONArray())
+ }
+ val settings = ClockSettings("ID", null).apply { metadata.put("appliedTimestamp", 50) }
+ val actual = ClockSettings.toJson(settings)
+ assertEquals(expected.toString(), actual.toString())
+ }
+
+ @Test
+ fun jsonSerialization_noTimestamp() {
+ val expected =
+ JSONObject().apply {
+ put("clockId", "ID")
+ put("metadata", JSONObject())
+ put("axes", JSONArray())
+ }
+ val actual = ClockSettings.toJson(ClockSettings("ID", null))
+ assertEquals(expected.toString(), actual.toString())
+ }
+
+ @Test
+ fun jsonSerialization_axisSettings() {
+ val settings = ClockSettings(axes = listOf(ClockFontAxisSetting("KEY", 10f)))
+ val actual = ClockSettings.toJson(settings)
+ val expected = JSONObject("""{"metadata":{},"axes":[{"key":"KEY","value":10}]}""")
+ assertEquals(expected.toString(), actual.toString())
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
index 7e86ff3e95ac..aa8b4f136683 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
@@ -89,7 +89,7 @@ class DefaultClockProviderTest : SysuiTestCase() {
// All providers need to provide clocks & thumbnails for exposed clocks
for (metadata in provider.getClocks()) {
assertNotNull(provider.createClock(metadata.clockId))
- assertNotNull(provider.getClockPickerConfig(metadata.clockId))
+ assertNotNull(provider.getClockPickerConfig(ClockSettings(metadata.clockId)))
}
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
index 5792175d1b67..7d55169e048a 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
@@ -28,6 +28,7 @@ import com.android.systemui.plugins.annotations.SimpleProperty
import java.io.PrintWriter
import java.util.Locale
import java.util.TimeZone
+import org.json.JSONArray
import org.json.JSONObject
/** Identifies a clock design */
@@ -61,7 +62,7 @@ interface ClockProvider {
@ProtectedReturn("return new ClockPickerConfig(\"\", \"\", \"\", null);")
/** Settings configuration parameters for the clock */
- fun getClockPickerConfig(id: ClockId): ClockPickerConfig
+ fun getClockPickerConfig(settings: ClockSettings): ClockPickerConfig
}
/** Interface for controlling an active clock */
@@ -213,7 +214,53 @@ data class ClockFontAxisSetting(
/** Value to set this axis to */
val value: Float,
-)
+) {
+ companion object {
+ private val KEY_AXIS_KEY = "key"
+ private val KEY_AXIS_VALUE = "value"
+
+ fun toJson(setting: ClockFontAxisSetting): JSONObject {
+ return JSONObject().apply {
+ put(KEY_AXIS_KEY, setting.key)
+ put(KEY_AXIS_VALUE, setting.value)
+ }
+ }
+
+ fun toJson(settings: List<ClockFontAxisSetting>): JSONArray {
+ return JSONArray().apply {
+ for (axis in settings) {
+ put(toJson(axis))
+ }
+ }
+ }
+
+ fun fromJson(jsonObj: JSONObject): ClockFontAxisSetting {
+ return ClockFontAxisSetting(
+ key = jsonObj.getString(KEY_AXIS_KEY),
+ value = jsonObj.getDouble(KEY_AXIS_VALUE).toFloat(),
+ )
+ }
+
+ fun fromJson(jsonArray: JSONArray): List<ClockFontAxisSetting> {
+ val result = mutableListOf<ClockFontAxisSetting>()
+ for (i in 0..jsonArray.length() - 1) {
+ val obj = jsonArray.getJSONObject(i)
+ if (obj == null) continue
+ result.add(fromJson(obj))
+ }
+ return result
+ }
+
+ fun toFVar(settings: List<ClockFontAxisSetting>): String {
+ val sb = StringBuilder()
+ for (axis in settings) {
+ if (sb.length > 0) sb.append(", ")
+ sb.append("'${axis.key}' ${axis.value.toInt()}")
+ }
+ return sb.toString()
+ }
+ }
+}
/** Methods which trigger various clock animations */
@ProtectedInterface
@@ -350,6 +397,21 @@ data class ClockFontAxis(
val description: String,
) {
fun toSetting() = ClockFontAxisSetting(key, currentValue)
+
+ companion object {
+ fun merge(
+ fontAxes: List<ClockFontAxis>,
+ axisSettings: List<ClockFontAxisSetting>,
+ ): List<ClockFontAxis> {
+ val result = mutableListOf<ClockFontAxis>()
+ for (axis in fontAxes) {
+ val setting = axisSettings.firstOrNull { axis.key == it.key }
+ val output = setting?.let { axis.copy(currentValue = it.value) } ?: axis
+ result.add(output)
+ }
+ return result
+ }
+ }
}
/** Axis user interaction modes */
@@ -406,7 +468,7 @@ data class ClockFaceConfig(
data class ClockSettings(
val clockId: ClockId? = null,
val seedColor: Int? = null,
- val axes: List<ClockFontAxisSetting>? = null,
+ val axes: List<ClockFontAxisSetting> = listOf(),
) {
// Exclude metadata from equality checks
var metadata: JSONObject = JSONObject()
@@ -415,38 +477,24 @@ data class ClockSettings(
private val KEY_CLOCK_ID = "clockId"
private val KEY_SEED_COLOR = "seedColor"
private val KEY_METADATA = "metadata"
-
- fun serialize(setting: ClockSettings?): String {
- if (setting == null) {
- return ""
+ private val KEY_AXIS_LIST = "axes"
+
+ fun toJson(setting: ClockSettings): JSONObject {
+ return JSONObject().apply {
+ put(KEY_CLOCK_ID, setting.clockId)
+ put(KEY_SEED_COLOR, setting.seedColor)
+ put(KEY_METADATA, setting.metadata)
+ put(KEY_AXIS_LIST, ClockFontAxisSetting.toJson(setting.axes))
}
-
- // TODO(b/364673977): Serialize axes
-
- return JSONObject()
- .put(KEY_CLOCK_ID, setting.clockId)
- .put(KEY_SEED_COLOR, setting.seedColor)
- .put(KEY_METADATA, setting.metadata)
- .toString()
}
- fun deserialize(jsonStr: String?): ClockSettings? {
- if (jsonStr.isNullOrEmpty()) {
- return null
+ fun fromJson(json: JSONObject): ClockSettings {
+ val clockId = if (!json.isNull(KEY_CLOCK_ID)) json.getString(KEY_CLOCK_ID) else null
+ val seedColor = if (!json.isNull(KEY_SEED_COLOR)) json.getInt(KEY_SEED_COLOR) else null
+ val axisList = json.optJSONArray(KEY_AXIS_LIST)?.let(ClockFontAxisSetting::fromJson)
+ return ClockSettings(clockId, seedColor, axisList ?: listOf()).apply {
+ metadata = json.optJSONObject(KEY_METADATA) ?: JSONObject()
}
-
- // TODO(b/364673977): Deserialize axes
-
- val json = JSONObject(jsonStr)
- val result =
- ClockSettings(
- if (!json.isNull(KEY_CLOCK_ID)) json.getString(KEY_CLOCK_ID) else null,
- if (!json.isNull(KEY_SEED_COLOR)) json.getInt(KEY_SEED_COLOR) else null,
- )
- if (!json.isNull(KEY_METADATA)) {
- result.metadata = json.getJSONObject(KEY_METADATA)
- }
- return result
}
}
}