From 456f3e89199a39a85b2c6da7523dc67569ee3d79 Mon Sep 17 00:00:00 2001 From: Mika Lindell Date: Wed, 1 Sep 2021 21:10:15 +0300 Subject: [PATCH] fix: talkback read display value on scroll value change (#373) * When TalkBack is enabled, read new values while scrolling a wheel * Support for reading displayed value instead index value (IosClone) * Add comments and small refactoring * Small refactor --- .../date_picker/pickers/IosClone.java | 31 +++++++--- .../date_picker/ui/Accessibility.java | 58 +++++++++++++++++++ 2 files changed, 80 insertions(+), 9 deletions(-) diff --git a/android/src/main/java/com/henninghall/date_picker/pickers/IosClone.java b/android/src/main/java/com/henninghall/date_picker/pickers/IosClone.java index 480f2c8..5b3ea57 100644 --- a/android/src/main/java/com/henninghall/date_picker/pickers/IosClone.java +++ b/android/src/main/java/com/henninghall/date_picker/pickers/IosClone.java @@ -6,22 +6,41 @@ import android.util.AttributeSet; import android.view.View; import android.view.MotionEvent; -import com.henninghall.date_picker.ui.Accessibility; - import cn.carbswang.android.numberpickerview.library.NumberPickerView; +import com.henninghall.date_picker.ui.Accessibility; + public class IosClone extends NumberPickerView implements Picker { + private Picker.OnValueChangeListenerInScrolling mOnValueChangeListenerInScrolling; public IosClone(Context context) { super(context); + initSetOnValueChangeListenerInScrolling(); } public IosClone(Context context, AttributeSet attrs) { super(context, attrs); + initSetOnValueChangeListenerInScrolling(); } public IosClone(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); + initSetOnValueChangeListenerInScrolling(); + } + + private void initSetOnValueChangeListenerInScrolling() { + final Picker self = this; + super.setOnValueChangeListenerInScrolling(new NumberPickerView.OnValueChangeListenerInScrolling() { + @Override + + public void onValueChangeInScrolling(NumberPickerView picker, int oldVal, int newVal) { + Accessibility.announceNumberPickerValue(picker, newVal); + + if (mOnValueChangeListenerInScrolling != null) { + mOnValueChangeListenerInScrolling.onValueChangeInScrolling(self, oldVal, newVal); + } + } + }); } @Override @@ -34,13 +53,7 @@ public class IosClone extends NumberPickerView implements Picker { @Override public void setOnValueChangeListenerInScrolling(final Picker.OnValueChangeListenerInScrolling listener) { - final Picker self = this; - super.setOnValueChangeListenerInScrolling(new NumberPickerView.OnValueChangeListenerInScrolling() { - @Override - public void onValueChangeInScrolling(NumberPickerView picker, int oldVal, int newVal) { - listener.onValueChangeInScrolling(self, oldVal, newVal); - } - }); + this.mOnValueChangeListenerInScrolling = listener; } @Override diff --git a/android/src/main/java/com/henninghall/date_picker/ui/Accessibility.java b/android/src/main/java/com/henninghall/date_picker/ui/Accessibility.java index ab3dc88..0a9e450 100644 --- a/android/src/main/java/com/henninghall/date_picker/ui/Accessibility.java +++ b/android/src/main/java/com/henninghall/date_picker/ui/Accessibility.java @@ -5,6 +5,8 @@ import android.os.Build; import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; +import android.accessibilityservice.AccessibilityServiceInfo; +import cn.carbswang.android.numberpickerview.library.NumberPickerView; import com.henninghall.date_picker.DatePickerManager; import com.henninghall.date_picker.State; @@ -13,6 +15,8 @@ import com.henninghall.date_picker.wheelFunctions.WheelFunction; import com.henninghall.date_picker.wheels.Wheel; import java.util.Locale; +import java.util.Arrays; +import java.util.List; public class Accessibility { @@ -85,6 +89,60 @@ public class Accessibility { picker.picker.getView().setContentDescription(descriptionPrefix + ", "+ descriptionPostFix + " "+ selectedDateString); } + /** + * Checks if the accessibility service responsible of spoken feedback is active + */ + public static boolean isSpokenFeedbackEnabled() { + return hasAccessibilityFeatureTypeEnabled(AccessibilityServiceInfo.FEEDBACK_SPOKEN); + } + + /** + * Get a list of accessibility services currently active + */ + private static boolean hasAccessibilityFeatureTypeEnabled(int type) { + + List enabledServices = + systemManager.getEnabledAccessibilityServiceList(type); + + return enabledServices != null && enabledServices.size() > 0; + } + + /** + * Read a message out loud when spoken feedback is active + */ + public static void announce(String message) { + if (systemManager == null || !isSpokenFeedbackEnabled()) { + return; + } + + AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_ANNOUNCEMENT); + event.getText().add(message); + systemManager.sendAccessibilityEvent(event); + } + + /** + * Get NumberPickerView displayValue from value. + */ + private static String numberPickerValueToDisplayedValue(NumberPickerView numberPicker, int value) { + final String[] displayValues = numberPicker.getDisplayedValues(); + + final String displayValue = displayValues[value]; + + if (displayValue != null) { + return displayValue; + } + + return String.valueOf(value); + } + + /** + * Read NumberPickerView displayed value. + * For TalkBack to read dates etc. correctly, make sure they are in localised format. + */ + public static void announceNumberPickerValue(NumberPickerView numberPicker, int newValue) { + announce(numberPickerValueToDisplayedValue(numberPicker, newValue)); + } + private String getAccessibleTextForSelectedDate() { String accessibleText; switch(state.getMode()) {