diff options
author | George Lin <giolin@google.com> | 2023-06-23 20:04:50 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-06-23 20:04:50 +0000 |
commit | 79a67340b080bdeba9a2f40b02382bc4c7cc0cae (patch) | |
tree | f27390c1d5c7a0f4e487f1b3f389859a8c7e8515 | |
parent | ada3587edef4c1c2fdfa4ec8367f2aa8bba7cce6 (diff) | |
parent | bd10aa9c9c6a1c6b04d61e2006b1a9226919499a (diff) | |
download | ThemePicker-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>
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 & 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 + } +} |