Skip to content

Commit f086154

Browse files
authored
[#631]【1300开源版本】无障碍新增组件属性方法(rfc:#2) (#634)
[#631]【1300联盟版本】无障碍新增组件属性方法(rfc:#2)
1 parent 047977d commit f086154

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+866
-106
lines changed

core/runtime/android/runtime/src/main/java/org/hapjs/component/Component.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import android.view.ViewGroup;
2929
import android.view.ViewParent;
3030
import android.view.ViewTreeObserver;
31+
import android.view.accessibility.AccessibilityEvent;
3132
import android.widget.RelativeLayout;
3233
import androidx.annotation.NonNull;
3334
import androidx.collection.ArraySet;
@@ -100,6 +101,7 @@
100101
import org.hapjs.runtime.ProviderManager;
101102
import org.hapjs.runtime.RuntimeActivity;
102103
import org.hapjs.system.SysOpProvider;
104+
import org.hapjs.system.utils.TalkBackUtils;
103105
import org.json.JSONException;
104106
import org.json.JSONObject;
105107

@@ -108,6 +110,8 @@ public abstract class Component<T extends View>
108110

109111
public static final int INVALID_PAGE_ID = -1;
110112
public static final String METHOD_FOCUS = "focus";
113+
public static final String METHOD_TALKBACK_FOCUS = "requestTalkBackFocus";
114+
public static final String METHOD_TALKBACK_ANNOUNCE = "announceForTalkBack";
111115
public static final String METHOD_ANIMATE = "animate";
112116
public static final String METHOD_REQUEST_FULLSCREEN = "requestFullscreen";
113117
public static final String METHOD_GET_BOUNDING_CLIENT_RECT = "getBoundingClientRect";
@@ -990,10 +994,12 @@ protected boolean setAttribute(String key, Object attribute) {
990994
setFocusable(focusable);
991995
return true;
992996
case Attributes.Style.ARIA_LABEL:
997+
case Attributes.Style.ARIA_LABEL_LOWER:
993998
String ariaLabel = Attributes.getString(attribute);
994999
setAriaLabel(ariaLabel);
9951000
return true;
9961001
case Attributes.Style.ARIA_UNFOCUSABLE:
1002+
case Attributes.Style.ARIA_UNFOCUSABLE_LOWER:
9971003
boolean ariaUnfocusable = Attributes.getBoolean(attribute, true);
9981004
setAriaUnfocusable(ariaUnfocusable);
9991005
return true;
@@ -2933,6 +2939,14 @@ public void invokeMethod(String methodName, final Map<String, Object> args) {
29332939
focus = Attributes.getBoolean(args.get("focus"), true);
29342940
}
29352941
focus(focus);
2942+
} else if (METHOD_TALKBACK_FOCUS.equals(methodName)) {
2943+
requestTalkBackFocus();
2944+
} else if (METHOD_TALKBACK_ANNOUNCE.equals(methodName)) {
2945+
String content = null;
2946+
if (args != null && args.get("content") != null) {
2947+
content = Attributes.getString(args.get("content"), "");
2948+
}
2949+
announceForTalkBack(content);
29362950
} else if (METHOD_REQUEST_FULLSCREEN.equals(methodName)) {
29372951
int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
29382952
if (args != null) {
@@ -4342,4 +4356,56 @@ public float getMinShowLevel() {
43424356
public float getMaxShowLevel() {
43434357
return mMaxShowLevel;
43444358
}
4359+
4360+
public void requestTalkBackFocus() {
4361+
if (isEnableTalkBack() && mHost != null) {
4362+
if (mHost.isAttachedToWindow()) {
4363+
mHost.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
4364+
} else {
4365+
Log.w(TAG, "requestTalkBackFocus is not valid.");
4366+
mHost.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
4367+
@Override
4368+
public void onViewAttachedToWindow(View v) {
4369+
mHost.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
4370+
mHost.removeOnAttachStateChangeListener(this);
4371+
}
4372+
4373+
@Override
4374+
public void onViewDetachedFromWindow(View v) {
4375+
4376+
}
4377+
});
4378+
}
4379+
}
4380+
}
4381+
4382+
public void announceForTalkBack(String content) {
4383+
if (isEnableTalkBack() && mHost != null && !TextUtils.isEmpty(content)) {
4384+
if (mHost.isAttachedToWindow()) {
4385+
mHost.announceForAccessibility(content);
4386+
} else {
4387+
Log.w(TAG, "announceForTalkBack is not valid.");
4388+
mHost.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
4389+
@Override
4390+
public void onViewAttachedToWindow(View v) {
4391+
mHost.announceForAccessibility(content);
4392+
mHost.removeOnAttachStateChangeListener(this);
4393+
}
4394+
4395+
@Override
4396+
public void onViewDetachedFromWindow(View v) {
4397+
4398+
}
4399+
});
4400+
}
4401+
}
4402+
}
4403+
4404+
public boolean isEnableTalkBack() {
4405+
return TalkBackUtils.isEnableTalkBack(mContext, false);
4406+
}
4407+
4408+
public void performComponentClick(MotionEvent event) {
4409+
4410+
}
43454411
}

