Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1/n Adding Android support for Accessibility TtsSpan API - Support for accessibilitySpan and accessibilityLabel props in nested Text #35130

Closed
wants to merge 91 commits into from
Closed
Show file tree
Hide file tree
Changes from 64 commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
216a30a
draft solution partially spelling correctly
fabOnReact Oct 29, 2022
48a01d0
correctly spelling a span text
fabOnReact Oct 29, 2022
08d6f43
add span description
fabOnReact Oct 31, 2022
145303e
remove code duplication
fabOnReact Oct 31, 2022
f66e914
remove code duplication
fabOnReact Oct 31, 2022
3d4e662
draft java configs to trigger setAccessibilityUnit
fabOnReact Nov 1, 2022
1653d6b
Merge branch 'main' into tts-span
fabOnReact Nov 1, 2022
6def7a9
draft cpp configs - they trigger runtime
fabOnReact Nov 1, 2022
7fa58f5
Fabric cpp settings trigger runtime error
fabOnReact Nov 1, 2022
43e7c29
cpp mapbuffer configs before rebase
fabOnReact Nov 1, 2022
0afdc69
Merge branch 'main' into tts-span
fabOnReact Nov 1, 2022
0cd0ac4
avoid using key from other props
fabOnReact Nov 1, 2022
f5a3b49
avoid using key 24 and use key 99
fabOnReact Nov 1, 2022
08fc9ac
remove log messages
fabOnReact Nov 2, 2022
c2adbb8
debug - change key number
fabOnReact Nov 2, 2022
46c4fb8
Merge branch 'main' into tts-span
fabOnReact Nov 2, 2022
45ec47f
custom conversion logic for accUnit as done with accRole
fabOnReact Nov 2, 2022
0a00193
Merge branch 'main' into tts-span
fabOnReact Nov 3, 2022
72ee5a1
remove accessibilityUnit prop from cpp
fabOnReact Nov 3, 2022
81fe302
accessibilityRole verbatim correctly announces span text, but does no…
fabOnReact Nov 3, 2022
7af9bd3
Remove logic for announcing nested text
fabOnReact Nov 3, 2022
16f1f39
clean up not needed logic
fabOnReact Nov 3, 2022
d845073
removing not relevant logic
fabOnReact Nov 3, 2022
e215baa
adding TtsSpan with type date
fabOnReact Nov 3, 2022
03a125c
refactoring logic parsing accRole to TtsSpan TYPES
fabOnReact Nov 4, 2022
fe5c480
TtsSpan works with parent Text component
fabOnReact Nov 4, 2022
7e264da
adding TtsSpan to TextLayoutManager
fabOnReact Nov 4, 2022
d8823e5
removing not required logic
fabOnReact Nov 4, 2022
9d4b8a5
update description
fabOnReact Nov 4, 2022
7b85e25
adding all TtsSpan, no comp errors
fabOnReact Nov 4, 2022
aefa45f
accessibility TtsSpan examples
fabOnReact Nov 4, 2022
95d6d3b
adding accessibility ttspan examples
fabOnReact Nov 4, 2022
24c182a
manually patching the prefab-headers avoid the app from triggering a …
fabOnReact Nov 9, 2022
7b4231f
Merge branch 'main' into tts-span
fabOnReact Nov 9, 2022
4fbc54b
accessibilityUnit hours param Java test implementation
fabOnReact Nov 10, 2022
29a8104
Merge branch 'main' into tts-span
fabOnReact Nov 10, 2022
e3fd7ff
clean up diff
fabOnReact Nov 11, 2022
3e1d292
clean up diff
fabOnReact Nov 11, 2022
8b23efd
Adding prop accessibilityUnit to TextAttributesProps (fabric) (#3)
fabOnReact Nov 15, 2022
bea5af9
code-review
fabOnReact Nov 15, 2022
6fc18d4
fix circleci errors
fabOnReact Nov 15, 2022
8b592f7
The ReactTtsSpan.Builder constructor expects a string and not an Acce…
fabOnReact Nov 16, 2022
f2642f6
adding type money support
fabOnReact Nov 16, 2022
c4cd23b
adding check on accessibilityUnit
fabOnReact Nov 16, 2022
576bad6
improve logging
fabOnReact Nov 17, 2022
958ae95
Test Buck fix circular dependency
fabOnReact Nov 17, 2022
8a59592
adding final to Set
fabOnReact Nov 17, 2022
eb95e08
static interface method invocations are not supported in -source 7
fabOnReact Nov 17, 2022
5aa9f74
error: static interface method invocations are not supported in -sour…
fabOnReact Nov 17, 2022
cb52ad9
refactor example
fabOnReact Nov 17, 2022
60ef8f0
adding support for telephonegst
fabOnReact Nov 17, 2022
06096d5
adding support for measure
fabOnReact Nov 17, 2022
cc45e04
simplify ReactTtsSpan API
fabOnReact Nov 17, 2022
096019c
remove time warning
fabOnReact Nov 17, 2022
7f4a0cd
adding back check on currency code
fabOnReact Nov 17, 2022
0a42fd0
adding comments to prop
fabOnReact Nov 17, 2022
79c4aed
remove comment
fabOnReact Nov 17, 2022
dfc4063
update TA_KEY_ACCESSIBILITY_UNIT value (code review)
fabOnReact Nov 18, 2022
3b30659
adding static set SUPPORTED_TYPES_SET
fabOnReact Nov 18, 2022
fe4e1e0
introducing Set in ReactTtsSpan
fabOnReact Nov 18, 2022
ef9c59b
Merge branch 'main' into tts-span
fabOnReact Dec 13, 2022
ac79bae
update types cpp, objc typescript and js
fabOnReact Dec 13, 2022
145db13
minor changes
fabOnReact Dec 13, 2022
a892b68
fix xcode warning
fabOnReact Dec 14, 2022
61e5920
Merge branch 'main' into tts-span
fabOnReact Jan 12, 2023
f495025
adding role grid to ViewAccessibility.d.ts
fabOnReact Jan 12, 2023
753858e
adding roles to Role typegst
fabOnReact Jan 12, 2023
821a4c8
Merge branch 'main' into tts-span
fabOnReact Jan 12, 2023
4988339
Merge branch 'main' into tts-span
fabOnReact Jan 12, 2023
02af5a4
Merge branch 'main' into tts-span
fabOnReact Feb 2, 2023
dcb9f61
remove view prop (take 3)
fabOnReact Feb 3, 2023
e7cbd28
remove change from ViewAcc.d.ts
fabOnReact Feb 3, 2023
565d7ed
adding accessibilitySpan prop
fabOnReact Feb 3, 2023
a1c7e0f
remove changes to accessibilityRole
fabOnReact Feb 3, 2023
f797c20
working solution migration to accessibilitySpan with AccSpan type
fabOnReact Feb 3, 2023
8b90011
accSpan enum type
fabOnReact Feb 3, 2023
e830578
fix verbatim not working
fabOnReact Feb 3, 2023
25b212e
adding cpp AccSpan type
fabOnReact Feb 3, 2023
c058657
adding more missing cpp configs
fabOnReact Feb 3, 2023
151b37c
Verbatim and other strings are not announced.
fabOnReact Feb 6, 2023
6f68513
adding type none to AccSpan
fabOnReact Feb 6, 2023
e1c56ac
android studio and circleci fixes
fabOnReact Feb 6, 2023
ecc815b
Use accessibilityLabel instead of accessibilityUnit.
fabOnReact Feb 7, 2023
7c80bdb
removing changes to ReactAccDelegate
fabOnReact Feb 7, 2023
34ed14e
Remove not supported TYPES from PR and move them to a separate branch
fabOnReact Feb 7, 2023
23241dd
rename UNIT to LABEL
fabOnReact Feb 7, 2023
112ed6f
Merge branch 'main' into tts-span
fabOnReact Feb 8, 2023
235eda8
Review Android Studio and XCODE errors
fabOnReact Feb 8, 2023
d536cf7
update comments
fabOnReact Feb 8, 2023
c154196
update comments
fabOnReact Feb 9, 2023
76ce49a
update check on accSpan and accLabel
fabOnReact Feb 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Libraries/Components/View/ReactNativeViewAttributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const UIView = {
accessibilityLiveRegion: true,
accessibilityRole: true,
accessibilityState: true,
accessibilityUnit: true,
accessibilityValue: true,
accessibilityHint: true,
accessibilityLanguage: true,
Expand Down
21 changes: 20 additions & 1 deletion Libraries/Components/View/ViewAccessibility.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ export interface AccessibilityProps
*/
accessibilityState?: AccessibilityState | undefined;

/**
* Used with nested Text and accessibilityRole measure, money or telephone to specify the unit to announce.
* Measure refer to https://developer.android.com/reference/android/text/style/TtsSpan#ARG_UNIT
* Currency refer to https://developer.android.com/reference/android/text/style/TtsSpan#ARG_CURRENCY
* Telephone refer to https://developer.android.com/reference/android/text/style/TtsSpan#ARG_NUMBER_PARTS
*/
accessibilityUnit?: string | undefined;

/**
* alias for accessibilityState
*
Expand Down Expand Up @@ -198,6 +206,18 @@ export type AccessibilityRole =
| 'button'
| 'togglebutton'
| 'link'
| 'cardinal'
| 'ordinal'
| 'fraction'
| 'measure'
| 'time'
| 'date'
| 'telephone'
| 'electronic'
| 'decimal'
| 'money'
| 'digits'
| 'verbatim'
| 'search'
| 'image'
| 'keyboardkey'
Expand Down Expand Up @@ -312,7 +332,6 @@ export type Role =
| 'feed'
| 'figure'
| 'form'
| 'grid'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we get rid of 'grid' here?

Copy link
Contributor Author

@fabOnReact fabOnReact Jan 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lunaleaps Sorry. It was a mistake while removing the duplicate from RCTViewManager (related f3d9f2e).
Fixed with commit f495025

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As explained by Nick in https://github.com/facebook/react-native/pull/34477/files#r982953176, this roles are platform specific. I'm not adding them to the Role type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test cases included in #35130 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

| 'group'
| 'heading'
| 'img'
Expand Down
12 changes: 12 additions & 0 deletions Libraries/Components/View/ViewAccessibility.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ export type AccessibilityRole =
| 'dropdownlist'
| 'togglebutton'
| 'link'
| 'cardinal'
| 'ordinal'
| 'decimal'
| 'fraction'
| 'measure'
| 'time'
| 'date'
| 'telephone'
| 'electronic'
| 'money'
| 'digits'
| 'verbatim'
| 'search'
| 'image'
| 'keyboardkey'
Expand Down
9 changes: 9 additions & 0 deletions Libraries/Components/View/ViewPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,15 @@ export type ViewProps = $ReadOnly<{|
* Indicates to accessibility services that UI Component is in a specific State.
*/
accessibilityState?: ?AccessibilityState,

/**
* Used with nested Text and accessibilityRole measure, money or telephone to specify the unit to announce.
* Measure refer to https://developer.android.com/reference/android/text/style/TtsSpan#ARG_UNIT
* Currency refer to https://developer.android.com/reference/android/text/style/TtsSpan#ARG_CURRENCY
* Telephone refer to https://developer.android.com/reference/android/text/style/TtsSpan#ARG_NUMBER_PARTS
*/
accessibilityUnit?: ?Stringish,

accessibilityValue?: ?AccessibilityValue,

/**
Expand Down
1 change: 1 addition & 0 deletions Libraries/NativeComponent/BaseViewConfig.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ const validAttributesForNonEventProps = {
accessibilityCollection: true,
accessibilityCollectionItem: true,
accessibilityState: true,
accessibilityUnit: true,
accessibilityActions: true,
accessibilityValue: true,
importantForAccessibility: true,
Expand Down
1 change: 1 addition & 0 deletions Libraries/NativeComponent/BaseViewConfig.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ const validAttributesForNonEventProps = {
transform: {diff: require('../Utilities/differ/matricesDiffer')},
accessibilityRole: true,
accessibilityState: true,
accessibilityUnit: true,
nativeID: true,
pointerEvents: true,
removeClippedSubviews: true,
Expand Down
8 changes: 8 additions & 0 deletions Libraries/Text/TextProps.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,14 @@ export type TextProps = $ReadOnly<{|
* Android Only
*/

/**
* Used with nested Text and accessibilityRole measure, money or telephone to specify the unit to announce.
* Measure refer to https://developer.android.com/reference/android/text/style/TtsSpan#ARG_UNIT
* Currency refer to https://developer.android.com/reference/android/text/style/TtsSpan#ARG_CURRENCY
* Telephone refer to https://developer.android.com/reference/android/text/style/TtsSpan#ARG_NUMBER_PARTS
*/
accessibilityUnit?: ?string,

/**
* Specifies the disabled state of the text view for testing purposes.
*
Expand Down
13 changes: 12 additions & 1 deletion React/Views/RCTViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ @implementation RCTConvert (UIAccessibilityTraits)
@"tablist" : @(UIAccessibilityTraitNone),
@"timer" : @(UIAccessibilityTraitNone),
@"toolbar" : @(UIAccessibilityTraitNone),
@"grid" : @(UIAccessibilityTraitNone),
@"pager" : @(UIAccessibilityTraitNone),
@"scrollview" : @(UIAccessibilityTraitNone),
@"horizontalscrollview" : @(UIAccessibilityTraitNone),
Expand All @@ -75,6 +74,18 @@ @implementation RCTConvert (UIAccessibilityTraits)
@"iconmenu" : @(UIAccessibilityTraitNone),
@"list" : @(UIAccessibilityTraitNone),
@"grid" : @(UIAccessibilityTraitNone),
@"cardinal": @(UIAccessibilityTraitNone),
@"ordinal": @(UIAccessibilityTraitNone),
@"decimal": @(UIAccessibilityTraitNone),
@"fraction": @(UIAccessibilityTraitNone),
@"measure": @(UIAccessibilityTraitNone),
@"time": @(UIAccessibilityTraitNone),
@"date": @(UIAccessibilityTraitNone),
@"telephone": @(UIAccessibilityTraitNone),
@"electronic": @(UIAccessibilityTraitNone),
@"money": @(UIAccessibilityTraitNone),
@"digits": @(UIAccessibilityTraitNone),
@"verbatim": @(UIAccessibilityTraitNone),
}),
UIAccessibilityTraitNone,
unsignedLongLongValue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import android.text.TextUtils;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.ClickableSpan;
import android.text.style.TtsSpan;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
Expand Down Expand Up @@ -108,6 +109,18 @@ public enum AccessibilityRole {
DROPDOWNLIST,
TOGGLEBUTTON,
LINK,
CARDINAL,
ORDINAL,
DECIMAL,
FRACTION,
MEASURE,
TIME,
DATE,
TELEPHONE,
ELECTRONIC,
MONEY,
DIGITS,
VERBATIM,
SEARCH,
IMAGE,
IMAGEBUTTON,
Expand Down Expand Up @@ -175,6 +188,30 @@ public static String getValue(AccessibilityRole role) {
return "android.widget.AbsListView";
case GRID:
return "android.widget.GridView";
case ORDINAL:
return TtsSpan.TYPE_ORDINAL;
case DECIMAL:
return TtsSpan.TYPE_DECIMAL;
case FRACTION:
return TtsSpan.TYPE_FRACTION;
case CARDINAL:
return TtsSpan.TYPE_CARDINAL;
case MEASURE:
return TtsSpan.TYPE_MEASURE;
case TIME:
return TtsSpan.TYPE_TIME;
case DATE:
return TtsSpan.TYPE_DATE;
case TELEPHONE:
return TtsSpan.TYPE_TELEPHONE;
case ELECTRONIC:
return TtsSpan.TYPE_ELECTRONIC;
case MONEY:
return TtsSpan.TYPE_MONEY;
case DIGITS:
return TtsSpan.TYPE_DIGITS;
case VERBATIM:
return TtsSpan.TYPE_VERBATIM;
case SCROLLVIEW:
return "android.widget.ScrollView";
case HORIZONTALSCROLLVIEW:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ public class ViewProps {
public static final String ACCESSIBILITY_LIVE_REGION = "accessibilityLiveRegion";
public static final String ACCESSIBILITY_ROLE = "accessibilityRole";
public static final String ACCESSIBILITY_STATE = "accessibilityState";
public static final String ACCESSIBILITY_UNIT = "accessibilityUnit";
public static final String ACCESSIBILITY_ACTIONS = "accessibilityActions";
public static final String ACCESSIBILITY_VALUE = "accessibilityValue";
public static final String ACCESSIBILITY_LABELLED_BY = "accessibilityLabelledBy";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.react.views.text;

import android.os.Parcel;
import android.os.PersistableBundle;
import android.text.style.TtsSpan;
import com.facebook.common.logging.FLog;
import com.facebook.react.uimanager.ReactAccessibilityDelegate.AccessibilityRole;
import java.util.Arrays;
import java.util.Currency;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.Nullable;

/*
* Wraps {@link TtsSpan} as a {@link ReactSpan}.
* A span that supplies additional meta-data for the associated text intended
* for text-to-speech engines. If the text is being processed by a
* text-to-speech engine, the engine may use the data in this span in addition
* to or instead of its associated text.
*
* Each instance of a TtsSpan has a type, for example {@link #TYPE_DATE}
* or {@link #TYPE_MEASURE}. And a list of arguments, provided as
* key-value pairs in a bundle.
*
* The inner classes are there for convenience and provide builders for each
* TtsSpan type.
*/
public class ReactTtsSpan extends TtsSpan implements ReactSpan {
private static final String TAG = ReactTtsSpan.class.getSimpleName();
private static final String TYPE_MONEY_WARNING_MSG =
"The accessibilityUnit format may not be compatible"
+ " with the format supported ISO 4217 (for example 'USD').";
private static final String TYPE_TELEPHONE_WARNING_MSG =
"Failed to retrieve telephone number (for example '0112123432').";
private static final String TYPE_MEASURE_WARNING_MSG =
"Failed to retrieve unit type (for ex. meter, second, milli).";
private static final String[] SUPPORTED_UNIT_VALUES = {
TYPE_MEASURE, TYPE_TELEPHONE, TYPE_MONEY,
};

private static final Set<String> SUPPORTED_UNIT_SET =
new HashSet<String>(Arrays.asList(SUPPORTED_UNIT_VALUES));

public ReactTtsSpan(String type, PersistableBundle args) {
super(type, args);
}

public ReactTtsSpan(Parcel src) {
super(src);
}

public static class Builder<C extends Builder<?>> {
private final String mType;
private PersistableBundle mArgs = new PersistableBundle();

public Builder(String type) {
mType = type;
}
fabOnReact marked this conversation as resolved.
Show resolved Hide resolved

public Builder(AccessibilityRole type, @Nullable String accessibilityUnit) {
String typeConvertedToString = AccessibilityRole.getValue(type);
mType = typeConvertedToString;
String roleClassName = AccessibilityRole.getValue(type);
String warningMessage = "";
Set<String> supportedTypes = new HashSet<String>();
if (accessibilityUnit == null || !ReactTtsSpan.SUPPORTED_UNIT_SET.contains(roleClassName)) {
return;
}
try {
if (roleClassName == ReactTtsSpan.TYPE_MONEY) {
warningMessage = ReactTtsSpan.TYPE_MONEY_WARNING_MSG;
Currency.getInstance(accessibilityUnit);
setStringArgument(ReactTtsSpan.ARG_INTEGER_PART, "");
setStringArgument(ReactTtsSpan.ARG_CURRENCY, accessibilityUnit);
}
if (roleClassName == ReactTtsSpan.TYPE_TELEPHONE) {
warningMessage = ReactTtsSpan.TYPE_TELEPHONE_WARNING_MSG;
setStringArgument(ReactTtsSpan.ARG_NUMBER_PARTS, accessibilityUnit);
}
// https://developer.android.com/reference/android/text/style/TtsSpan#ARG_UNIT
if (roleClassName == ReactTtsSpan.TYPE_MEASURE) {
warningMessage = ReactTtsSpan.TYPE_MEASURE_WARNING_MSG;
setStringArgument(ReactTtsSpan.ARG_UNIT, accessibilityUnit);
}
} catch (Exception e) {
FLog.e(
TAG,
"Failed to create ReactTtsSpan.Builder with params type: "
+ type
+ " and accessibilityUnit: "
+ accessibilityUnit
+ " "
+ warningMessage
+ "Error: "
+ e);
}
}

public ReactTtsSpan build() {
return new ReactTtsSpan(mType, mArgs);
}

public C setIntArgument(String arg, int value) {
mArgs.putInt(arg, value);
return (C) this;
}

public C setStringArgument(String arg, String value) {
mArgs.putString(arg, value);
return (C) this;
}
}
}
Loading