• 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.graphics.Rect
20 import androidx.annotation.VisibleForTesting
21 import com.android.app.animation.Interpolators
22 import com.android.systemui.log.core.Logger
23 import com.android.systemui.plugins.clocks.AlarmData
24 import com.android.systemui.plugins.clocks.ClockAnimations
25 import com.android.systemui.plugins.clocks.ClockAxisStyle
26 import com.android.systemui.plugins.clocks.ClockEvents
27 import com.android.systemui.plugins.clocks.ClockFaceConfig
28 import com.android.systemui.plugins.clocks.ClockFaceEvents
29 import com.android.systemui.plugins.clocks.ThemeConfig
30 import com.android.systemui.plugins.clocks.WeatherData
31 import com.android.systemui.plugins.clocks.ZenData
32 import com.android.systemui.shared.clocks.view.FlexClockView
33 import com.android.systemui.shared.clocks.view.HorizontalAlignment
34 import com.android.systemui.shared.clocks.view.VerticalAlignment
35 import java.util.Locale
36 import java.util.TimeZone
37 
38 class ComposedDigitalLayerController(private val clockCtx: ClockContext) :
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     override var onViewBoundsChanged by view::onViewBoundsChanged
48 
49     init {
createControllernull50         fun createController(cfg: LayerConfig) {
51             val controller = SimpleDigitalHandLayerController(clockCtx, cfg, isLargeClock = true)
52             view.addView(controller.view)
53             layerControllers.add(controller)
54         }
55 
56         val layerCfg =
57             LayerConfig(
58                 style = FontTextStyle(lineHeight = 147.25f),
59                 alignment = DigitalAlignment(HorizontalAlignment.CENTER, VerticalAlignment.CENTER),
60                 aodStyle =
61                     FontTextStyle(
62                         transitionInterpolator = Interpolators.EMPHASIZED,
63                         transitionDuration = 750,
64                     ),
65 
66                 // Placeholders
67                 timespec = DigitalTimespec.TIME_FULL_FORMAT,
68                 dateTimeFormat = "hh:mm",
69             )
70 
71         createController(
72             layerCfg.copy(timespec = DigitalTimespec.FIRST_DIGIT, dateTimeFormat = "hh")
73         )
74         createController(
75             layerCfg.copy(timespec = DigitalTimespec.SECOND_DIGIT, dateTimeFormat = "hh")
76         )
77         createController(
78             layerCfg.copy(timespec = DigitalTimespec.FIRST_DIGIT, dateTimeFormat = "mm")
79         )
80         createController(
81             layerCfg.copy(timespec = DigitalTimespec.SECOND_DIGIT, dateTimeFormat = "mm")
82         )
83     }
84 
refreshTimenull85     private fun refreshTime() {
86         layerControllers.forEach { it.faceEvents.onTimeTick() }
87         view.refreshTime()
88     }
89 
90     override val events =
91         object : ClockEvents {
onTimeZoneChangednull92             override fun onTimeZoneChanged(timeZone: TimeZone) {
93                 layerControllers.forEach { it.events.onTimeZoneChanged(timeZone) }
94                 refreshTime()
95             }
96 
onTimeFormatChangednull97             override fun onTimeFormatChanged(is24Hr: Boolean) {
98                 layerControllers.forEach { it.events.onTimeFormatChanged(is24Hr) }
99                 refreshTime()
100             }
101 
onLocaleChangednull102             override fun onLocaleChanged(locale: Locale) {
103                 layerControllers.forEach { it.events.onLocaleChanged(locale) }
104                 view.onLocaleChanged(locale)
105                 refreshTime()
106             }
107 
onWeatherDataChangednull108             override fun onWeatherDataChanged(data: WeatherData) {}
109 
onAlarmDataChangednull110             override fun onAlarmDataChanged(data: AlarmData) {}
111 
onZenDataChangednull112             override fun onZenDataChanged(data: ZenData) {}
113 
114             override var isReactiveTouchInteractionEnabled
115                 get() = view.isReactiveTouchInteractionEnabled
116                 set(value) {
117                     view.isReactiveTouchInteractionEnabled = value
118                 }
119         }
120 
121     override val animations =
122         object : ClockAnimations {
enternull123             override fun enter() {
124                 refreshTime()
125             }
126 
dozenull127             override fun doze(fraction: Float) {
128                 val (hasChanged, hasJumped) = dozeState.update(fraction)
129                 if (hasChanged) view.animateDoze(dozeState.isActive, !hasJumped)
130                 view.dozeFraction = fraction
131                 view.invalidate()
132             }
133 
foldnull134             override fun fold(fraction: Float) {
135                 refreshTime()
136             }
137 
chargenull138             override fun charge() {
139                 view.animateCharge()
140             }
141 
onPositionUpdatednull142             override fun onPositionUpdated(fromLeft: Int, direction: Int, fraction: Float) {}
143 
onPositionUpdatednull144             override fun onPositionUpdated(distance: Float, fraction: Float) {}
145 
onPickerCarouselSwipingnull146             override fun onPickerCarouselSwiping(swipingFraction: Float) {}
147 
onFidgetTapnull148             override fun onFidgetTap(x: Float, y: Float) {
149                 view.animateFidget(x, y)
150             }
151 
152             private var hasFontAxes = false
153 
onFontAxesChangednull154             override fun onFontAxesChanged(style: ClockAxisStyle) {
155                 view.updateAxes(style, isAnimated = hasFontAxes)
156                 hasFontAxes = true
157             }
158         }
159 
160     override val faceEvents =
161         object : ClockFaceEvents {
onTimeTicknull162             override fun onTimeTick() {
163                 refreshTime()
164             }
165 
onThemeChangednull166             override fun onThemeChanged(theme: ThemeConfig) {
167                 view.updateColor(theme.getDefaultColor(clockCtx.context))
168             }
169 
onFontSettingChangednull170             override fun onFontSettingChanged(fontSizePx: Float) {
171                 view.onFontSettingChanged(fontSizePx)
172             }
173 
onTargetRegionChangednull174             override fun onTargetRegionChanged(targetRegion: Rect?) {}
175 
onSecondaryDisplayChangednull176             override fun onSecondaryDisplayChanged(onSecondaryDisplay: Boolean) {}
177         }
178 
179     override val config =
180         ClockFaceConfig(
181             hasCustomWeatherDataDisplay = false,
182             hasCustomPositionUpdatedAnimation = true,
183         )
184 
185     @VisibleForTesting
186     override var fakeTimeMills: Long? = null
187         get() = field
188         set(timeInMills) {
189             field = timeInMills
190             for (layerController in layerControllers) {
191                 layerController.fakeTimeMills = timeInMills
192             }
193         }
194 }
195