Skip to content

Commit

Permalink
feat(Android): add support for invert colors check on android accessi…
Browse files Browse the repository at this point in the history
…bility (#47341)

Summary:
This PR provides a fix for the long existing issue of missing check for invert color in accessibility options on Android.
Reference Issue : #30870

## Changelog:
- Added native module code to check for invert color settings value
- Updated js module to return a proper promise instead of default false for isInvertColorsEnabled()

Pick one each for the category and type tags:

[ANDROID] [FIXED] - Missing isInvertColorsEnabled implementation for Android

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests

Pull Request resolved: #47341

Test Plan: Tested on OnePlus 12 with Android 14 and Pixel 6 with Android 15. The try catch exists because in some cases if the switch hasn't been toggled before the android system raises the missing settings exception.

Reviewed By: cortinico, fabriziocucci

Differential Revision: D65419632

Pulled By: javache

fbshipit-source-id: ddb103445a9d0f318e52ba9d23750140ce5a7ed0
  • Loading branch information
oddlyspaced authored and facebook-github-bot committed Nov 4, 2024
1 parent dc9db01 commit cc1d285
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const EventNames: Map<
['highTextContrastChanged', 'highTextContrastDidChange'],
['screenReaderChanged', 'touchExplorationDidChange'],
['accessibilityServiceChanged', 'accessibilityServiceDidChange'],
['invertColorsChanged', 'invertColorDidChange'],
])
: new Map([
['announcementFinished', 'announcementFinished'],
Expand Down Expand Up @@ -138,7 +139,13 @@ const AccessibilityInfo = {
*/
isInvertColorsEnabled(): Promise<boolean> {
if (Platform.OS === 'android') {
return Promise.resolve(false);
return new Promise((resolve, reject) => {
if (NativeAccessibilityInfoAndroid?.isInvertColorsEnabled != null) {
NativeAccessibilityInfoAndroid.isInvertColorsEnabled(resolve);
} else {
reject(null);
}
});
} else {
return new Promise((resolve, reject) => {
if (NativeAccessibilityManagerIOS != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ internal class AccessibilityInfoModule(context: ReactApplicationContext) :
private var touchExplorationEnabled = false
private var accessibilityServiceEnabled = false
private var recommendedTimeout = 0
private var invertColorsEnabled = false

init {
val appContext = context.applicationContext
Expand All @@ -111,6 +112,17 @@ internal class AccessibilityInfoModule(context: ReactApplicationContext) :
return parsedValue == 0f
}

@get:TargetApi(Build.VERSION_CODES.LOLLIPOP)
private val isInvertColorsEnabledValue: Boolean
get() {
try {
return Settings.Secure.getInt(
contentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) == 1
} catch (e: Settings.SettingNotFoundException) {
return false
}
}

@get:TargetApi(Build.VERSION_CODES.LOLLIPOP)
private val isHighTextContrastEnabledValue: Boolean
get() {
Expand All @@ -125,6 +137,10 @@ internal class AccessibilityInfoModule(context: ReactApplicationContext) :
successCallback.invoke(reduceMotionEnabled)
}

override fun isInvertColorsEnabled(successCallback: Callback) {
successCallback.invoke(invertColorsEnabled)
}

override fun isHighTextContrastEnabled(successCallback: Callback) {
successCallback.invoke(highTextContrastEnabled)
}
Expand All @@ -148,6 +164,17 @@ internal class AccessibilityInfoModule(context: ReactApplicationContext) :
}
}

private fun updateAndSendInvertColorsChangeEvent() {
val isInvertColorsEnabled = isInvertColorsEnabledValue
if (invertColorsEnabled != isInvertColorsEnabled) {
invertColorsEnabled = isInvertColorsEnabled
val reactApplicationContext = getReactApplicationContextIfActiveOrWarn()
if (reactApplicationContext != null) {
reactApplicationContext.emitDeviceEvent(INVERT_COLOR_EVENT_NAME, invertColorsEnabled)
}
}
}

private fun updateAndSendHighTextContrastChangeEvent() {
val isHighTextContrastEnabled = isHighTextContrastEnabledValue
if (highTextContrastEnabled != isHighTextContrastEnabled) {
Expand Down Expand Up @@ -199,6 +226,7 @@ internal class AccessibilityInfoModule(context: ReactApplicationContext) :
updateAndSendAccessibilityServiceChangeEvent(accessibilityManager?.isEnabled == true)
updateAndSendReduceMotionChangeEvent()
updateAndSendHighTextContrastChangeEvent()
updateAndSendInvertColorsChangeEvent()
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
Expand Down Expand Up @@ -263,5 +291,6 @@ internal class AccessibilityInfoModule(context: ReactApplicationContext) :
private const val ACCESSIBILITY_SERVICE_EVENT_NAME = "accessibilityServiceDidChange"
private const val ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED_CONSTANT =
"high_text_contrast_enabled" // constant is marked with @hide
private const val INVERT_COLOR_EVENT_NAME = "invertColorDidChange"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ export interface Spec extends TurboModule {
+isReduceMotionEnabled: (
onSuccess: (isReduceMotionEnabled: boolean) => void,
) => void;
+isInvertColorsEnabled?: (
onSuccess: (isInvertColorsEnabled: boolean) => void,
) => void;
+isHighTextContrastEnabled?: (
onSuccess: (isHighTextContrastEnabled: boolean) => void,
) => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1341,12 +1341,6 @@ class EnabledExamples extends React.Component<{}> {
eventListener="grayscaleChanged"
/>
</RNTesterBlock>
<RNTesterBlock title="isInvertColorsEnabled()">
<EnabledExample
test="invert colors"
eventListener="invertColorsChanged"
/>
</RNTesterBlock>
<RNTesterBlock title="isReduceTransparencyEnabled()">
<EnabledExample
test="reduce transparency"
Expand Down Expand Up @@ -1376,6 +1370,13 @@ class EnabledExamples extends React.Component<{}> {
/>
</RNTesterBlock>

<RNTesterBlock title="isInvertColorsEnabled()">
<EnabledExample
test="invert colors"
eventListener="invertColorsChanged"
/>
</RNTesterBlock>

<RNTesterBlock title="isScreenReaderEnabled()">
<EnabledExample
test="screen reader"
Expand Down

0 comments on commit cc1d285

Please sign in to comment.