Skip to content

Commit

Permalink
[#631]【1300开源版本】无障碍新增组件属性方法(rfc:#2) (#634)
Browse files Browse the repository at this point in the history
[#631]【1300联盟版本】无障碍新增组件属性方法(rfc:#2)
  • Loading branch information
mingcan-mc authored Dec 18, 2023
1 parent 047977d commit f086154
Show file tree
Hide file tree
Showing 71 changed files with 866 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import androidx.collection.ArraySet;
Expand Down Expand Up @@ -100,6 +101,7 @@
import org.hapjs.runtime.ProviderManager;
import org.hapjs.runtime.RuntimeActivity;
import org.hapjs.system.SysOpProvider;
import org.hapjs.system.utils.TalkBackUtils;
import org.json.JSONException;
import org.json.JSONObject;

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

public static final int INVALID_PAGE_ID = -1;
public static final String METHOD_FOCUS = "focus";
public static final String METHOD_TALKBACK_FOCUS = "requestTalkBackFocus";
public static final String METHOD_TALKBACK_ANNOUNCE = "announceForTalkBack";
public static final String METHOD_ANIMATE = "animate";
public static final String METHOD_REQUEST_FULLSCREEN = "requestFullscreen";
public static final String METHOD_GET_BOUNDING_CLIENT_RECT = "getBoundingClientRect";
Expand Down Expand Up @@ -990,10 +994,12 @@ protected boolean setAttribute(String key, Object attribute) {
setFocusable(focusable);
return true;
case Attributes.Style.ARIA_LABEL:
case Attributes.Style.ARIA_LABEL_LOWER:
String ariaLabel = Attributes.getString(attribute);
setAriaLabel(ariaLabel);
return true;
case Attributes.Style.ARIA_UNFOCUSABLE:
case Attributes.Style.ARIA_UNFOCUSABLE_LOWER:
boolean ariaUnfocusable = Attributes.getBoolean(attribute, true);
setAriaUnfocusable(ariaUnfocusable);
return true;
Expand Down Expand Up @@ -2933,6 +2939,14 @@ public void invokeMethod(String methodName, final Map<String, Object> args) {
focus = Attributes.getBoolean(args.get("focus"), true);
}
focus(focus);
} else if (METHOD_TALKBACK_FOCUS.equals(methodName)) {
requestTalkBackFocus();
} else if (METHOD_TALKBACK_ANNOUNCE.equals(methodName)) {
String content = null;
if (args != null && args.get("content") != null) {
content = Attributes.getString(args.get("content"), "");
}
announceForTalkBack(content);
} else if (METHOD_REQUEST_FULLSCREEN.equals(methodName)) {
int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
if (args != null) {
Expand Down Expand Up @@ -4342,4 +4356,56 @@ public float getMinShowLevel() {
public float getMaxShowLevel() {
return mMaxShowLevel;
}

public void requestTalkBackFocus() {
if (isEnableTalkBack() && mHost != null) {
if (mHost.isAttachedToWindow()) {
mHost.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
} else {
Log.w(TAG, "requestTalkBackFocus is not valid.");
mHost.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
mHost.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
mHost.removeOnAttachStateChangeListener(this);
}

@Override
public void onViewDetachedFromWindow(View v) {

}
});
}
}
}

public void announceForTalkBack(String content) {
if (isEnableTalkBack() && mHost != null && !TextUtils.isEmpty(content)) {
if (mHost.isAttachedToWindow()) {
mHost.announceForAccessibility(content);
} else {
Log.w(TAG, "announceForTalkBack is not valid.");
mHost.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
mHost.announceForAccessibility(content);
mHost.removeOnAttachStateChangeListener(this);
}

@Override
public void onViewDetachedFromWindow(View v) {

}
});
}
}
}

public boolean isEnableTalkBack() {
return TalkBackUtils.isEnableTalkBack(mContext, false);
}

public void performComponentClick(MotionEvent event) {

}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, the hapjs-platform Project Contributors
* Copyright (c) 2021-present, the hapjs-platform Project Contributors
* SPDX-License-Identifier: Apache-2.0
*/

