99
1010import android .annotation .TargetApi ;
1111import android .content .Context ;
12+ import android .content .ContentResolver ;
13+ import android .database .ContentObserver ;
14+ import android .net .Uri ;
1215import android .os .Build ;
16+ import android .os .Handler ;
17+ import android .os .Looper ;
18+ import android .provider .Settings ;
1319import android .view .accessibility .AccessibilityManager ;
1420
1521import com .facebook .react .bridge .Callback ;
@@ -36,21 +42,42 @@ private class ReactTouchExplorationStateChangeListener
3642
3743 @ Override
3844 public void onTouchExplorationStateChanged (boolean enabled ) {
39- updateAndSendChangeEvent (enabled );
45+ updateAndSendTouchExplorationChangeEvent (enabled );
4046 }
4147 }
4248
49+ // Listener that is notified when the global TRANSITION_ANIMATION_SCALE.
50+ private final ContentObserver animationScaleObserver = new ContentObserver (new Handler (Looper .getMainLooper ())) {
51+ @ Override
52+ public void onChange (boolean selfChange ) {
53+ this .onChange (selfChange , null );
54+ }
55+
56+ @ Override
57+ public void onChange (boolean selfChange , Uri uri ) {
58+ if (getReactApplicationContext ().hasActiveCatalystInstance ()) {
59+ AccessibilityInfoModule .this .updateAndSendReduceMotionChangeEvent ();
60+ }
61+ }
62+ };
63+
4364 private @ Nullable AccessibilityManager mAccessibilityManager ;
4465 private @ Nullable ReactTouchExplorationStateChangeListener mTouchExplorationStateChangeListener ;
45- private boolean mEnabled = false ;
66+ private final ContentResolver mContentResolver ;
67+ private boolean mReduceMotionEnabled = false ;
68+ private boolean mTouchExplorationEnabled = false ;
4669
47- private static final String EVENT_NAME = "touchExplorationDidChange" ;
70+ private static final String REDUCE_MOTION_EVENT_NAME = "reduceMotionDidChange" ;
71+ private static final String TOUCH_EXPLORATION_EVENT_NAME = "touchExplorationDidChange" ;
4872
4973 public AccessibilityInfoModule (ReactApplicationContext context ) {
5074 super (context );
5175 Context appContext = context .getApplicationContext ();
5276 mAccessibilityManager = (AccessibilityManager ) appContext .getSystemService (Context .ACCESSIBILITY_SERVICE );
53- mEnabled = mAccessibilityManager .isTouchExplorationEnabled ();
77+ mContentResolver = getReactApplicationContext ().getContentResolver ();
78+ mTouchExplorationEnabled = mAccessibilityManager .isTouchExplorationEnabled ();
79+ mReduceMotionEnabled = this .getIsReduceMotionEnabledValue ();
80+
5481 if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .KITKAT ) {
5582 mTouchExplorationStateChangeListener = new ReactTouchExplorationStateChangeListener ();
5683 }
@@ -61,16 +88,41 @@ public String getName() {
6188 return "AccessibilityInfo" ;
6289 }
6390
91+ private boolean getIsReduceMotionEnabledValue () {
92+ String value = Build .VERSION .SDK_INT < Build .VERSION_CODES .JELLY_BEAN_MR1 ? null
93+ : Settings .Global .getString (
94+ mContentResolver ,
95+ Settings .Global .TRANSITION_ANIMATION_SCALE
96+ );
97+
98+ return value != null && value .equals ("0.0" );
99+ }
100+
101+ @ ReactMethod
102+ public void isReduceMotionEnabled (Callback successCallback ) {
103+ successCallback .invoke (mReduceMotionEnabled );
104+ }
105+
64106 @ ReactMethod
65107 public void isTouchExplorationEnabled (Callback successCallback ) {
66- successCallback .invoke (mEnabled );
108+ successCallback .invoke (mTouchExplorationEnabled );
109+ }
110+
111+ private void updateAndSendReduceMotionChangeEvent () {
112+ boolean isReduceMotionEnabled = this .getIsReduceMotionEnabledValue ();
113+
114+ if (mReduceMotionEnabled != isReduceMotionEnabled ) {
115+ mReduceMotionEnabled = isReduceMotionEnabled ;
116+ getReactApplicationContext ().getJSModule (DeviceEventManagerModule .RCTDeviceEventEmitter .class )
117+ .emit (REDUCE_MOTION_EVENT_NAME , mReduceMotionEnabled );
118+ }
67119 }
68120
69- private void updateAndSendChangeEvent (boolean enabled ) {
70- if (mEnabled != enabled ) {
71- mEnabled = enabled ;
121+ private void updateAndSendTouchExplorationChangeEvent (boolean enabled ) {
122+ if (mTouchExplorationEnabled != enabled ) {
123+ mTouchExplorationEnabled = enabled ;
72124 getReactApplicationContext ().getJSModule (DeviceEventManagerModule .RCTDeviceEventEmitter .class )
73- .emit (EVENT_NAME , mEnabled );
125+ .emit (TOUCH_EXPLORATION_EVENT_NAME , mTouchExplorationEnabled );
74126 }
75127 }
76128
@@ -80,7 +132,14 @@ public void onHostResume() {
80132 mAccessibilityManager .addTouchExplorationStateChangeListener (
81133 mTouchExplorationStateChangeListener );
82134 }
83- updateAndSendChangeEvent (mAccessibilityManager .isTouchExplorationEnabled ());
135+
136+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .JELLY_BEAN_MR1 ) {
137+ Uri transitionUri = Settings .Global .getUriFor (Settings .Global .TRANSITION_ANIMATION_SCALE );
138+ mContentResolver .registerContentObserver (transitionUri , false , animationScaleObserver );
139+ }
140+
141+ updateAndSendTouchExplorationChangeEvent (mAccessibilityManager .isTouchExplorationEnabled ());
142+ updateAndSendReduceMotionChangeEvent ();
84143 }
85144
86145 @ Override
@@ -89,12 +148,17 @@ public void onHostPause() {
89148 mAccessibilityManager .removeTouchExplorationStateChangeListener (
90149 mTouchExplorationStateChangeListener );
91150 }
151+
152+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .JELLY_BEAN_MR1 ) {
153+ mContentResolver .unregisterContentObserver (animationScaleObserver );
154+ }
92155 }
93156
94157 @ Override
95158 public void initialize () {
96159 getReactApplicationContext ().addLifecycleEventListener (this );
97- updateAndSendChangeEvent (mAccessibilityManager .isTouchExplorationEnabled ());
160+ updateAndSendTouchExplorationChangeEvent (mAccessibilityManager .isTouchExplorationEnabled ());
161+ updateAndSendReduceMotionChangeEvent ();
98162 }
99163
100164 @ Override
0 commit comments