• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.shared.clocks
18 
19 import android.content.res.Resources
20 import com.android.systemui.animation.GSFAxes
21 import com.android.systemui.customization.R
22 import com.android.systemui.plugins.clocks.AlarmData
23 import com.android.systemui.plugins.clocks.AxisPresetConfig
24 import com.android.systemui.plugins.clocks.AxisType
25 import com.android.systemui.plugins.clocks.ClockAxisStyle
26 import com.android.systemui.plugins.clocks.ClockConfig
27 import com.android.systemui.plugins.clocks.ClockController
28 import com.android.systemui.plugins.clocks.ClockEventListener
29 import com.android.systemui.plugins.clocks.ClockEvents
30 import com.android.systemui.plugins.clocks.ClockFontAxis
31 import com.android.systemui.plugins.clocks.ClockFontAxis.Companion.merge
32 import com.android.systemui.plugins.clocks.ClockSettings
33 import com.android.systemui.plugins.clocks.WeatherData
34 import com.android.systemui.plugins.clocks.ZenData
35 import com.android.systemui.shared.clocks.FontUtils.put
36 import com.android.systemui.shared.clocks.FontUtils.toClockAxis
37 import com.android.systemui.shared.clocks.view.FlexClockView
38 import java.io.PrintWriter
39 import java.util.Locale
40 import java.util.TimeZone
41 
42 /** Controller for the default flex clock */
43 class FlexClockController(private val clockCtx: ClockContext) : ClockController {
44     override val smallClock =
45         FlexClockFaceController(
46             clockCtx.copy(messageBuffer = clockCtx.messageBuffers.smallClockMessageBuffer),
47             isLargeClock = false,
48         )
49 
50     override val largeClock =
51         FlexClockFaceController(
52             clockCtx.copy(messageBuffer = clockCtx.messageBuffers.largeClockMessageBuffer),
53             isLargeClock = true,
54         )
55 
<lambda>null56     override val config: ClockConfig by lazy {
57         ClockConfig(
58             DEFAULT_CLOCK_ID,
59             clockCtx.resources.getString(R.string.clock_default_name),
60             clockCtx.resources.getString(R.string.clock_default_description),
61         )
62     }
63 
64     override val events =
65         object : ClockEvents {
66             override var isReactiveTouchInteractionEnabled = false
67                 set(value) {
68                     field = value
69                     val view = largeClock.view as FlexClockView
70                     view.isReactiveTouchInteractionEnabled = value
71                 }
72 
onTimeZoneChangednull73             override fun onTimeZoneChanged(timeZone: TimeZone) {
74                 smallClock.events.onTimeZoneChanged(timeZone)
75                 largeClock.events.onTimeZoneChanged(timeZone)
76             }
77 
onTimeFormatChangednull78             override fun onTimeFormatChanged(is24Hr: Boolean) {
79                 smallClock.events.onTimeFormatChanged(is24Hr)
80                 largeClock.events.onTimeFormatChanged(is24Hr)
81             }
82 
onLocaleChangednull83             override fun onLocaleChanged(locale: Locale) {
84                 smallClock.events.onLocaleChanged(locale)
85                 largeClock.events.onLocaleChanged(locale)
86             }
87 
onWeatherDataChangednull88             override fun onWeatherDataChanged(data: WeatherData) {
89                 smallClock.events.onWeatherDataChanged(data)
90                 largeClock.events.onWeatherDataChanged(data)
91             }
92 
onAlarmDataChangednull93             override fun onAlarmDataChanged(data: AlarmData) {
94                 smallClock.events.onAlarmDataChanged(data)
95                 largeClock.events.onAlarmDataChanged(data)
96             }
97 
onZenDataChangednull98             override fun onZenDataChanged(data: ZenData) {
99                 smallClock.events.onZenDataChanged(data)
100                 largeClock.events.onZenDataChanged(data)
101             }
102         }
103 
initializenull104     override fun initialize(
105         isDarkTheme: Boolean,
106         dozeFraction: Float,
107         foldFraction: Float,
108         clockListener: ClockEventListener?,
109     ) {
110         smallClock.run {
111             layerController.onViewBoundsChanged = { clockListener?.onBoundsChanged(it) }
112             events.onThemeChanged(theme.copy(isDarkTheme = isDarkTheme))
113             animations.onFontAxesChanged(clockCtx.settings.axes)
114             animations.doze(dozeFraction)
115             animations.fold(foldFraction)
116             events.onTimeTick()
117         }
118 
119         largeClock.run {
120             layerController.onViewBoundsChanged = { clockListener?.onBoundsChanged(it) }
121             events.onThemeChanged(theme.copy(isDarkTheme = isDarkTheme))
122             animations.onFontAxesChanged(clockCtx.settings.axes)
123             animations.doze(dozeFraction)
124             animations.fold(foldFraction)
125             events.onTimeTick()
126         }
127     }
128 
dumpnull129     override fun dump(pw: PrintWriter) {}
130 
131     companion object {
getDefaultAxesnull132         fun getDefaultAxes(settings: ClockSettings): List<ClockFontAxis> {
133             return if (settings.clockId == FLEX_CLOCK_ID) {
134                 FONT_AXES.merge(LEGACY_FLEX_SETTINGS)
135             } else FONT_AXES
136         }
137 
138         private val FONT_AXES =
139             listOf(
140                 GSFAxes.WEIGHT.toClockAxis(
141                     type = AxisType.Float,
142                     currentValue = 400f,
143                     name = "Weight",
144                     description = "Glyph Weight",
145                 ),
146                 GSFAxes.WIDTH.toClockAxis(
147                     type = AxisType.Float,
148                     currentValue = 80f,
149                     name = "Width",
150                     description = "Glyph Width",
151                 ),
152                 GSFAxes.ROUND.toClockAxis(
153                     type = AxisType.Boolean,
154                     currentValue = 100f,
155                     name = "Round",
156                     description = "Glyph Roundness",
157                 ),
158                 GSFAxes.SLANT.toClockAxis(
159                     type = AxisType.Boolean,
160                     currentValue = 0f,
161                     name = "Slant",
162                     description = "Glyph Slant",
163                 ),
164             )
165 
<lambda>null166         private val LEGACY_FLEX_SETTINGS = ClockAxisStyle {
167             put(GSFAxes.WEIGHT, 600f)
168             put(GSFAxes.WIDTH, 100f)
169             put(GSFAxes.ROUND, 100f)
170             put(GSFAxes.SLANT, 0f)
171         }
172 
173         private val PRESET_COUNT = 8
174         private val PRESET_WIDTH_INIT = 30f
175         private val PRESET_WIDTH_STEP = 12.5f
176         private val PRESET_WEIGHT_INIT = 800f
177         private val PRESET_WEIGHT_STEP = -100f
<lambda>null178         private val BASE_PRESETS: List<ClockAxisStyle> = run {
179             val presets = mutableListOf<ClockAxisStyle>()
180             var weight = PRESET_WEIGHT_INIT
181             var width = PRESET_WIDTH_INIT
182             for (i in 1..PRESET_COUNT) {
183                 presets.add(
184                     ClockAxisStyle {
185                         put(GSFAxes.WEIGHT, weight)
186                         put(GSFAxes.WIDTH, width)
187                         put(GSFAxes.ROUND, 0f)
188                         put(GSFAxes.SLANT, 0f)
189                     }
190                 )
191 
192                 weight += PRESET_WEIGHT_STEP
193                 width += PRESET_WIDTH_STEP
194             }
195 
196             return@run presets
197         }
198 
buildPresetGroupnull199         fun buildPresetGroup(resources: Resources, isRound: Boolean): AxisPresetConfig.Group {
200             val round = if (isRound) GSFAxes.ROUND.maxValue else GSFAxes.ROUND.minValue
201             return AxisPresetConfig.Group(
202                 presets = BASE_PRESETS.map { it.copy { put(GSFAxes.ROUND, round) } },
203                 // TODO(b/395647577): Placeholder Icon; Replace or remove
204                 icon = resources.getDrawable(R.drawable.clock_default_thumbnail, null),
205             )
206         }
207     }
208 }
209