• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2022 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.shared.clocks
15 
16 import android.content.Context
17 import android.content.res.Resources
18 import android.graphics.Typeface
19 import android.os.Vibrator
20 import android.view.LayoutInflater
21 import com.android.systemui.customization.R
22 import com.android.systemui.log.core.MessageBuffer
23 import com.android.systemui.plugins.clocks.AxisPresetConfig
24 import com.android.systemui.plugins.clocks.ClockAxisStyle
25 import com.android.systemui.plugins.clocks.ClockController
26 import com.android.systemui.plugins.clocks.ClockFontAxis.Companion.merge
27 import com.android.systemui.plugins.clocks.ClockLogger
28 import com.android.systemui.plugins.clocks.ClockMessageBuffers
29 import com.android.systemui.plugins.clocks.ClockMetadata
30 import com.android.systemui.plugins.clocks.ClockPickerConfig
31 import com.android.systemui.plugins.clocks.ClockProvider
32 import com.android.systemui.plugins.clocks.ClockSettings
33 import com.android.systemui.shared.clocks.FlexClockController.Companion.buildPresetGroup
34 import com.android.systemui.shared.clocks.FlexClockController.Companion.getDefaultAxes
35 
36 private val TAG = DefaultClockProvider::class.simpleName
37 const val DEFAULT_CLOCK_ID = "DEFAULT"
38 const val FLEX_CLOCK_ID = "DIGITAL_CLOCK_FLEX"
39 
40 data class ClockContext(
41     val context: Context,
42     val resources: Resources,
43     val settings: ClockSettings,
44     val typefaceCache: TypefaceCache,
45     val messageBuffers: ClockMessageBuffers,
46     val messageBuffer: MessageBuffer,
47     val vibrator: Vibrator?,
48 )
49 
50 /** Provides the default system clock */
51 class DefaultClockProvider(
52     val ctx: Context,
53     val layoutInflater: LayoutInflater,
54     val resources: Resources,
55     private val isClockReactiveVariantsEnabled: Boolean = false,
56     private val vibrator: Vibrator?,
57 ) : ClockProvider {
58     private var messageBuffers: ClockMessageBuffers? = null
59 
60     override fun initialize(buffers: ClockMessageBuffers?) {
61         messageBuffers = buffers
62     }
63 
64     override fun getClocks(): List<ClockMetadata> {
65         var clocks = listOf(ClockMetadata(DEFAULT_CLOCK_ID))
66         if (isClockReactiveVariantsEnabled) {
67             clocks +=
68                 ClockMetadata(
69                     FLEX_CLOCK_ID,
70                     isDeprecated = true,
71                     replacementTarget = DEFAULT_CLOCK_ID,
72                 )
73         }
74         return clocks
75     }
76 
77     override fun createClock(settings: ClockSettings): ClockController {
78         if (getClocks().all { it.clockId != settings.clockId }) {
79             throw IllegalArgumentException("${settings.clockId} is unsupported by $TAG")
80         }
81 
82         return if (isClockReactiveVariantsEnabled) {
83             val buffers = messageBuffers ?: ClockMessageBuffers(ClockLogger.DEFAULT_MESSAGE_BUFFER)
84             val fontAxes = getDefaultAxes(settings).merge(settings.axes)
85             val clockSettings = settings.copy(axes = ClockAxisStyle(fontAxes))
86             val typefaceCache =
87                 TypefaceCache(buffers.infraMessageBuffer, NUM_CLOCK_FONT_ANIMATION_STEPS) {
88                     FLEX_TYPEFACE
89                 }
90             FlexClockController(
91                 ClockContext(
92                     ctx,
93                     resources,
94                     clockSettings,
95                     typefaceCache,
96                     buffers,
97                     buffers.infraMessageBuffer,
98                     vibrator,
99                 )
100             )
101         } else {
102             DefaultClockController(ctx, layoutInflater, resources, settings, messageBuffers)
103         }
104     }
105 
106     override fun getClockPickerConfig(settings: ClockSettings): ClockPickerConfig {
107         if (getClocks().all { it.clockId != settings.clockId }) {
108             throw IllegalArgumentException("${settings.clockId} is unsupported by $TAG")
109         }
110 
111         if (!isClockReactiveVariantsEnabled) {
112             return ClockPickerConfig(
113                 settings.clockId ?: DEFAULT_CLOCK_ID,
114                 resources.getString(R.string.clock_default_name),
115                 resources.getString(R.string.clock_default_description),
116                 resources.getDrawable(R.drawable.clock_default_thumbnail, null),
117                 isReactiveToTone = true,
118                 axes = emptyList(),
119                 presetConfig = null,
120             )
121         } else {
122             val fontAxes = getDefaultAxes(settings).merge(settings.axes)
123             return ClockPickerConfig(
124                 settings.clockId ?: DEFAULT_CLOCK_ID,
125                 resources.getString(R.string.clock_default_name),
126                 resources.getString(R.string.clock_default_description),
127                 resources.getDrawable(R.drawable.clock_default_thumbnail, null),
128                 isReactiveToTone = true,
129                 axes = fontAxes,
130                 presetConfig =
131                     AxisPresetConfig(
132                             listOf(
133                                 buildPresetGroup(resources, isRound = true),
134                                 buildPresetGroup(resources, isRound = false),
135                             )
136                         )
137                         .let { cfg -> cfg.copy(current = cfg.findStyle(ClockAxisStyle(fontAxes))) },
138             )
139         }
140     }
141 
142     companion object {
143         // 750ms @ 120hz -> 90 frames of animation
144         // In practice, 30 looks good enough and limits our memory usage
145         const val NUM_CLOCK_FONT_ANIMATION_STEPS = 30
146 
147         val FLEX_TYPEFACE by lazy {
148             // TODO(b/364680873): Move constant to config_clockFontFamily when shipping
149             Typeface.create("google-sans-flex-clock", Typeface.NORMAL)
150         }
151     }
152 }
153