1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 package com.android.systemui.plugins.clocks 15 16 import com.android.internal.annotations.Keep 17 import org.json.JSONArray 18 import org.json.JSONObject 19 20 @Keep 21 /** Structure for keeping clock-specific settings */ 22 data class ClockSettings( 23 val clockId: ClockId? = null, 24 val seedColor: Int? = null, 25 val axes: ClockAxisStyle = ClockAxisStyle(), 26 ) { 27 // Exclude metadata from equality checks 28 var metadata: JSONObject = JSONObject() 29 30 companion object { 31 private val KEY_CLOCK_ID = "clockId" 32 private val KEY_SEED_COLOR = "seedColor" 33 private val KEY_METADATA = "metadata" 34 private val KEY_AXIS_LIST = "axes" 35 toJsonnull36 fun toJson(setting: ClockSettings): JSONObject { 37 return JSONObject().apply { 38 put(KEY_CLOCK_ID, setting.clockId) 39 put(KEY_SEED_COLOR, setting.seedColor) 40 put(KEY_METADATA, setting.metadata) 41 put(KEY_AXIS_LIST, ClockAxisStyle.toJson(setting.axes)) 42 } 43 } 44 fromJsonnull45 fun fromJson(json: JSONObject): ClockSettings { 46 val clockId = if (!json.isNull(KEY_CLOCK_ID)) json.getString(KEY_CLOCK_ID) else null 47 val seedColor = if (!json.isNull(KEY_SEED_COLOR)) json.getInt(KEY_SEED_COLOR) else null 48 val axisList = json.optJSONArray(KEY_AXIS_LIST)?.let(ClockAxisStyle::fromJson) 49 return ClockSettings(clockId, seedColor, axisList ?: ClockAxisStyle()).apply { 50 metadata = json.optJSONObject(KEY_METADATA) ?: JSONObject() 51 } 52 } 53 } 54 } 55 56 @Keep 57 class ClockAxisStyle { 58 private val settings: MutableMap<String, Float> 59 60 // Iterable would be implemented on ClockAxisStyle directly, 61 // but that doesn't appear to work with plugins/dynamic libs. 62 val items: Iterable<Map.Entry<String, Float>> 63 get() = settings.asIterable() 64 65 val isEmpty: Boolean 66 get() = settings.isEmpty() 67 <lambda>null68 constructor(initialize: ClockAxisStyle.() -> Unit = {}) { 69 settings = mutableMapOf() 70 this.initialize() 71 } 72 73 constructor(style: ClockAxisStyle) { 74 settings = style.settings.toMutableMap() 75 } 76 77 constructor(items: Map<String, Float>) { 78 settings = items.toMutableMap() 79 } 80 81 constructor(key: String, value: Float) { 82 settings = mutableMapOf(key to value) 83 } 84 85 constructor(items: List<ClockFontAxis>) { <lambda>null86 settings = items.associate { it.key to it.currentValue }.toMutableMap() 87 } 88 copynull89 fun copy(initialize: ClockAxisStyle.() -> Unit): ClockAxisStyle { 90 return ClockAxisStyle(this).apply { initialize() } 91 } 92 getnull93 operator fun get(key: String): Float? = settings[key] 94 95 operator fun set(key: String, value: Float) = put(key, value) 96 97 fun put(key: String, value: Float) { 98 settings.put(key, value) 99 } 100 toFVarnull101 fun toFVar(): String { 102 val sb = StringBuilder() 103 for (axis in settings) { 104 if (sb.length > 0) sb.append(", ") 105 sb.append("'${axis.key}' ${axis.value.toInt()}") 106 } 107 return sb.toString() 108 } 109 copyWithnull110 fun copyWith(replacements: ClockAxisStyle): ClockAxisStyle { 111 val result = ClockAxisStyle(this) 112 for ((key, value) in replacements.settings) { 113 result[key] = value 114 } 115 return result 116 } 117 equalsnull118 override fun equals(other: Any?): Boolean { 119 if (this === other) return true 120 if (other !is ClockAxisStyle) return false 121 return settings == other.settings 122 } 123 124 companion object { 125 private val KEY_AXIS_KEY = "key" 126 private val KEY_AXIS_VALUE = "value" 127 fromJsonnull128 fun fromJson(jsonArray: JSONArray): ClockAxisStyle { 129 val result = ClockAxisStyle() 130 for (i in 0..jsonArray.length() - 1) { 131 val obj = jsonArray.getJSONObject(i) 132 if (obj == null) continue 133 134 result.put( 135 key = obj.getString(KEY_AXIS_KEY), 136 value = obj.getDouble(KEY_AXIS_VALUE).toFloat(), 137 ) 138 } 139 return result 140 } 141 toJsonnull142 fun toJson(style: ClockAxisStyle): JSONArray { 143 return JSONArray().apply { 144 for ((key, value) in style.settings) { 145 put( 146 JSONObject().apply { 147 put(KEY_AXIS_KEY, key) 148 put(KEY_AXIS_VALUE, value) 149 } 150 ) 151 } 152 } 153 } 154 } 155 } 156