Expand All @@ -25,7 +25,7 @@ public abstract class RecyclerDataItem implements ComponentDataHolder {
private final CombinedMap<String, CSSValues> mStyleDomData = new CombinedMap<>();
private final CombinedMap<String, Object> mAttrsDomData = new CombinedMap<>();
private final CombinedMap<String, Boolean> mEventDomData = new CombinedMap<>();
private final ComponentCreator mComponentCreator;
protected final ComponentCreator mComponentCreator;
protected Node mCssNode;
private Container.RecyclerItem mParent;
private Component mBoundRecycleComponent;
Expand Down Expand Up @@ -384,6 +384,10 @@ public static class ComponentCreator {
private RenderEventCallback mCallback;
private Widget mWidget;

public Context getContext() {
return mContext;
}

public ComponentCreator(
HapEngine hapEngine, Context context, RenderEventCallback callback, Widget widget) {
mHapEngine = hapEngine;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,9 @@ public interface Style {
String MODE = "mode";

String ARIA_LABEL = "ariaLabel";
String ARIA_LABEL_LOWER = "arialabel";
String ARIA_UNFOCUSABLE = "ariaUnfocusable";
String ARIA_UNFOCUSABLE_LOWER = "ariaunfocusable";

String FORCE_DARK = "forcedark";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, the hapjs-platform Project Contributors
* Copyright (c) 2021-present, the hapjs-platform Project Contributors
* SPDX-License-Identifier: Apache-2.0
*/

Expand Down Expand Up @@ -29,6 +29,7 @@
import org.hapjs.component.view.helper.StateHelper;
import org.hapjs.component.view.keyevent.KeyEventDelegate;
import org.hapjs.render.vdom.DocComponent;
import org.hapjs.system.utils.TalkBackUtils;

public class PercentFlexboxLayout extends YogaLayout implements ComponentHost, GestureHost {

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

private List<Integer> mPositionArray;
private boolean mDisallowIntercept = false;
private boolean mIsEnableTalkBack;
private MotionEvent mLastMotionEvent = null;

public PercentFlexboxLayout(Context context) {
super(context);
mIsEnableTalkBack = TalkBackUtils.isEnableTalkBack(context, false);
getYogaNode().setFlexDirection(YogaFlexDirection.ROW);
getYogaNode().setFlexShrink(1f);
}

@Override
public boolean performClick() {
boolean isConsume = super.performClick();
if (mIsEnableTalkBack) {
if (null != mComponent) {
mComponent.performComponentClick(mLastMotionEvent);
}
}
return isConsume;
}


@Override
protected boolean dispatchHoverEvent(MotionEvent event) {
mLastMotionEvent = event;
return super.dispatchHoverEvent(event);
}

@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mLastMotionEvent = null;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!(getParent() instanceof YogaLayout)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, the hapjs-platform Project Contributors
* Copyright (c) 2021-present, the hapjs-platform Project Contributors
* SPDX-License-Identifier: Apache-2.0
*/

Expand Down Expand Up @@ -32,6 +32,7 @@
import org.hapjs.model.videodata.VideoCacheManager;
import org.hapjs.render.RootView;
import org.hapjs.render.jsruntime.JsThread;
import org.hapjs.system.utils.TalkBackUtils;

public class RuntimeActivity extends AppCompatActivity {
public static final String PROP_APP = "runtime.app";
Expand Down Expand Up @@ -418,6 +419,7 @@ protected void onResume() {
if (mHybridView != null) {
mHybridView.getHybridManager().onResume();
}
TalkBackUtils.isEnableTalkBack(RuntimeActivity.this,true);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -571,4 +571,8 @@ public void updateConfiguration(Context context, Configuration configuration) {

}

public boolean isEnableTalkBack(Context context) {
return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,6 @@ interface OnUpdateMenubarDataCallback {
float getScaleShowLevel(Context context);

void updateConfiguration(Context context, Configuration configuration);

boolean isEnableTalkBack(Context context);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2023-present, the hapjs-platform Project Contributors
* SPDX-License-Identifier: Apache-2.0
*/
package org.hapjs.system.utils;

import android.content.ComponentName;
import android.content.Context;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;

import org.hapjs.runtime.ProviderManager;
import org.hapjs.system.SysOpProvider;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class TalkBackUtils {
private final static String TAG = "TalkBackUtils";
/*
* 获取当前开启的所有辅助功能服务
*/
static int sTalkBackEnable = -1;
static volatile boolean sIsForceCheck;
static volatile boolean sIsChecking;
static final int TALKBACK_ENABLE = 1;
static final int TALKBACK_DISABLE = 0;
static final int TALKBACK_DEFAULT = -1;
static final char ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ':';
static final ComponentName TALKBACK_SERVICE_ENABLE = ComponentName.unflattenFromString("com.google.android.marvin.talkback/com.google.android.marvin.talkback.TalkBackService");
final static TextUtils.SimpleStringSplitter sStringColonSplitter =
new TextUtils.SimpleStringSplitter(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);

private static Set<ComponentName> getEnabledServicesFromSettings(Context context) {
Set<ComponentName> enabledServices = null;
if (null == context) {
return enabledServices;
}
try {
String enabledServicesSetting = Settings.Secure.getString(context.getContentResolver(), "enabled_accessibility_services");
if (TextUtils.isEmpty(enabledServicesSetting)) {
return Collections.emptySet();
} else {
enabledServices = new HashSet();
TextUtils.SimpleStringSplitter colonSplitter = sStringColonSplitter;
colonSplitter.setString(enabledServicesSetting);
while (colonSplitter.hasNext()) {
String componentNameString = colonSplitter.next();
ComponentName enabledService = ComponentName.unflattenFromString(componentNameString);
if (enabledService != null) {
enabledServices.add(enabledService);
}
}
return enabledServices;
}
} catch (Exception e) {
Log.e(TAG, "getEnabledServicesFromSettings error : " + e.getMessage());
}
return enabledServices;
}

public static void setIsForceCheck(boolean isForceCheck) {
TalkBackUtils.sIsForceCheck = isForceCheck;
}

public static boolean isEnableTalkBack(Context context, boolean forceCheck) {
if (sIsChecking) {
return false;
}
if ((sIsForceCheck || forceCheck || sTalkBackEnable == TALKBACK_DEFAULT) && null != context) {
sIsForceCheck = false;
sIsChecking = true;
boolean isEnable = false;
SysOpProvider provider = ProviderManager.getDefault().getProvider(SysOpProvider.NAME);
if (null != provider) {
isEnable = provider.isEnableTalkBack(context);
}
if (isEnable) {
Set<ComponentName> componentNames = getEnabledServicesFromSettings(context);
if (null != componentNames && componentNames.contains(TALKBACK_SERVICE_ENABLE)) {
sTalkBackEnable = TALKBACK_ENABLE;
sIsChecking = false;
return true;
}
}
sTalkBackEnable = TALKBACK_DISABLE;
sIsChecking = false;
return false;
} else {
return sTalkBackEnable == TALKBACK_ENABLE;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>

<!--
Copyright (c) 2021-2022, the hapjs-platform Project Contributors
Copyright (c) 2021-present, the hapjs-platform Project Contributors
SPDX-License-Identifier: Apache-2.0
-->

Expand Down Expand Up @@ -46,7 +46,8 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_gravity="center"
android:src="@drawable/menu_dot" />
android:src="@drawable/menu_dot"
android:contentDescription="@string/talkback_titlebar_left_menu_iv"/>
</LinearLayout>

<LinearLayout
Expand Down Expand Up @@ -100,7 +101,8 @@
android:layout_width="@dimen/menubar_dialog_menu_close_image_width"
android:layout_height="@dimen/menubar_dialog_menu_close_image_height"
android:layout_gravity="center"
android:src="@drawable/menu_close" />
android:src="@drawable/menu_close"
android:contentDescription="@string/talkback_close"/>
</LinearLayout>
</LinearLayout>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,10 @@
<string name="shortcut_add_shortcut_mini">加桌</string>
<string name="shortcut_add_shortcut_desktop">桌面</string>
<string name="shortcut_add_shortcut_long">添加到桌面</string>

<!--menubar 无障碍-->
<string name="talkback_titlebar_left_menu_iv">更多-按钮</string>
<string name="popup_window_default_title">弹出式窗口</string>
<string name="talkback_close">关闭-按钮</string>
<string name="talkback_common_button">按钮</string>
</resources>
5 changes: 5 additions & 0 deletions core/runtime/android/runtime/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,9 @@
<string name="shortcut_add_shortcut_mini">Add to desktop</string>
<string name="shortcut_add_shortcut_desktop">Add to desktop</string>
<string name="shortcut_add_shortcut_long">Add to desktop</string>
<!--menubar 无障碍-->
<string name="talkback_titlebar_left_menu_iv">more-button</string>
<string name="popup_window_default_title">pop-up window</string>
<string name="talkback_close">close-button</string>
<string name="talkback_common_button">button</string>
</resources>
Loading

0 comments on commit f086154

Please sign in to comment.