feat: add isAccessibilityServiceEnabled (#31396)

Summary:
fix https://github.com/facebook/react-native/issues/30863

This PR adds `isAccessibilityServiceEnabled` to get if accessibility services are enabled on Android.

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[Android] [Added] - Added `isAccessibilityServiceEnabled` to get if accessibility services are enabled

Pull Request resolved: https://github.com/facebook/react-native/pull/31396

Test Plan: ![accessibilityService](https://user-images.githubusercontent.com/40130327/115560972-11d5b100-a2f0-11eb-8aa2-7c52dc71ca59.gif)

Reviewed By: yungsters

Differential Revision: D31911880

Pulled By: lunaleaps

fbshipit-source-id: 9ae294999a6d46bf051ab658507bf97764a945d2
This commit is contained in:
grgr-dkrk
2021-10-29 18:39:38 -07:00
committed by Facebook GitHub Bot
parent bbb52aa276
commit c8b83d4e0b
5 changed files with 98 additions and 1 deletions
@@ -46,6 +46,19 @@ public class AccessibilityInfoModule extends NativeAccessibilityInfoSpec
}
}
// Android can listen for accessibility service enable with `accessibilityStateChange`, but
// `accessibilityState` conflicts with React Native props and confuses developers. Therefore, the
// name `accessibilityServiceChange` is used here instead.
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private class ReactAccessibilityServiceChangeListener
implements AccessibilityManager.AccessibilityStateChangeListener {
@Override
public void onAccessibilityStateChanged(boolean enabled) {
updateAndSendAccessibilityServiceChangeEvent(enabled);
}
}
// Listener that is notified when the global TRANSITION_ANIMATION_SCALE.
private final ContentObserver animationScaleObserver =
new ContentObserver(new Handler(Looper.getMainLooper())) {
@@ -64,13 +77,16 @@ public class AccessibilityInfoModule extends NativeAccessibilityInfoSpec
private @Nullable AccessibilityManager mAccessibilityManager;
private @Nullable ReactTouchExplorationStateChangeListener mTouchExplorationStateChangeListener;
private @Nullable ReactAccessibilityServiceChangeListener mAccessibilityServiceChangeListener;
private final ContentResolver mContentResolver;
private boolean mReduceMotionEnabled = false;
private boolean mTouchExplorationEnabled = false;
private boolean mAccessibilityServiceEnabled = false;
private int mRecommendedTimeout;
private static final String REDUCE_MOTION_EVENT_NAME = "reduceMotionDidChange";
private static final String TOUCH_EXPLORATION_EVENT_NAME = "touchExplorationDidChange";
private static final String ACCESSIBILITY_SERVICE_EVENT_NAME = "accessibilityServiceDidChange";
public AccessibilityInfoModule(ReactApplicationContext context) {
super(context);
@@ -79,8 +95,10 @@ public class AccessibilityInfoModule extends NativeAccessibilityInfoSpec
(AccessibilityManager) appContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
mContentResolver = getReactApplicationContext().getContentResolver();
mTouchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
mAccessibilityServiceEnabled = mAccessibilityManager.isEnabled();
mReduceMotionEnabled = this.getIsReduceMotionEnabledValue();
mTouchExplorationStateChangeListener = new ReactTouchExplorationStateChangeListener();
mAccessibilityServiceChangeListener = new ReactAccessibilityServiceChangeListener();
}
@Override
@@ -106,6 +124,11 @@ public class AccessibilityInfoModule extends NativeAccessibilityInfoSpec
successCallback.invoke(mTouchExplorationEnabled);
}
@Override
public void isAccessibilityServiceEnabled(Callback successCallback) {
successCallback.invoke(mAccessibilityServiceEnabled);
}
private void updateAndSendReduceMotionChangeEvent() {
boolean isReduceMotionEnabled = this.getIsReduceMotionEnabledValue();
@@ -134,16 +157,31 @@ public class AccessibilityInfoModule extends NativeAccessibilityInfoSpec
}
}
private void updateAndSendAccessibilityServiceChangeEvent(boolean enabled) {
if (mAccessibilityServiceEnabled != enabled) {
mAccessibilityServiceEnabled = enabled;
ReactApplicationContext reactApplicationContext = getReactApplicationContextIfActiveOrWarn();
if (reactApplicationContext != null) {
getReactApplicationContext()
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(ACCESSIBILITY_SERVICE_EVENT_NAME, mAccessibilityServiceEnabled);
}
}
}
@Override
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void onHostResume() {
mAccessibilityManager.addTouchExplorationStateChangeListener(
mTouchExplorationStateChangeListener);
mAccessibilityManager.addAccessibilityStateChangeListener(mAccessibilityServiceChangeListener);
Uri transitionUri = Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE);
mContentResolver.registerContentObserver(transitionUri, false, animationScaleObserver);
updateAndSendTouchExplorationChangeEvent(mAccessibilityManager.isTouchExplorationEnabled());
updateAndSendAccessibilityServiceChangeEvent(mAccessibilityManager.isEnabled());
updateAndSendReduceMotionChangeEvent();
}
@@ -152,6 +190,8 @@ public class AccessibilityInfoModule extends NativeAccessibilityInfoSpec
public void onHostPause() {
mAccessibilityManager.removeTouchExplorationStateChangeListener(
mTouchExplorationStateChangeListener);
mAccessibilityManager.removeAccessibilityStateChangeListener(
mAccessibilityServiceChangeListener);
mContentResolver.unregisterContentObserver(animationScaleObserver);
}
@@ -160,6 +200,7 @@ public class AccessibilityInfoModule extends NativeAccessibilityInfoSpec
public void initialize() {
getReactApplicationContext().addLifecycleEventListener(this);
updateAndSendTouchExplorationChangeEvent(mAccessibilityManager.isTouchExplorationEnabled());
updateAndSendAccessibilityServiceChangeEvent(mAccessibilityManager.isEnabled());
updateAndSendReduceMotionChangeEvent();
}