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