summaryrefslogtreecommitdiff
path: root/src/com/android/customization/picker/clock
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/customization/picker/clock')
-rw-r--r--src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt3
-rw-r--r--src/com/android/customization/picker/clock/shared/ClockSize.kt11
-rw-r--r--src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt1
-rw-r--r--src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt10
-rw-r--r--src/com/android/customization/picker/clock/ui/binder/ClockSectionViewBinder.kt53
-rw-r--r--src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt81
-rw-r--r--src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt20
-rw-r--r--src/com/android/customization/picker/clock/ui/section/ClockSectionController.kt62
-rw-r--r--src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt4
-rw-r--r--src/com/android/customization/picker/clock/ui/view/ClockSizeRadioButtonGroup.kt50
-rw-r--r--src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt212
-rw-r--r--src/com/android/customization/picker/clock/ui/view/ClockViewFactoryImpl.kt240
-rw-r--r--src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselItemViewModel.kt22
-rw-r--r--src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt26
-rw-r--r--src/com/android/customization/picker/clock/ui/viewmodel/ClockSectionViewModel.kt51
-rw-r--r--src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt42
-rw-r--r--src/com/android/customization/picker/clock/utils/ClockDescriptionUtils.kt26
-rw-r--r--src/com/android/customization/picker/clock/utils/ThemePickerClockDescriptionUtils.kt22
18 files changed, 405 insertions, 531 deletions
diff --git a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
index 004103f3..cc4079a1 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
@@ -21,7 +21,7 @@ import androidx.annotation.ColorInt
import androidx.annotation.IntRange
import com.android.customization.picker.clock.shared.ClockSize
import com.android.customization.picker.clock.shared.model.ClockMetadataModel
-import com.android.systemui.plugins.ClockMetadata
+import com.android.systemui.plugins.clocks.ClockMetadata
import com.android.systemui.shared.clocks.ClockRegistry
import com.android.wallpaper.settings.data.repository.SecureSettingsRepository
import kotlinx.coroutines.CoroutineDispatcher
@@ -187,7 +187,6 @@ class ClockPickerRepositoryImpl(
): ClockMetadataModel {
return ClockMetadataModel(
clockId = clockId,
- name = name,
isSelected = isSelected,
selectedColorId = selectedColorId,
colorToneProgress = colorTone,
diff --git a/src/com/android/customization/picker/clock/shared/ClockSize.kt b/src/com/android/customization/picker/clock/shared/ClockSize.kt
index 279ee54b..9b35f73f 100644
--- a/src/com/android/customization/picker/clock/shared/ClockSize.kt
+++ b/src/com/android/customization/picker/clock/shared/ClockSize.kt
@@ -16,7 +16,18 @@
*/
package com.android.customization.picker.clock.shared
+import android.stats.style.StyleEnums
+import com.android.customization.module.logging.ThemesUserEventLogger
+
enum class ClockSize {
DYNAMIC,
SMALL,
}
+
+@ThemesUserEventLogger.ClockSize
+fun ClockSize.toClockSizeForLogging(): Int {
+ return when (this) {
+ ClockSize.DYNAMIC -> StyleEnums.CLOCK_SIZE_DYNAMIC
+ ClockSize.SMALL -> StyleEnums.CLOCK_SIZE_SMALL
+ }
+}
diff --git a/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt b/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt
index 25225075..6e2bfb38 100644
--- a/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt
+++ b/src/com/android/customization/picker/clock/shared/model/ClockMetadataModel.kt
@@ -23,7 +23,6 @@ import androidx.annotation.IntRange
/** Model for clock metadata. */
data class ClockMetadataModel(
val clockId: String,
- val name: String,
val isSelected: Boolean,
val selectedColorId: String?,
@IntRange(from = 0, to = 100) val colorToneProgress: Int,
diff --git a/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt b/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt
index 6bd717b7..e2616c76 100644
--- a/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt
+++ b/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt
@@ -58,11 +58,6 @@ object ClockCarouselViewBinder {
carouselView.transitionToPrevious()
}
)
- screenPreviewClickView.accessibilityDelegate = carouselAccessibilityDelegate
- screenPreviewClickView.setOnSideClickedListener { isStart ->
- if (isStart) carouselView.scrollToPrevious() else carouselView.scrollToNext()
- }
-
lifecycleOwner.lifecycleScope.launch {
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
@@ -76,6 +71,11 @@ object ClockCarouselViewBinder {
},
isTwoPaneAndSmallWidth = isTwoPaneAndSmallWidth,
)
+ screenPreviewClickView.accessibilityDelegate = carouselAccessibilityDelegate
+ screenPreviewClickView.setOnSideClickedListener { isStart ->
+ if (isStart) carouselView.scrollToPrevious()
+ else carouselView.scrollToNext()
+ }
}
}
diff --git a/src/com/android/customization/picker/clock/ui/binder/ClockSectionViewBinder.kt b/src/com/android/customization/picker/clock/ui/binder/ClockSectionViewBinder.kt
deleted file mode 100644
index 7dc0d0c4..00000000
--- a/src/com/android/customization/picker/clock/ui/binder/ClockSectionViewBinder.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.customization.picker.clock.ui.binder
-
-import android.view.View
-import android.widget.TextView
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.lifecycleScope
-import androidx.lifecycle.repeatOnLifecycle
-import com.android.customization.picker.clock.ui.viewmodel.ClockSectionViewModel
-import com.android.wallpaper.R
-import kotlinx.coroutines.flow.collectLatest
-import kotlinx.coroutines.launch
-
-object ClockSectionViewBinder {
- fun bind(
- view: View,
- viewModel: ClockSectionViewModel,
- lifecycleOwner: LifecycleOwner,
- onClicked: () -> Unit,
- ) {
- view.setOnClickListener { onClicked() }
-
- val selectedClockColorAndSize: TextView =
- view.requireViewById(R.id.selected_clock_color_and_size)
-
- lifecycleOwner.lifecycleScope.launch {
- lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
- launch {
- viewModel.selectedClockColorAndSizeText.collectLatest {
- selectedClockColorAndSize.text = it
- }
- }
- }
- }
- }
-}
diff --git a/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
index 6e745d54..d17cdf8a 100644
--- a/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
+++ b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
@@ -15,11 +15,18 @@
*/
package com.android.customization.picker.clock.ui.binder
+import android.content.Context
import android.content.res.Configuration
+import android.text.Spannable
+import android.text.SpannableString
+import android.text.style.TextAppearanceSpan
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
+import android.widget.RadioButton
+import android.widget.RadioGroup
+import android.widget.RadioGroup.OnCheckedChangeListener
import android.widget.SeekBar
import androidx.core.view.doOnPreDraw
import androidx.core.view.isInvisible
@@ -35,7 +42,6 @@ import com.android.customization.picker.clock.shared.ClockSize
import com.android.customization.picker.clock.ui.adapter.ClockSettingsTabAdapter
import com.android.customization.picker.clock.ui.view.ClockCarouselView
import com.android.customization.picker.clock.ui.view.ClockHostView
-import com.android.customization.picker.clock.ui.view.ClockSizeRadioButtonGroup
import com.android.customization.picker.clock.ui.view.ClockViewFactory
import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel
import com.android.customization.picker.color.ui.binder.ColorOptionIconBinder
@@ -83,14 +89,27 @@ object ClockSettingsBinder {
}
)
- val sizeOptions =
- view.requireViewById<ClockSizeRadioButtonGroup>(R.id.clock_size_radio_button_group)
- sizeOptions.onRadioButtonClickListener =
- object : ClockSizeRadioButtonGroup.OnRadioButtonClickListener {
- override fun onClick(size: ClockSize) {
- viewModel.setClockSize(size)
- }
+ val onCheckedChangeListener = OnCheckedChangeListener { _, id ->
+ when (id) {
+ R.id.radio_dynamic -> viewModel.setClockSize(ClockSize.DYNAMIC)
+ R.id.radio_small -> viewModel.setClockSize(ClockSize.SMALL)
}
+ }
+ val clockSizeRadioGroup =
+ view.requireViewById<RadioGroup>(R.id.clock_size_radio_button_group)
+ clockSizeRadioGroup.setOnCheckedChangeListener(onCheckedChangeListener)
+ view.requireViewById<RadioButton>(R.id.radio_dynamic).text =
+ getRadioText(
+ view.context.applicationContext,
+ view.resources.getString(R.string.clock_size_dynamic),
+ view.resources.getString(R.string.clock_size_dynamic_description)
+ )
+ view.requireViewById<RadioButton>(R.id.radio_small).text =
+ getRadioText(
+ view.context.applicationContext,
+ view.resources.getString(R.string.clock_size_small),
+ view.resources.getString(R.string.clock_size_small_description)
+ )
val colorOptionContainer = view.requireViewById<View>(R.id.color_picker_container)
lifecycleOwner.lifecycleScope.launch {
@@ -110,11 +129,11 @@ object ClockSettingsBinder {
when (tab) {
ClockSettingsViewModel.Tab.COLOR -> {
colorOptionContainer.isVisible = true
- sizeOptions.isInvisible = true
+ clockSizeRadioGroup.isInvisible = true
}
ClockSettingsViewModel.Tab.SIZE -> {
colorOptionContainer.isInvisible = true
- sizeOptions.isVisible = true
+ clockSizeRadioGroup.isVisible = true
}
}
}
@@ -122,6 +141,7 @@ object ClockSettingsBinder {
launch {
viewModel.colorOptions.collect { colorOptions ->
+ colorOptionContainerListView.removeAllViews()
colorOptions.forEachIndexed { index, colorOption ->
colorOption.payload?.let { payload ->
val item =
@@ -189,16 +209,28 @@ object ClockSettingsBinder {
clockHostView.addView(clockView)
when (size) {
ClockSize.DYNAMIC -> {
- sizeOptions.radioButtonDynamic.isChecked = true
- sizeOptions.radioButtonSmall.isChecked = false
+ // When clock size data flow emits clock size signal, we want
+ // to update the view without triggering on checked change,
+ // which is supposed to be triggered by user interaction only.
+ clockSizeRadioGroup.setOnCheckedChangeListener(null)
+ clockSizeRadioGroup.check(R.id.radio_dynamic)
+ clockSizeRadioGroup.setOnCheckedChangeListener(
+ onCheckedChangeListener
+ )
clockHostView.doOnPreDraw {
it.pivotX = it.width / 2F
it.pivotY = it.height / 2F
}
}
ClockSize.SMALL -> {
- sizeOptions.radioButtonDynamic.isChecked = false
- sizeOptions.radioButtonSmall.isChecked = true
+ // When clock size data flow emits clock size signal, we want
+ // to update the view without triggering on checked change,
+ // which is supposed to be triggered by user interaction only.
+ clockSizeRadioGroup.setOnCheckedChangeListener(null)
+ clockSizeRadioGroup.check(R.id.radio_small)
+ clockSizeRadioGroup.setOnCheckedChangeListener(
+ onCheckedChangeListener
+ )
clockHostView.doOnPreDraw {
it.pivotX = ClockCarouselView.getCenteredHostViewPivotX(it)
it.pivotY = 0F
@@ -238,4 +270,25 @@ object ClockSettingsBinder {
}
)
}
+
+ private fun getRadioText(
+ context: Context,
+ title: String,
+ description: String
+ ): SpannableString {
+ val text = SpannableString(title + "\n" + description)
+ text.setSpan(
+ TextAppearanceSpan(context, R.style.SectionTitleTextStyle),
+ 0,
+ title.length,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
+ )
+ text.setSpan(
+ TextAppearanceSpan(context, R.style.SectionSubtitleTextStyle),
+ title.length + 1,
+ title.length + 1 + description.length,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
+ )
+ return text
+ }
}
diff --git a/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt b/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
index 4805f376..dc70633e 100644
--- a/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
+++ b/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
@@ -68,7 +68,7 @@ class ClockSettingsFragment : AppbarFragment() {
val injector = InjectorProvider.getInjector() as ThemePickerInjector
val lockScreenView: CardView = view.requireViewById(R.id.lock_preview)
- val colorViewModel = injector.getWallpaperColorsViewModel()
+ val wallpaperColorsRepository = injector.getWallpaperColorsRepository()
val displayUtils = injector.getDisplayUtils(context)
ScreenPreviewBinder.bind(
activity = activity,
@@ -88,18 +88,18 @@ class ClockSettingsFragment : AppbarFragment() {
injector
.getCurrentWallpaperInfoFactory(context)
.createCurrentWallpaperInfos(
- { homeWallpaper, lockWallpaper, _ ->
- continuation.resume(
- lockWallpaper ?: homeWallpaper,
- null,
- )
- },
+ context,
forceReload,
- )
+ ) { homeWallpaper, lockWallpaper, _ ->
+ continuation.resume(
+ lockWallpaper ?: homeWallpaper,
+ null,
+ )
+ }
}
},
onWallpaperColorChanged = { colors ->
- colorViewModel.setLockWallpaperColors(colors)
+ wallpaperColorsRepository.setLockWallpaperColors(colors)
},
initialExtrasProvider = {
Bundle().apply {
@@ -125,7 +125,7 @@ class ClockSettingsFragment : AppbarFragment() {
this,
injector.getClockSettingsViewModelFactory(
context,
- injector.getWallpaperColorsViewModel(),
+ injector.getWallpaperColorsRepository(),
injector.getClockViewFactory(activity),
),
)
diff --git a/src/com/android/customization/picker/clock/ui/section/ClockSectionController.kt b/src/com/android/customization/picker/clock/ui/section/ClockSectionController.kt
deleted file mode 100644
index b47c2433..00000000
--- a/src/com/android/customization/picker/clock/ui/section/ClockSectionController.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.customization.picker.clock.ui.section
-
-import android.content.Context
-import android.view.LayoutInflater
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.lifecycleScope
-import com.android.customization.picker.clock.ui.binder.ClockSectionViewBinder
-import com.android.customization.picker.clock.ui.fragment.ClockSettingsFragment
-import com.android.customization.picker.clock.ui.view.ClockSectionView
-import com.android.customization.picker.clock.ui.viewmodel.ClockSectionViewModel
-import com.android.wallpaper.R
-import com.android.wallpaper.config.BaseFlags
-import com.android.wallpaper.model.CustomizationSectionController
-import com.android.wallpaper.model.CustomizationSectionController.CustomizationSectionNavigationController
-import kotlinx.coroutines.launch
-
-/** A [CustomizationSectionController] for clock customization. */
-class ClockSectionController(
- private val navigationController: CustomizationSectionNavigationController,
- private val lifecycleOwner: LifecycleOwner,
- private val flag: BaseFlags,
- private val viewModel: ClockSectionViewModel,
-) : CustomizationSectionController<ClockSectionView> {
-
- override fun isAvailable(context: Context): Boolean {
- return flag.isCustomClocksEnabled(context!!)
- }
-
- override fun createView(context: Context): ClockSectionView {
- val view =
- LayoutInflater.from(context)
- .inflate(
- R.layout.clock_section_view,
- null,
- ) as ClockSectionView
- lifecycleOwner.lifecycleScope.launch {
- ClockSectionViewBinder.bind(
- view = view,
- viewModel = viewModel,
- lifecycleOwner = lifecycleOwner
- ) {
- navigationController.navigateTo(ClockSettingsFragment())
- }
- }
- return view
- }
-}
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt b/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt
index d4f501b7..cae4e06b 100644
--- a/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt
+++ b/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt
@@ -31,7 +31,7 @@ import androidx.core.view.get
import androidx.core.view.isNotEmpty
import com.android.customization.picker.clock.shared.ClockSize
import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselItemViewModel
-import com.android.systemui.plugins.ClockController
+import com.android.systemui.plugins.clocks.ClockController
import com.android.wallpaper.R
import com.android.wallpaper.picker.FixedWidthDisplayRatioFrameLayout
import java.lang.Float.max
@@ -384,7 +384,7 @@ class ClockCarouselView(
) : Carousel.Adapter {
fun getContentDescription(index: Int, resources: Resources): String {
- return clocks[index].getContentDescription(resources)
+ return clocks[index].contentDescription
}
override fun count(): Int {
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockSizeRadioButtonGroup.kt b/src/com/android/customization/picker/clock/ui/view/ClockSizeRadioButtonGroup.kt
deleted file mode 100644
index 909491a3..00000000
--- a/src/com/android/customization/picker/clock/ui/view/ClockSizeRadioButtonGroup.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.customization.picker.clock.ui.view
-
-import android.content.Context
-import android.util.AttributeSet
-import android.view.LayoutInflater
-import android.view.View
-import android.widget.FrameLayout
-import android.widget.RadioButton
-import com.android.customization.picker.clock.shared.ClockSize
-import com.android.wallpaper.R
-
-/** The radio button group to pick the clock size. */
-class ClockSizeRadioButtonGroup(
- context: Context,
- attrs: AttributeSet?,
-) : FrameLayout(context, attrs) {
-
- interface OnRadioButtonClickListener {
- fun onClick(size: ClockSize)
- }
-
- val radioButtonDynamic: RadioButton
- val radioButtonSmall: RadioButton
- var onRadioButtonClickListener: OnRadioButtonClickListener? = null
-
- init {
- LayoutInflater.from(context).inflate(R.layout.clock_size_radio_button_group, this, true)
- radioButtonDynamic = requireViewById(R.id.radio_button_dynamic)
- val buttonDynamic = requireViewById<View>(R.id.button_container_dynamic)
- buttonDynamic.setOnClickListener { onRadioButtonClickListener?.onClick(ClockSize.DYNAMIC) }
- radioButtonSmall = requireViewById(R.id.radio_button_large)
- val buttonLarge = requireViewById<View>(R.id.button_container_small)
- buttonLarge.setOnClickListener { onRadioButtonClickListener?.onClick(ClockSize.SMALL) }
- }
-}
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt b/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt
index 3f6f423f..2ab162d3 100644
--- a/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt
+++ b/src/com/android/customization/picker/clock/ui/view/ClockViewFactory.kt
@@ -15,226 +15,38 @@
*/
package com.android.customization.picker.clock.ui.view
-import android.app.WallpaperColors
-import android.app.WallpaperManager
-import android.content.Context
-import android.content.res.Resources
-import android.graphics.Point
-import android.graphics.Rect
import android.view.View
-import android.widget.FrameLayout
import androidx.annotation.ColorInt
-import androidx.core.text.util.LocalePreferences
import androidx.lifecycle.LifecycleOwner
-import com.android.systemui.plugins.ClockController
-import com.android.systemui.plugins.WeatherData
-import com.android.systemui.shared.clocks.ClockRegistry
-import com.android.wallpaper.R
-import com.android.wallpaper.util.TimeUtils.TimeTicker
-import java.util.concurrent.ConcurrentHashMap
+import com.android.systemui.plugins.clocks.ClockController
-/**
- * Provide reusable clock view and related util functions.
- *
- * @property screenSize The Activity or Fragment's window size.
- */
-class ClockViewFactory(
- private val appContext: Context,
- val screenSize: Point,
- private val wallpaperManager: WallpaperManager,
- private val registry: ClockRegistry,
-) {
- private val resources = appContext.resources
- private val timeTickListeners: ConcurrentHashMap<Int, TimeTicker> = ConcurrentHashMap()
- private val clockControllers: HashMap<String, ClockController> = HashMap()
- private val smallClockFrames: HashMap<String, FrameLayout> = HashMap()
+interface ClockViewFactory {
- fun getController(clockId: String): ClockController {
- return clockControllers[clockId]
- ?: initClockController(clockId).also { clockControllers[clockId] = it }
- }
+ fun getController(clockId: String): ClockController
/**
* Reset the large view to its initial state when getting the view. This is because some view
* configs, e.g. animation state, might change during the reuse of the clock view in the app.
*/
- fun getLargeView(clockId: String): View {
- return getController(clockId).largeClock.let {
- it.animations.onPickerCarouselSwiping(1F)
- it.view
- }
- }
+ fun getLargeView(clockId: String): View
/**
* Reset the small view to its initial state when getting the view. This is because some view
* configs, e.g. translation X, might change during the reuse of the clock view in the app.
*/
- fun getSmallView(clockId: String): View {
- val smallClockFrame =
- smallClockFrames[clockId]
- ?: createSmallClockFrame().also {
- it.addView(getController(clockId).smallClock.view)
- smallClockFrames[clockId] = it
- }
- smallClockFrame.translationX = 0F
- smallClockFrame.translationY = 0F
- return smallClockFrame
- }
-
- private fun createSmallClockFrame(): FrameLayout {
- val smallClockFrame = FrameLayout(appContext)
- val layoutParams =
- FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.WRAP_CONTENT,
- resources.getDimensionPixelSize(R.dimen.small_clock_height)
- )
- layoutParams.topMargin = getSmallClockTopMargin()
- layoutParams.marginStart = getSmallClockStartPadding()
- smallClockFrame.layoutParams = layoutParams
- smallClockFrame.clipChildren = false
- return smallClockFrame
- }
-
- private fun getSmallClockTopMargin() =
- getStatusBarHeight(appContext.resources) +
- appContext.resources.getDimensionPixelSize(R.dimen.small_clock_padding_top)
-
- private fun getSmallClockStartPadding() =
- appContext.resources.getDimensionPixelSize(R.dimen.clock_padding_start)
-
- fun updateColorForAllClocks(@ColorInt seedColor: Int?) {
- clockControllers.values.forEach { it.events.onSeedColorChanged(seedColor = seedColor) }
- }
-
- fun updateColor(clockId: String, @ColorInt seedColor: Int?) {
- clockControllers[clockId]?.events?.onSeedColorChanged(seedColor)
- }
-
- fun updateRegionDarkness() {
- val isRegionDark = isLockscreenWallpaperDark()
- clockControllers.values.forEach {
- it.largeClock.events.onRegionDarknessChanged(isRegionDark)
- it.smallClock.events.onRegionDarknessChanged(isRegionDark)
- }
- }
-
- private fun isLockscreenWallpaperDark(): Boolean {
- val colors = wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_LOCK)
- return (colors?.colorHints?.and(WallpaperColors.HINT_SUPPORTS_DARK_TEXT)) == 0
- }
-
- fun updateTimeFormat(clockId: String) {
- getController(clockId)
- .events
- .onTimeFormatChanged(android.text.format.DateFormat.is24HourFormat(appContext))
- }
+ fun getSmallView(clockId: String): View
- fun registerTimeTicker(owner: LifecycleOwner) {
- val hashCode = owner.hashCode()
- if (timeTickListeners.keys.contains(hashCode)) {
- return
- }
+ fun updateColorForAllClocks(@ColorInt seedColor: Int?)
- timeTickListeners[hashCode] = TimeTicker.registerNewReceiver(appContext) { onTimeTick() }
- }
+ fun updateColor(clockId: String, @ColorInt seedColor: Int?)
- fun onDestroy() {
- timeTickListeners.forEach { (_, timeTicker) -> appContext.unregisterReceiver(timeTicker) }
- timeTickListeners.clear()
- clockControllers.clear()
- smallClockFrames.clear()
- }
+ fun updateRegionDarkness()
- private fun onTimeTick() {
- clockControllers.values.forEach {
- it.largeClock.events.onTimeTick()
- it.smallClock.events.onTimeTick()
- }
- }
+ fun updateTimeFormat(clockId: String)
- fun unregisterTimeTicker(owner: LifecycleOwner) {
- val hashCode = owner.hashCode()
- timeTickListeners[hashCode]?.let {
- appContext.unregisterReceiver(it)
- timeTickListeners.remove(hashCode)
- }
- }
-
- private fun initClockController(clockId: String): ClockController {
- val controller =
- registry.createExampleClock(clockId).also { it?.initialize(resources, 0f, 0f) }
- checkNotNull(controller)
-
- val isWallpaperDark = isLockscreenWallpaperDark()
- // Initialize large clock
- controller.largeClock.events.onRegionDarknessChanged(isWallpaperDark)
- controller.largeClock.events.onFontSettingChanged(
- resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat()
- )
- controller.largeClock.events.onTargetRegionChanged(getLargeClockRegion())
-
- // Initialize small clock
- controller.smallClock.events.onRegionDarknessChanged(isWallpaperDark)
- controller.smallClock.events.onFontSettingChanged(
- resources.getDimensionPixelSize(R.dimen.small_clock_text_size).toFloat()
- )
- controller.smallClock.events.onTargetRegionChanged(getSmallClockRegion())
-
- // Use placeholder for weather clock preview in picker.
- // Use locale default temp unit since assistant default is not available in this context.
- val useCelsius =
- LocalePreferences.getTemperatureUnit() == LocalePreferences.TemperatureUnit.CELSIUS
- controller.events.onWeatherDataChanged(
- WeatherData(
- description = DESCRIPTION_PLACEHODLER,
- state = WEATHERICON_PLACEHOLDER,
- temperature =
- if (useCelsius) TEMPERATURE_CELSIUS_PLACEHOLDER
- else TEMPERATURE_FAHRENHEIT_PLACEHOLDER,
- useCelsius = useCelsius,
- )
- )
- return controller
- }
-
- /**
- * Simulate the function of getLargeClockRegion in KeyguardClockSwitch so that we can get a
- * proper region corresponding to lock screen in picker and for onTargetRegionChanged to scale
- * and position the clock view
- */
- private fun getLargeClockRegion(): Rect {
- val largeClockTopMargin =
- resources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin)
- val targetHeight = resources.getDimensionPixelSize(R.dimen.large_clock_text_size) * 2
- val top = (screenSize.y / 2 - targetHeight / 2 + largeClockTopMargin / 2)
- return Rect(0, top, screenSize.x, (top + targetHeight))
- }
-
- /**
- * Simulate the function of getSmallClockRegion in KeyguardClockSwitch so that we can get a
- * proper region corresponding to lock screen in picker and for onTargetRegionChanged to scale
- * and position the clock view
- */
- private fun getSmallClockRegion(): Rect {
- val topMargin = getSmallClockTopMargin()
- val targetHeight = resources.getDimensionPixelSize(R.dimen.small_clock_height)
- return Rect(getSmallClockStartPadding(), topMargin, screenSize.x, topMargin + targetHeight)
- }
+ fun registerTimeTicker(owner: LifecycleOwner)
- companion object {
- const val DESCRIPTION_PLACEHODLER = ""
- const val TEMPERATURE_FAHRENHEIT_PLACEHOLDER = 58
- const val TEMPERATURE_CELSIUS_PLACEHOLDER = 21
- val WEATHERICON_PLACEHOLDER = WeatherData.WeatherStateIcon.MOSTLY_SUNNY
- const val USE_CELSIUS_PLACEHODLER = false
+ fun onDestroy()
- private fun getStatusBarHeight(resource: Resources): Int {
- var result = 0
- val resourceId: Int = resource.getIdentifier("status_bar_height", "dimen", "android")
- if (resourceId > 0) {
- result = resource.getDimensionPixelSize(resourceId)
- }
- return result
- }
- }
+ fun unregisterTimeTicker(owner: LifecycleOwner)
}
diff --git a/src/com/android/customization/picker/clock/ui/view/ClockViewFactoryImpl.kt b/src/com/android/customization/picker/clock/ui/view/ClockViewFactoryImpl.kt
new file mode 100644
index 00000000..5caea58d
--- /dev/null
+++ b/src/com/android/customization/picker/clock/ui/view/ClockViewFactoryImpl.kt
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.customization.picker.clock.ui.view
+
+import android.app.WallpaperColors
+import android.app.WallpaperManager
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.Point
+import android.graphics.Rect
+import android.view.View
+import android.widget.FrameLayout
+import androidx.annotation.ColorInt
+import androidx.core.text.util.LocalePreferences
+import androidx.lifecycle.LifecycleOwner
+import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.plugins.clocks.WeatherData
+import com.android.systemui.shared.clocks.ClockRegistry
+import com.android.wallpaper.R
+import com.android.wallpaper.util.TimeUtils.TimeTicker
+import java.util.concurrent.ConcurrentHashMap
+
+/**
+ * Provide reusable clock view and related util functions.
+ *
+ * @property screenSize The Activity or Fragment's window size.
+ */
+class ClockViewFactoryImpl(
+ private val appContext: Context,
+ val screenSize: Point,
+ private val wallpaperManager: WallpaperManager,
+ private val registry: ClockRegistry,
+) : ClockViewFactory {
+ private val resources = appContext.resources
+ private val timeTickListeners: ConcurrentHashMap<Int, TimeTicker> = ConcurrentHashMap()
+ private val clockControllers: HashMap<String, ClockController> = HashMap()
+ private val smallClockFrames: HashMap<String, FrameLayout> = HashMap()
+
+ override fun getController(clockId: String): ClockController {
+ return clockControllers[clockId]
+ ?: initClockController(clockId).also { clockControllers[clockId] = it }
+ }
+
+ /**
+ * Reset the large view to its initial state when getting the view. This is because some view
+ * configs, e.g. animation state, might change during the reuse of the clock view in the app.
+ */
+ override fun getLargeView(clockId: String): View {
+ return getController(clockId).largeClock.let {
+ it.animations.onPickerCarouselSwiping(1F)
+ it.view
+ }
+ }
+
+ /**
+ * Reset the small view to its initial state when getting the view. This is because some view
+ * configs, e.g. translation X, might change during the reuse of the clock view in the app.
+ */
+ override fun getSmallView(clockId: String): View {
+ val smallClockFrame =
+ smallClockFrames[clockId]
+ ?: createSmallClockFrame().also {
+ it.addView(getController(clockId).smallClock.view)
+ smallClockFrames[clockId] = it
+ }
+ smallClockFrame.translationX = 0F
+ smallClockFrame.translationY = 0F
+ return smallClockFrame
+ }
+
+ private fun createSmallClockFrame(): FrameLayout {
+ val smallClockFrame = FrameLayout(appContext)
+ val layoutParams =
+ FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ resources.getDimensionPixelSize(R.dimen.small_clock_height)
+ )
+ layoutParams.topMargin = getSmallClockTopMargin()
+ layoutParams.marginStart = getSmallClockStartPadding()
+ smallClockFrame.layoutParams = layoutParams
+ smallClockFrame.clipChildren = false
+ return smallClockFrame
+ }
+
+ private fun getSmallClockTopMargin() =
+ getStatusBarHeight(appContext.resources) +
+ appContext.resources.getDimensionPixelSize(R.dimen.small_clock_padding_top)
+
+ private fun getSmallClockStartPadding() =
+ appContext.resources.getDimensionPixelSize(R.dimen.clock_padding_start)
+
+ override fun updateColorForAllClocks(@ColorInt seedColor: Int?) {
+ clockControllers.values.forEach { it.events.onSeedColorChanged(seedColor = seedColor) }
+ }
+
+ override fun updateColor(clockId: String, @ColorInt seedColor: Int?) {
+ clockControllers[clockId]?.events?.onSeedColorChanged(seedColor)
+ }
+
+ override fun updateRegionDarkness() {
+ val isRegionDark = isLockscreenWallpaperDark()
+ clockControllers.values.forEach {
+ it.largeClock.events.onRegionDarknessChanged(isRegionDark)
+ it.smallClock.events.onRegionDarknessChanged(isRegionDark)
+ }
+ }
+
+ private fun isLockscreenWallpaperDark(): Boolean {
+ val colors = wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_LOCK)
+ return (colors?.colorHints?.and(WallpaperColors.HINT_SUPPORTS_DARK_TEXT)) == 0
+ }
+
+ override fun updateTimeFormat(clockId: String) {
+ getController(clockId)
+ .events
+ .onTimeFormatChanged(android.text.format.DateFormat.is24HourFormat(appContext))
+ }
+
+ override fun registerTimeTicker(owner: LifecycleOwner) {
+ val hashCode = owner.hashCode()
+ if (timeTickListeners.keys.contains(hashCode)) {
+ return
+ }
+
+ timeTickListeners[hashCode] = TimeTicker.registerNewReceiver(appContext) { onTimeTick() }
+ }
+
+ override fun onDestroy() {
+ timeTickListeners.forEach { (_, timeTicker) -> appContext.unregisterReceiver(timeTicker) }
+ timeTickListeners.clear()
+ clockControllers.clear()
+ smallClockFrames.clear()
+ }
+
+ private fun onTimeTick() {
+ clockControllers.values.forEach {
+ it.largeClock.events.onTimeTick()
+ it.smallClock.events.onTimeTick()
+ }
+ }
+
+ override fun unregisterTimeTicker(owner: LifecycleOwner) {
+ val hashCode = owner.hashCode()
+ timeTickListeners[hashCode]?.let {
+ appContext.unregisterReceiver(it)
+ timeTickListeners.remove(hashCode)
+ }
+ }
+
+ private fun initClockController(clockId: String): ClockController {
+ val controller =
+ registry.createExampleClock(clockId).also { it?.initialize(resources, 0f, 0f) }
+ checkNotNull(controller)
+
+ val isWallpaperDark = isLockscreenWallpaperDark()
+ // Initialize large clock
+ controller.largeClock.events.onRegionDarknessChanged(isWallpaperDark)
+ controller.largeClock.events.onFontSettingChanged(
+ resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat()
+ )
+ controller.largeClock.events.onTargetRegionChanged(getLargeClockRegion())
+
+ // Initialize small clock
+ controller.smallClock.events.onRegionDarknessChanged(isWallpaperDark)
+ controller.smallClock.events.onFontSettingChanged(
+ resources.getDimensionPixelSize(R.dimen.small_clock_text_size).toFloat()
+ )
+ controller.smallClock.events.onTargetRegionChanged(getSmallClockRegion())
+
+ // Use placeholder for weather clock preview in picker.
+ // Use locale default temp unit since assistant default is not available in this context.
+ val useCelsius =
+ LocalePreferences.getTemperatureUnit() == LocalePreferences.TemperatureUnit.CELSIUS
+ controller.events.onWeatherDataChanged(
+ WeatherData(
+ description = DESCRIPTION_PLACEHODLER,
+ state = WEATHERICON_PLACEHOLDER,
+ temperature =
+ if (useCelsius) TEMPERATURE_CELSIUS_PLACEHOLDER
+ else TEMPERATURE_FAHRENHEIT_PLACEHOLDER,
+ useCelsius = useCelsius,
+ )
+ )
+ return controller
+ }
+
+ /**
+ * Simulate the function of getLargeClockRegion in KeyguardClockSwitch so that we can get a
+ * proper region corresponding to lock screen in picker and for onTargetRegionChanged to scale
+ * and position the clock view
+ */
+ private fun getLargeClockRegion(): Rect {
+ val largeClockTopMargin =
+ resources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin)
+ val targetHeight = resources.getDimensionPixelSize(R.dimen.large_clock_text_size) * 2
+ val top = (screenSize.y / 2 - targetHeight / 2 + largeClockTopMargin / 2)
+ return Rect(0, top, screenSize.x, (top + targetHeight))
+ }
+
+ /**
+ * Simulate the function of getSmallClockRegion in KeyguardClockSwitch so that we can get a
+ * proper region corresponding to lock screen in picker and for onTargetRegionChanged to scale
+ * and position the clock view
+ */
+ private fun getSmallClockRegion(): Rect {
+ val topMargin = getSmallClockTopMargin()
+ val targetHeight = resources.getDimensionPixelSize(R.dimen.small_clock_height)
+ return Rect(getSmallClockStartPadding(), topMargin, screenSize.x, topMargin + targetHeight)
+ }
+
+ companion object {
+ const val DESCRIPTION_PLACEHODLER = ""
+ const val TEMPERATURE_FAHRENHEIT_PLACEHOLDER = 58
+ const val TEMPERATURE_CELSIUS_PLACEHOLDER = 21
+ val WEATHERICON_PLACEHOLDER = WeatherData.WeatherStateIcon.MOSTLY_SUNNY
+ const val USE_CELSIUS_PLACEHODLER = false
+
+ private fun getStatusBarHeight(resource: Resources): Int {
+ var result = 0
+ val resourceId: Int = resource.getIdentifier("status_bar_height", "dimen", "android")
+ if (resourceId > 0) {
+ result = resource.getDimensionPixelSize(resourceId)
+ }
+ return result
+ }
+ }
+}
diff --git a/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselItemViewModel.kt b/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselItemViewModel.kt
index 98114260..e5ac953c 100644
--- a/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselItemViewModel.kt
+++ b/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselItemViewModel.kt
@@ -15,20 +15,8 @@
*/
package com.android.customization.picker.clock.ui.viewmodel
-import android.content.res.Resources
-import com.android.customization.module.CustomizationInjector
-import com.android.wallpaper.R
-import com.android.wallpaper.module.InjectorProvider
-
-class ClockCarouselItemViewModel(val clockId: String, val isSelected: Boolean) {
-
- /** Description for accessibility purposes when a clock is selected. */
- fun getContentDescription(resources: Resources): String {
- val clockContent =
- (InjectorProvider.getInjector() as? CustomizationInjector)
- ?.getClockDescriptionUtils(resources)
- ?.getDescription(clockId)
- ?: ""
- return resources.getString(R.string.select_clock_action_description, clockContent)
- }
-}
+class ClockCarouselItemViewModel(
+ val clockId: String,
+ val isSelected: Boolean,
+ val contentDescription: String,
+)
diff --git a/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt b/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt
index 27c25a20..3f6394be 100644
--- a/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt
+++ b/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt
@@ -15,12 +15,15 @@
*/
package com.android.customization.picker.clock.ui.viewmodel
+import android.content.res.Resources
import android.graphics.Color
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
+import com.android.customization.module.logging.ThemesUserEventLogger
import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
import com.android.customization.picker.clock.shared.ClockSize
+import com.android.customization.picker.clock.ui.view.ClockViewFactory
import com.android.wallpaper.R
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -43,6 +46,9 @@ import kotlinx.coroutines.launch
class ClockCarouselViewModel(
private val interactor: ClockPickerInteractor,
private val backgroundDispatcher: CoroutineDispatcher,
+ private val clockViewFactory: ClockViewFactory,
+ private val resources: Resources,
+ private val logger: ThemesUserEventLogger,
) : ViewModel() {
@OptIn(ExperimentalCoroutinesApi::class)
val allClocks: StateFlow<List<ClockCarouselItemViewModel>> =
@@ -50,7 +56,14 @@ class ClockCarouselViewModel(
.mapLatest { allClocks ->
// Delay to avoid the case that the full list of clocks is not initiated.
delay(CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
- allClocks.map { ClockCarouselItemViewModel(it.clockId, it.isSelected) }
+ allClocks.map {
+ val contentDescription =
+ resources.getString(
+ R.string.select_clock_action_description,
+ clockViewFactory.getController(it.clockId).config.description
+ )
+ ClockCarouselItemViewModel(it.clockId, it.isSelected, contentDescription)
+ }
}
.stateIn(viewModelScope, SharingStarted.Eagerly, emptyList())
@@ -111,18 +124,27 @@ class ClockCarouselViewModel(
fun setSelectedClock(clockId: String) {
setSelectedClockJob?.cancel()
setSelectedClockJob =
- viewModelScope.launch(backgroundDispatcher) { interactor.setSelectedClock(clockId) }
+ viewModelScope.launch(backgroundDispatcher) {
+ interactor.setSelectedClock(clockId)
+ logger.logClockApplied(clockId)
+ }
}
class Factory(
private val interactor: ClockPickerInteractor,
private val backgroundDispatcher: CoroutineDispatcher,
+ private val clockViewFactory: ClockViewFactory,
+ private val resources: Resources,
+ private val logger: ThemesUserEventLogger,
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return ClockCarouselViewModel(
interactor = interactor,
backgroundDispatcher = backgroundDispatcher,
+ clockViewFactory = clockViewFactory,
+ resources = resources,
+ logger = logger,
)
as T
}
diff --git a/src/com/android/customization/picker/clock/ui/viewmodel/ClockSectionViewModel.kt b/src/com/android/customization/picker/clock/ui/viewmodel/ClockSectionViewModel.kt
deleted file mode 100644
index 8a655225..00000000
--- a/src/com/android/customization/picker/clock/ui/viewmodel/ClockSectionViewModel.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package com.android.customization.picker.clock.ui.viewmodel
-
-import android.content.Context
-import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
-import com.android.customization.picker.clock.shared.ClockSize
-import com.android.wallpaper.R
-import java.util.Locale
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.map
-
-/** View model for the clock section view on the lockscreen customization surface. */
-class ClockSectionViewModel(context: Context, interactor: ClockPickerInteractor) {
- val appContext: Context = context.applicationContext
- val clockColorMap: Map<String, ClockColorViewModel> =
- ClockColorViewModel.getPresetColorMap(appContext.resources)
- val selectedClockColorAndSizeText: Flow<String> =
- combine(interactor.selectedColorId, interactor.selectedClockSize, ::Pair).map {
- (selectedColorId, selectedClockSize) ->
- val colorText =
- clockColorMap[selectedColorId]?.colorName
- ?: appContext.getString(R.string.default_theme_title)
- val sizeText =
- when (selectedClockSize) {
- ClockSize.SMALL -> appContext.getString(R.string.clock_size_small)
- ClockSize.DYNAMIC -> appContext.getString(R.string.clock_size_dynamic)
- }
- appContext
- .getString(R.string.clock_color_and_size_description, colorText, sizeText)
- .lowercase()
- .replaceFirstChar {
- if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
- }
- }
-}
diff --git a/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt b/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
index a498c716..d0e4f8fe 100644
--- a/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
+++ b/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
@@ -21,9 +21,12 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.android.customization.model.color.ColorOptionImpl
+import com.android.customization.module.logging.ThemesUserEventLogger
+import com.android.customization.module.logging.ThemesUserEventLogger.Companion.NULL_SEED_COLOR
import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
import com.android.customization.picker.clock.shared.ClockSize
import com.android.customization.picker.clock.shared.model.ClockMetadataModel
+import com.android.customization.picker.clock.shared.toClockSizeForLogging
import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
import com.android.customization.picker.color.shared.model.ColorOptionModel
import com.android.customization.picker.color.shared.model.ColorType
@@ -53,6 +56,7 @@ private constructor(
private val clockPickerInteractor: ClockPickerInteractor,
private val colorPickerInteractor: ColorPickerInteractor,
private val getIsReactiveToTone: (clockId: String?) -> Boolean,
+ private val logger: ThemesUserEventLogger,
) : ViewModel() {
enum class Tab {
@@ -106,15 +110,17 @@ private constructor(
suspend fun onSliderProgressStop(progress: Int) {
val selectedColorId = selectedColorId.value ?: return
val clockColorViewModel = colorMap[selectedColorId] ?: return
+ val seedColor =
+ blendColorWithTone(
+ color = clockColorViewModel.color,
+ colorTone = clockColorViewModel.getColorTone(progress),
+ )
clockPickerInteractor.setClockColor(
selectedColorId = selectedColorId,
colorToneProgress = progress,
- seedColor =
- blendColorWithTone(
- color = clockColorViewModel.color,
- colorTone = clockColorViewModel.getColorTone(progress),
- )
+ seedColor = seedColor,
)
+ logger.logClockColorApplied(seedColor)
}
@OptIn(ExperimentalCoroutinesApi::class)
@@ -169,18 +175,20 @@ private constructor(
} else {
{
viewModelScope.launch {
+ val seedColor =
+ blendColorWithTone(
+ color = colorModel.color,
+ colorTone =
+ colorModel.getColorTone(
+ colorToneProgress,
+ ),
+ )
clockPickerInteractor.setClockColor(
selectedColorId = colorModel.colorId,
colorToneProgress = colorToneProgress,
- seedColor =
- blendColorWithTone(
- color = colorModel.color,
- colorTone =
- colorModel.getColorTone(
- colorToneProgress,
- ),
- ),
+ seedColor = seedColor,
)
+ logger.logClockColorApplied(seedColor)
}
}
}
@@ -244,6 +252,7 @@ private constructor(
ClockMetadataModel.DEFAULT_COLOR_TONE_PROGRESS,
seedColor = null,
)
+ logger.logClockColorApplied(NULL_SEED_COLOR)
}
}
}
@@ -254,7 +263,10 @@ private constructor(
val selectedClockSize: Flow<ClockSize> = clockPickerInteractor.selectedClockSize
fun setClockSize(size: ClockSize) {
- viewModelScope.launch { clockPickerInteractor.setClockSize(size) }
+ viewModelScope.launch {
+ clockPickerInteractor.setClockSize(size)
+ logger.logClockSizeApplied(size.toClockSizeForLogging())
+ }
}
private val _selectedTabPosition = MutableStateFlow(Tab.COLOR)
@@ -304,6 +316,7 @@ private constructor(
private val context: Context,
private val clockPickerInteractor: ClockPickerInteractor,
private val colorPickerInteractor: ColorPickerInteractor,
+ private val logger: ThemesUserEventLogger,
private val getIsReactiveToTone: (clockId: String?) -> Boolean,
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@@ -312,6 +325,7 @@ private constructor(
context = context,
clockPickerInteractor = clockPickerInteractor,
colorPickerInteractor = colorPickerInteractor,
+ logger = logger,
getIsReactiveToTone = getIsReactiveToTone,
)
as T
diff --git a/src/com/android/customization/picker/clock/utils/ClockDescriptionUtils.kt b/src/com/android/customization/picker/clock/utils/ClockDescriptionUtils.kt
deleted file mode 100644
index 28ea4a3f..00000000
--- a/src/com/android/customization/picker/clock/utils/ClockDescriptionUtils.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.customization.picker.clock.utils
-
-/** Provides clock description for accessibility purposes. */
-interface ClockDescriptionUtils {
-
- /**
- * TODO (b/287507746) : Migrate the clock description to system UI or a shared library, instead
- * of preserving at the Wallpaper Picker side.
- */
- fun getDescription(clockId: String): String
-}
diff --git a/src/com/android/customization/picker/clock/utils/ThemePickerClockDescriptionUtils.kt b/src/com/android/customization/picker/clock/utils/ThemePickerClockDescriptionUtils.kt
deleted file mode 100644
index a04ebfff..00000000
--- a/src/com/android/customization/picker/clock/utils/ThemePickerClockDescriptionUtils.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.customization.picker.clock.utils
-
-class ThemePickerClockDescriptionUtils : ClockDescriptionUtils {
- override fun getDescription(clockId: String): String {
- return ""
- }
-}