diff options
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 } } } |