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.graphics.Rect
20 import androidx.annotation.VisibleForTesting
21 import com.android.systemui.log.core.Logger
22 import com.android.systemui.plugins.clocks.AlarmData
23 import com.android.systemui.plugins.clocks.ClockAnimations
24 import com.android.systemui.plugins.clocks.ClockEvents
25 import com.android.systemui.plugins.clocks.ClockFaceConfig
26 import com.android.systemui.plugins.clocks.ClockFaceEvents
27 import com.android.systemui.plugins.clocks.ClockFontAxisSetting
28 import com.android.systemui.plugins.clocks.ThemeConfig
29 import com.android.systemui.plugins.clocks.WeatherData
30 import com.android.systemui.plugins.clocks.ZenData
31 import com.android.systemui.shared.clocks.view.FlexClockView
32 import com.android.systemui.shared.clocks.view.SimpleDigitalClockTextView
33 import java.util.Locale
34 import java.util.TimeZone
35 
36 class ComposedDigitalLayerController(
37     private val clockCtx: ClockContext,
38     private val layer: ComposedDigitalHandLayer,
39 ) : SimpleClockLayerController {
40     private val logger =
41         Logger(clockCtx.messageBuffer, ComposedDigitalLayerController::class.simpleName!!)
42 
43     val layerControllers = mutableListOf<SimpleClockLayerController>()
44     val dozeState = DefaultClockController.AnimationState(1F)
45 
46     override val view = FlexClockView(clockCtx)
47 
48     init {
<lambda>null49         layer.digitalLayers.forEach {
50             val childView = SimpleDigitalClockTextView(clockCtx)
51             val controller =
52                 SimpleDigitalHandLayerController(clockCtx, it as DigitalHandLayer, childView)
53 
54             view.addView(childView)
55             layerControllers.add(controller)
56         }
57     }
58 
refreshTimenull59     private fun refreshTime() {
60         layerControllers.forEach { it.faceEvents.onTimeTick() }
61         view.refreshTime()
62     }
63 
64     override val events =
65         object : ClockEvents {
onTimeZoneChangednull66             override fun onTimeZoneChanged(timeZone: TimeZone) {
67                 layerControllers.forEach { it.events.onTimeZoneChanged(timeZone) }
68                 refreshTime()
69             }
70 
onTimeFormatChangednull71             override fun onTimeFormatChanged(is24Hr: Boolean) {
72                 layerControllers.forEach { it.events.onTimeFormatChanged(is24Hr) }
73                 refreshTime()
74             }
75 
onLocaleChangednull76             override fun onLocaleChanged(locale: Locale) {
77                 layerControllers.forEach { it.events.onLocaleChanged(locale) }
78                 view.onLocaleChanged(locale)
79                 refreshTime()
80             }
81 
onWeatherDataChangednull82             override fun onWeatherDataChanged(data: WeatherData) {
83                 view.onWeatherDataChanged(data)
84             }
85 
onAlarmDataChangednull86             override fun onAlarmDataChanged(data: AlarmData) {
87                 view.onAlarmDataChanged(data)
88             }
89 
onZenDataChangednull90             override fun onZenDataChanged(data: ZenData) {
91                 view.onZenDataChanged(data)
92             }
93 
onFontAxesChangednull94             override fun onFontAxesChanged(axes: List<ClockFontAxisSetting>) {
95                 view.updateAxes(axes)
96             }
97 
98             override var isReactiveTouchInteractionEnabled
99                 get() = view.isReactiveTouchInteractionEnabled
100                 set(value) {
101                     view.isReactiveTouchInteractionEnabled = value
102                 }
103         }
104 
105     override val animations =
106         object : ClockAnimations {
enternull107             override fun enter() {
108                 refreshTime()
109             }
110 
dozenull111             override fun doze(fraction: Float) {
112                 val (hasChanged, hasJumped) = dozeState.update(fraction)
113                 if (hasChanged) view.animateDoze(dozeState.isActive, !hasJumped)
114                 view.dozeFraction = fraction
115                 view.invalidate()
116             }
117 
foldnull118             override fun fold(fraction: Float) {
119                 refreshTime()
120             }
121 
chargenull122             override fun charge() {
123                 view.animateCharge()
124             }
125 
onPositionUpdatednull126             override fun onPositionUpdated(fromLeft: Int, direction: Int, fraction: Float) {
127                 view.onPositionUpdated(fromLeft, direction, fraction)
128             }
129 
onPositionUpdatednull130             override fun onPositionUpdated(distance: Float, fraction: Float) {}
131 
onPickerCarouselSwipingnull132             override fun onPickerCarouselSwiping(swipingFraction: Float) {
133                 view.onPickerCarouselSwiping(swipingFraction)
134             }
135         }
136 
137     override val faceEvents =
138         object : ClockFaceEvents {
onTimeTicknull139             override fun onTimeTick() {
140                 refreshTime()
141             }
142 
onThemeChangednull143             override fun onThemeChanged(theme: ThemeConfig) {
144                 val color =
145                     when {
146                         theme.seedColor != null -> theme.seedColor!!
147                         theme.isDarkTheme ->
148                             clockCtx.resources.getColor(android.R.color.system_accent1_100)
149                         else -> clockCtx.resources.getColor(android.R.color.system_accent2_600)
150                     }
151 
152                 view.updateColor(color)
153             }
154 
onFontSettingChangednull155             override fun onFontSettingChanged(fontSizePx: Float) {
156                 view.onFontSettingChanged(fontSizePx)
157             }
158 
onTargetRegionChangednull159             override fun onTargetRegionChanged(targetRegion: Rect?) {}
160 
onSecondaryDisplayChangednull161             override fun onSecondaryDisplayChanged(onSecondaryDisplay: Boolean) {}
162         }
163 
164     override val config =
165         ClockFaceConfig(
166             hasCustomWeatherDataDisplay = view.hasCustomWeatherDataDisplay,
167             hasCustomPositionUpdatedAnimation = view.hasCustomPositionUpdatedAnimation,
168             useCustomClockScene = view.useCustomClockScene,
169         )
170 
171     @VisibleForTesting
172     override var fakeTimeMills: Long? = null
173         get() = field
174         set(timeInMills) {
175             field = timeInMills
176             for (layerController in layerControllers) {
177                 layerController.fakeTimeMills = timeInMills
178             }
179         }
180 }
181