core/runtime/android/runtime/src/main/java/org/hapjs/component/RecyclerDataItem.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, the hapjs-platform Project Contributors
2+
* Copyright (c) 2021-present, the hapjs-platform Project Contributors
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

@@ -25,7 +25,7 @@ public abstract class RecyclerDataItem implements ComponentDataHolder {
2525
private final CombinedMap<String, CSSValues> mStyleDomData = new CombinedMap<>();
2626
private final CombinedMap<String, Object> mAttrsDomData = new CombinedMap<>();
2727
private final CombinedMap<String, Boolean> mEventDomData = new CombinedMap<>();
28-
private final ComponentCreator mComponentCreator;
28+
protected final ComponentCreator mComponentCreator;
2929
protected Node mCssNode;
3030
private Container.RecyclerItem mParent;
3131
private Component mBoundRecycleComponent;
@@ -384,6 +384,10 @@ public static class ComponentCreator {
384384
private RenderEventCallback mCallback;
385385
private Widget mWidget;
386386

387+
public Context getContext() {
388+
return mContext;
389+
}
390+
387391
public ComponentCreator(
388392
HapEngine hapEngine, Context context, RenderEventCallback callback, Widget widget) {
389393
mHapEngine = hapEngine;

core/runtime/android/runtime/src/main/java/org/hapjs/component/constants/Attributes.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,9 @@ public interface Style {
591591
String MODE = "mode";
592592

593593
String ARIA_LABEL = "ariaLabel";
594+
String ARIA_LABEL_LOWER = "arialabel";
594595
String ARIA_UNFOCUSABLE = "ariaUnfocusable";
596+
String ARIA_UNFOCUSABLE_LOWER = "ariaunfocusable";
595597

596598
String FORCE_DARK = "forcedark";
597599

core/runtime/android/runtime/src/main/java/org/hapjs/component/view/flexbox/PercentFlexboxLayout.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, the hapjs-platform Project Contributors
2+
* Copyright (c) 2021-present, the hapjs-platform Project Contributors
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

@@ -29,6 +29,7 @@
2929
import org.hapjs.component.view.helper.StateHelper;
3030
import org.hapjs.component.view.keyevent.KeyEventDelegate;
3131
import org.hapjs.render.vdom.DocComponent;
32+
import org.hapjs.system.utils.TalkBackUtils;
3233

3334
public class PercentFlexboxLayout extends YogaLayout implements ComponentHost, GestureHost {
3435

@@ -38,13 +39,40 @@ public class PercentFlexboxLayout extends YogaLayout implements ComponentHost, G
3839

3940
private List<Integer> mPositionArray;
4041
private boolean mDisallowIntercept = false;
42+
private boolean mIsEnableTalkBack;
43+
private MotionEvent mLastMotionEvent = null;
4144

4245
public PercentFlexboxLayout(Context context) {
4346
super(context);
47+
mIsEnableTalkBack = TalkBackUtils.isEnableTalkBack(context, false);
4448
getYogaNode().setFlexDirection(YogaFlexDirection.ROW);
4549
getYogaNode().setFlexShrink(1f);
4650
}
4751

52+
@Override
53+
public boolean performClick() {
54+
boolean isConsume = super.performClick();
55+
if (mIsEnableTalkBack) {
56+
if (null != mComponent) {
57+
mComponent.performComponentClick(mLastMotionEvent);
58+
}
59+
}
60+
return isConsume;
61+
}
62+
63+
64+
@Override
65+
protected boolean dispatchHoverEvent(MotionEvent event) {
66+
mLastMotionEvent = event;
67+
return super.dispatchHoverEvent(event);
68+
}
69+
70+
@Override
71+
protected void onDetachedFromWindow() {
72+
super.onDetachedFromWindow();
73+
mLastMotionEvent = null;
74+
}
75+
4876
@Override
4977
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
5078
if (!(getParent() instanceof YogaLayout)) {

core/runtime/android/runtime/src/main/java/org/hapjs/runtime/RuntimeActivity.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, the hapjs-platform Project Contributors
2+
* Copyright (c) 2021-present, the hapjs-platform Project Contributors
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

@@ -32,6 +32,7 @@
3232
import org.hapjs.model.videodata.VideoCacheManager;
3333
import org.hapjs.render.RootView;
3434
import org.hapjs.render.jsruntime.JsThread;
35+
import org.hapjs.system.utils.TalkBackUtils;
3536

3637
public class RuntimeActivity extends AppCompatActivity {
3738
public static final String PROP_APP = "runtime.app";
@@ -418,6 +419,7 @@ protected void onResume() {
418419
if (mHybridView != null) {
419420
mHybridView.getHybridManager().onResume();
420421
}
422+
TalkBackUtils.isEnableTalkBack(RuntimeActivity.this,true);
421423
}
422424

423425
@Override

core/runtime/android/runtime/src/main/java/org/hapjs/system/DefaultSysOpProviderImpl.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,4 +571,8 @@ public void updateConfiguration(Context context, Configuration configuration) {
571571

572572
}
573573

574+
public boolean isEnableTalkBack(Context context) {
575+
return false;
576+
}
577+
574578
}

core/runtime/android/runtime/src/main/java/org/hapjs/system/SysOpProvider.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,4 +190,6 @@ interface OnUpdateMenubarDataCallback {
190190
float getScaleShowLevel(Context context);
191191

192192
void updateConfiguration(Context context, Configuration configuration);
193+
194+
boolean isEnableTalkBack(Context context);
193195
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright (c) 2023-present, the hapjs-platform Project Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
package org.hapjs.system.utils;
6+
7+
import android.content.ComponentName;
8+
import android.content.Context;
9+
import android.provider.Settings;
10+
import android.text.TextUtils;
11+
import android.util.Log;
12+
13+
import org.hapjs.runtime.ProviderManager;
14+
import org.hapjs.system.SysOpProvider;
15+
16+
import java.util.Collections;
17+
import java.util.HashSet;
18+
import java.util.Set;
19+
20+
public class TalkBackUtils {
21+
private final static String TAG = "TalkBackUtils";
22+
/*
23+
* 获取当前开启的所有辅助功能服务
24+
*/
25+
static int sTalkBackEnable = -1;
26+
static volatile boolean sIsForceCheck;
27+
static volatile boolean sIsChecking;
28+
static final int TALKBACK_ENABLE = 1;
29+
static final int TALKBACK_DISABLE = 0;
30+
static final int TALKBACK_DEFAULT = -1;
31+
static final char ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ':';
32+
static final ComponentName TALKBACK_SERVICE_ENABLE = ComponentName.unflattenFromString("com.google.android.marvin.talkback/com.google.android.marvin.talkback.TalkBackService");
33+
final static TextUtils.SimpleStringSplitter sStringColonSplitter =
34+
new TextUtils.SimpleStringSplitter(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
35+
36+
private static Set<ComponentName> getEnabledServicesFromSettings(Context context) {
37+
Set<ComponentName> enabledServices = null;
38+
if (null == context) {
39+
return enabledServices;
40+
}
41+
try {
42+
String enabledServicesSetting = Settings.Secure.getString(context.getContentResolver(), "enabled_accessibility_services");
43+
if (TextUtils.isEmpty(enabledServicesSetting)) {
44+
return Collections.emptySet();
45+
} else {
46+
enabledServices = new HashSet();
47+
TextUtils.SimpleStringSplitter colonSplitter = sStringColonSplitter;
48+
colonSplitter.setString(enabledServicesSetting);
49+
while (colonSplitter.hasNext()) {
50+
String componentNameString = colonSplitter.next();
51+
ComponentName enabledService = ComponentName.unflattenFromString(componentNameString);
52+
if (enabledService != null) {
53+
enabledServices.add(enabledService);
54+
}
55+
}
56+
return enabledServices;
57+
}
58+
} catch (Exception e) {
59+
Log.e(TAG, "getEnabledServicesFromSettings error : " + e.getMessage());
60+
}
61+
return enabledServices;
62+
}
63+
64+
public static void setIsForceCheck(boolean isForceCheck) {
65+
TalkBackUtils.sIsForceCheck = isForceCheck;
66+
}
67+
68+
public static boolean isEnableTalkBack(Context context, boolean forceCheck) {
69+
if (sIsChecking) {
70+
return false;
71+
}
72+
if ((sIsForceCheck || forceCheck || sTalkBackEnable == TALKBACK_DEFAULT) && null != context) {
73+
sIsForceCheck = false;
74+
sIsChecking = true;
75+
boolean isEnable = false;
76+
SysOpProvider provider = ProviderManager.getDefault().getProvider(SysOpProvider.NAME);
77+
if (null != provider) {
78+
isEnable = provider.isEnableTalkBack(context);
79+
}
80+
if (isEnable) {
81+
Set<ComponentName> componentNames = getEnabledServicesFromSettings(context);
82+
if (null != componentNames && componentNames.contains(TALKBACK_SERVICE_ENABLE)) {
83+
sTalkBackEnable = TALKBACK_ENABLE;
84+
sIsChecking = false;
85+
return true;
86+
}
87+
}
88+
sTalkBackEnable = TALKBACK_DISABLE;
89+
sIsChecking = false;
90+
return false;
91+
} else {
92+
return sTalkBackEnable == TALKBACK_ENABLE;
93+
}
94+
}
95+
}

core/runtime/android/runtime/src/main/res/layout/titlebar_view.xml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22

33
<!--
4-
Copyright (c) 2021-2022, the hapjs-platform Project Contributors
4+
Copyright (c) 2021-present, the hapjs-platform Project Contributors
55
SPDX-License-Identifier: Apache-2.0
66
-->
77

@@ -46,7 +46,8 @@
4646
android:layout_width="16dp"
4747
android:layout_height="16dp"
4848
android:layout_gravity="center"
49-
android:src="@drawable/menu_dot" />
49+
android:src="@drawable/menu_dot"
50+
android:contentDescription="@string/talkback_titlebar_left_menu_iv"/>
5051
</LinearLayout>
5152

5253
<LinearLayout
@@ -100,7 +101,8 @@
100101
android:layout_width="@dimen/menubar_dialog_menu_close_image_width"
101102
android:layout_height="@dimen/menubar_dialog_menu_close_image_height"
102103
android:layout_gravity="center"
103-
android:src="@drawable/menu_close" />
104+
android:src="@drawable/menu_close"
105+
android:contentDescription="@string/talkback_close"/>
104106
</LinearLayout>
105107
</LinearLayout>
106108

core/runtime/android/runtime/src/main/res/values-zh-rCN/strings.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,10 @@
104104
<string name="shortcut_add_shortcut_mini">加桌</string>
105105
<string name="shortcut_add_shortcut_desktop">桌面</string>
106106
<string name="shortcut_add_shortcut_long">添加到桌面</string>
107+
108+
<!--menubar 无障碍-->
109+
<string name="talkback_titlebar_left_menu_iv">更多-按钮</string>
110+
<string name="popup_window_default_title">弹出式窗口</string>
111+
<string name="talkback_close">关闭-按钮</string>
112+
<string name="talkback_common_button">按钮</string>
107113
</resources>

core/runtime/android/runtime/src/main/res/values/strings.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,9 @@
143143
<string name="shortcut_add_shortcut_mini">Add to desktop</string>
144144
<string name="shortcut_add_shortcut_desktop">Add to desktop</string>
145145
<string name="shortcut_add_shortcut_long">Add to desktop</string>
146+
<!--menubar 无障碍-->
147+
<string name="talkback_titlebar_left_menu_iv">more-button</string>
148+
<string name="popup_window_default_title">pop-up window</string>
149+
<string name="talkback_close">close-button</string>
150+
<string name="talkback_common_button">button</string>
146151
</resources>

0 commit comments

Comments
 (0)