summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Lin <giolin@google.com>2023-06-23 20:04:50 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-06-23 20:04:50 +0000
commit79a67340b080bdeba9a2f40b02382bc4c7cc0cae (patch)
treef27390c1d5c7a0f4e487f1b3f389859a8c7e8515
parentada3587edef4c1c2fdfa4ec8367f2aa8bba7cce6 (diff)
parentbd10aa9c9c6a1c6b04d61e2006b1a9226919499a (diff)
downloadThemePicker-79a67340b080bdeba9a2f40b02382bc4c7cc0cae.tar.gz
Merge "Adds new mappings to content descriptions for custom clock faces" into udc-dev am: bd10aa9c9c
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/ThemePicker/+/23727699 Change-Id: If3c5483e9d4a4ba7696ecbd0d67c18edae23250e Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--res/layout/clock_carousel.xml15
-rwxr-xr-xres/values/strings.xml3
-rw-r--r--src/com/android/customization/module/CustomizationInjector.kt3
-rw-r--r--src/com/android/customization/module/ThemePickerInjector.kt8
-rw-r--r--src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt14
-rw-r--r--src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt26
-rw-r--r--src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselItemViewModel.kt35
-rw-r--r--src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt16
-rw-r--r--src/com/android/customization/picker/clock/utils/ClockDescriptionUtils.kt28
-rw-r--r--src/com/android/customization/picker/clock/utils/ThemePickerClockDescriptionUtils.kt25
10 files changed, 144 insertions, 29 deletions
diff --git a/res/layout/clock_carousel.xml b/res/layout/clock_carousel.xml
index a43e8044..e93a6971 100644
--- a/res/layout/clock_carousel.xml
+++ b/res/layout/clock_carousel.xml
@@ -43,7 +43,8 @@
android:layout_width="@dimen/screen_preview_width"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:clipChildren="false">
+ android:clipChildren="false"
+ android:importantForAccessibility="noHideDescendants">
<com.android.customization.picker.clock.ui.view.ClockHostView
android:id="@+id/clock_host_view_0"
android:layout_width="match_parent"
@@ -74,7 +75,8 @@
android:layout_width="@dimen/screen_preview_width"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:clipChildren="false">
+ android:clipChildren="false"
+ android:importantForAccessibility="noHideDescendants">
<com.android.customization.picker.clock.ui.view.ClockHostView
android:id="@+id/clock_host_view_1"
android:layout_width="match_parent"
@@ -107,7 +109,8 @@
android:layout_width="@dimen/screen_preview_width"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:clipChildren="false">
+ android:clipChildren="false"
+ android:importantForAccessibility="noHideDescendants">
<com.android.customization.picker.clock.ui.view.ClockHostView
android:id="@+id/clock_host_view_2"
android:layout_width="match_parent"
@@ -138,7 +141,8 @@
android:layout_width="@dimen/screen_preview_width"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:clipChildren="false">
+ android:clipChildren="false"
+ android:importantForAccessibility="noHideDescendants">
<com.android.customization.picker.clock.ui.view.ClockHostView
android:id="@+id/clock_host_view_3"
android:layout_width="match_parent"
@@ -169,7 +173,8 @@
android:layout_width="@dimen/screen_preview_width"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:clipChildren="false">
+ android:clipChildren="false"
+ android:importantForAccessibility="noHideDescendants">
<com.android.customization.picker.clock.ui.view.ClockHostView
android:id="@+id/clock_host_view_4"
android:layout_width="match_parent"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 40142d1f..b7574a3e 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -33,6 +33,9 @@
<!-- The content description of clock entry. [CHAR LIMIT=NONE] -->
<string name="clock_picker_entry_content_description">Change a custom clock</string>
+ <!-- action description for announcing selected Clock [CHAR LIMIT=NONE]-->
+ <string name="select_clock_action_description">Clock face option <xliff:g name="clock_face_description">%1$s</xliff:g></string>
+
<!-- Title of a section of the customization picker where the user can configure Clock face. [CHAR LIMIT=19] -->
<string name="clock_settings_title">Clock color &amp; size</string>
diff --git a/src/com/android/customization/module/CustomizationInjector.kt b/src/com/android/customization/module/CustomizationInjector.kt
index 8b0d90f1..5f8f9d3c 100644
--- a/src/com/android/customization/module/CustomizationInjector.kt
+++ b/src/com/android/customization/module/CustomizationInjector.kt
@@ -26,6 +26,7 @@ import com.android.customization.picker.clock.ui.view.ClockViewFactory
import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselViewModel
import com.android.customization.picker.clock.ui.viewmodel.ClockSectionViewModel
import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel
+import com.android.customization.picker.clock.utils.ClockDescriptionUtils
import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
import com.android.customization.picker.color.ui.viewmodel.ColorPickerViewModel
import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordancePickerInteractor
@@ -76,4 +77,6 @@ interface CustomizationInjector : Injector {
wallpaperColorsViewModel: WallpaperColorsViewModel,
clockViewFactory: ClockViewFactory,
): ClockSettingsViewModel.Factory
+
+ fun getClockDescriptionUtils(): ClockDescriptionUtils
}
diff --git a/src/com/android/customization/module/ThemePickerInjector.kt b/src/com/android/customization/module/ThemePickerInjector.kt
index d00ed28e..cceb8965 100644
--- a/src/com/android/customization/module/ThemePickerInjector.kt
+++ b/src/com/android/customization/module/ThemePickerInjector.kt
@@ -51,6 +51,8 @@ import com.android.customization.picker.clock.ui.view.ClockViewFactory
import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselViewModel
import com.android.customization.picker.clock.ui.viewmodel.ClockSectionViewModel
import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel
+import com.android.customization.picker.clock.utils.ClockDescriptionUtils
+import com.android.customization.picker.clock.utils.ThemePickerClockDescriptionUtils
import com.android.customization.picker.color.data.repository.ColorPickerRepositoryImpl
import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
import com.android.customization.picker.color.domain.interactor.ColorPickerSnapshotRestorer
@@ -115,6 +117,7 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject
private var themedIconSnapshotRestorer: ThemedIconSnapshotRestorer? = null
private var themedIconInteractor: ThemedIconInteractor? = null
private var clockSettingsViewModelFactory: ClockSettingsViewModel.Factory? = null
+ private var clockDescriptionUtils: ClockDescriptionUtils? = null
private var gridInteractor: GridInteractor? = null
private var gridSnapshotRestorer: GridSnapshotRestorer? = null
private var gridScreenViewModelFactory: GridScreenViewModel.Factory? = null
@@ -534,6 +537,11 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject
.also { clockSettingsViewModelFactory = it }
}
+ override fun getClockDescriptionUtils(): ClockDescriptionUtils {
+ return clockDescriptionUtils
+ ?: ThemePickerClockDescriptionUtils().also { clockDescriptionUtils = it }
+ }
+
fun getGridScreenViewModelFactory(
context: Context,
): ViewModelProvider.Factory {
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 8f964cf1..13c80c85 100644
--- a/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt
+++ b/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt
@@ -50,20 +50,22 @@ object ClockCarouselViewBinder {
launch { viewModel.isCarouselVisible.collect { carouselView.isVisible = it } }
launch {
- combine(viewModel.selectedClockSize, viewModel.allClockIds, ::Pair).collect {
- (size, allClockIds) ->
+ combine(viewModel.selectedClockSize, viewModel.allClocks, ::Pair).collect {
+ (size, allClocks) ->
carouselView.setUpClockCarouselView(
clockSize = size,
- clockIds = allClockIds,
- onClockSelected = { clockId -> viewModel.setSelectedClock(clockId) },
+ clocks = allClocks,
+ onClockSelected = { clock ->
+ viewModel.setSelectedClock(clock.clockId)
+ },
isTwoPaneAndSmallWidth = isTwoPaneAndSmallWidth,
)
}
}
launch {
- viewModel.allClockIds.collect {
- it.forEach { clockId -> clockViewFactory.updateTimeFormat(clockId) }
+ viewModel.allClocks.collect {
+ it.forEach { clock -> clockViewFactory.updateTimeFormat(clock.clockId) }
}
}
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 56d4dea2..73d55084 100644
--- a/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt
+++ b/src/com/android/customization/picker/clock/ui/view/ClockCarouselView.kt
@@ -28,6 +28,7 @@ import androidx.core.view.doOnPreDraw
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.wallpaper.R
import com.android.wallpaper.picker.FixedWidthDisplayRatioFrameLayout
@@ -70,15 +71,15 @@ class ClockCarouselView(
fun setUpClockCarouselView(
clockSize: ClockSize,
- clockIds: List<String>,
- onClockSelected: (clockId: String) -> Unit,
+ clocks: List<ClockCarouselItemViewModel>,
+ onClockSelected: (clock: ClockCarouselItemViewModel) -> Unit,
isTwoPaneAndSmallWidth: Boolean,
) {
if (isTwoPaneAndSmallWidth) {
overrideScreenPreviewWidth()
}
- adapter = ClockCarouselAdapter(clockSize, clockIds, clockViewFactory, onClockSelected)
+ adapter = ClockCarouselAdapter(clockSize, clocks, clockViewFactory, onClockSelected)
carousel.setAdapter(adapter)
carousel.refresh()
motionLayout.setTransitionListener(
@@ -118,11 +119,11 @@ class ClockCarouselView(
}
private fun prepareDynamicClockView(motionLayout: MotionLayout, endId: Int) {
- val scalingDownClockId = adapter.clockIds[carousel.currentIndex]
+ val scalingDownClockId = adapter.clocks[carousel.currentIndex].clockId
val scalingUpIdx =
if (endId == R.id.next) (carousel.currentIndex + 1) % adapter.count()
else (carousel.currentIndex - 1 + adapter.count()) % adapter.count()
- val scalingUpClockId = adapter.clockIds[scalingUpIdx]
+ val scalingUpClockId = adapter.clocks[scalingUpIdx].clockId
offCenterClockController = clockViewFactory.getController(scalingDownClockId)
toCenterClockController = clockViewFactory.getController(scalingUpClockId)
offCenterClockScaleView = motionLayout.findViewById(R.id.clock_scale_view_2)
@@ -298,13 +299,13 @@ class ClockCarouselView(
private class ClockCarouselAdapter(
val clockSize: ClockSize,
- val clockIds: List<String>,
+ val clocks: List<ClockCarouselItemViewModel>,
private val clockViewFactory: ClockViewFactory,
- private val onClockSelected: (clockId: String) -> Unit
+ private val onClockSelected: (clock: ClockCarouselItemViewModel) -> Unit
) : Carousel.Adapter {
override fun count(): Int {
- return clockIds.size
+ return clocks.size
}
override fun populate(view: View?, index: Int) {
@@ -318,7 +319,7 @@ class ClockCarouselView(
val clockHostView =
getClockHostViewId(viewRoot.id)?.let { viewRoot.findViewById(it) as? ClockHostView }
?: return
- val clockId = clockIds[index]
+ val clockId = clocks[index].clockId
// Add the clock view to the cloc host view
clockHostView.removeAllViews()
@@ -333,6 +334,11 @@ class ClockCarouselView(
clockHostView.addView(clockView)
val isMiddleView = isMiddleView(viewRoot.id)
+
+ // Accessibility
+ viewRoot.contentDescription = clocks[index].getContentDescription(view.resources)
+ viewRoot.isSelected = isMiddleView
+
when (clockSize) {
ClockSize.DYNAMIC ->
initializeDynamicClockView(
@@ -411,7 +417,7 @@ class ClockCarouselView(
}
override fun onNewItem(index: Int) {
- onClockSelected.invoke(clockIds[index])
+ onClockSelected.invoke(clocks[index])
}
}
diff --git a/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselItemViewModel.kt b/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselItemViewModel.kt
new file mode 100644
index 00000000..708fa2f9
--- /dev/null
+++ b/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselItemViewModel.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.res.Resources
+import com.android.customization.module.CustomizationInjector
+import com.android.wallpaper.R
+import com.android.wallpaper.module.InjectorProvider
+
+class ClockCarouselItemViewModel(val clockId: String) {
+
+ /** Description for accessibility purposes when a clock is selected. */
+ fun getContentDescription(resources: Resources): String {
+ val clockContent =
+ (InjectorProvider.getInjector() as? CustomizationInjector)
+ ?.getClockDescriptionUtils()
+ ?.getDescriptionResId(clockId)
+ ?.let { resources.getString(it) }
+ ?: ""
+ return resources.getString(R.string.select_clock_action_description, clockContent)
+ }
+}
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 781b48c0..a4f9cc4a 100644
--- a/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt
+++ b/src/com/android/customization/picker/clock/ui/viewmodel/ClockCarouselViewModel.kt
@@ -45,12 +45,12 @@ constructor(
private val backgroundDispatcher: CoroutineDispatcher,
) : ViewModel() {
@OptIn(ExperimentalCoroutinesApi::class)
- val allClockIds: StateFlow<List<String>> =
+ val allClocks: StateFlow<List<ClockCarouselItemViewModel>> =
interactor.allClocks
.mapLatest { allClocks ->
// Delay to avoid the case that the full list of clocks is not initiated.
delay(CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
- allClocks.map { it.clockId }
+ allClocks.map { ClockCarouselItemViewModel(it.clockId) }
}
.stateIn(viewModelScope, SharingStarted.Eagerly, emptyList())
@@ -58,14 +58,14 @@ constructor(
val seedColor: Flow<Int?> = interactor.seedColor
- val isCarouselVisible: Flow<Boolean> = allClockIds.map { it.size > 1 }.distinctUntilChanged()
+ val isCarouselVisible: Flow<Boolean> = allClocks.map { it.size > 1 }.distinctUntilChanged()
@OptIn(ExperimentalCoroutinesApi::class)
val selectedIndex: Flow<Int> =
- allClockIds
+ allClocks
.flatMapLatest { allClockIds ->
interactor.selectedClockId.map { selectedClockId ->
- val index = allClockIds.indexOf(selectedClockId)
+ val index = allClockIds.indexOfFirst { it.clockId == selectedClockId }
/** Making sure there is no active [setSelectedClockJob] */
val isSetClockIdJobActive = setSelectedClockJob?.isActive == true
if (index >= 0 && !isSetClockIdJobActive) {
@@ -79,11 +79,11 @@ constructor(
// Handle the case when there is only one clock in the carousel
val isSingleClockViewVisible: Flow<Boolean> =
- allClockIds.map { it.size == 1 }.distinctUntilChanged()
+ allClocks.map { it.size == 1 }.distinctUntilChanged()
val clockId: Flow<String> =
- allClockIds
- .map { allClockIds -> if (allClockIds.size == 1) allClockIds[0] else null }
+ allClocks
+ .map { allClockIds -> if (allClockIds.size == 1) allClockIds[0].clockId else null }
.mapNotNull { it }
private var setSelectedClockJob: Job? = null
diff --git a/src/com/android/customization/picker/clock/utils/ClockDescriptionUtils.kt b/src/com/android/customization/picker/clock/utils/ClockDescriptionUtils.kt
new file mode 100644
index 00000000..9a0b66f1
--- /dev/null
+++ b/src/com/android/customization/picker/clock/utils/ClockDescriptionUtils.kt
@@ -0,0 +1,28 @@
+/*
+ * 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
+
+import androidx.annotation.StringRes
+
+/** Provides clock description for accessibility purposes. */
+interface ClockDescriptionUtils {
+
+ /**
+ * TODO (b/287507746) : Migrate description res ID to system UI or a shared library, instead of
+ * preserving the clock description at the Wallpaper Picker side.
+ */
+ @StringRes fun getDescriptionResId(clockId: String): Int
+}
diff --git a/src/com/android/customization/picker/clock/utils/ThemePickerClockDescriptionUtils.kt b/src/com/android/customization/picker/clock/utils/ThemePickerClockDescriptionUtils.kt
new file mode 100644
index 00000000..6b3b4055
--- /dev/null
+++ b/src/com/android/customization/picker/clock/utils/ThemePickerClockDescriptionUtils.kt
@@ -0,0 +1,25 @@
+/*
+ * 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
+
+import androidx.annotation.StringRes
+
+class ThemePickerClockDescriptionUtils : ClockDescriptionUtils {
+ @StringRes
+ override fun getDescriptionResId(clockId: String): Int {
+ return -1
+ }
+}