Skip to content

Commit

Permalink
Fix selectionColor doesn't style Android TextInput selection handles (#…
Browse files Browse the repository at this point in the history
…31007)

Summary:
This issue fixes #30283 selectionColor does not change the handles color.

The method setCursorColor changes the cursor color of field `mCursorDrawable` using a reflection for Android Devices lower then API 28. This fix adds a reflection to change color of the left, center and right handles of a selection (mTextSelectHandleLeftRes, mTextSelectHandleRes and mTextSelectHandleRightRes).

## 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] [Fixed] - Fix selectionColor doesn't style Android TextInput selection handles

Pull Request resolved: #31007

Test Plan:
This changes fix the Java API for which I can not write Java tests as explained in commit 709a441
The java TextInputTest was excluded from the test suite in commit 709a441 as they need the Yoga libraries to run

**<details><summary>CLICK TO OPEN TESTS RESULTS - API 22</summary>**
<p>

left/right handles do not change color with the cursor

| **BEFORE** |
|:-------------------------:|
| <img src="https://user-images.githubusercontent.com/24992535/108241887-98351180-714c-11eb-9c7b-7c693ea0bb06.png" width="250" height="" /> |

center Handle color does not change color

| **BEFORE** |
|:-------------------------:|
| <img src="https://user-images.githubusercontent.com/24992535/108241904-9ec38900-714c-11eb-9fc3-dbd26f83b979.png" width="250" height="" /> |

The left and right handle change color with the cursor color

| **AFTER** |
|:-------------------------:|
| <img src="https://user-images.githubusercontent.com/24992535/108241796-805d8d80-714c-11eb-9d90-6871ddaea86f.png" width="250" height="" /> |

The center handle color is correctly updated

| **AFTER** |
|:-------------------------:|
| <img src="https://user-images.githubusercontent.com/24992535/108241571-45f3f080-714c-11eb-8475-86e6dea64d73.png" width="250" height="" /> |

`setCursorColor` changes correctly the cursor color

| **AFTER** |
|:-------------------------:|
| <img src="https://user-images.githubusercontent.com/24992535/108241484-2d83d600-714c-11eb-8a0c-80a847f28537.png" width="250" height="" /> |

Default Colors do not have issues

| **AFTER** |
|:-------------------------:|
| <img src="https://user-images.githubusercontent.com/24992535/108241346-04634580-714c-11eb-933e-0dce504498a8.png" width="250" height="" /> |

| **AFTER** |
|:-------------------------:|
| <img src="https://user-images.githubusercontent.com/24992535/108241347-04fbdc00-714c-11eb-902a-fc057cf94986.png" width="250" height="" /> |

</p>
</details>

Reviewed By: ShikaSD

Differential Revision: D28682935

Pulled By: sota000

fbshipit-source-id: ff037c93f36bbf20c915373b995bbfd8e8ca92d0
  • Loading branch information
fabOnReact authored and facebook-github-bot committed Aug 16, 2021
1 parent c29ec46 commit 5819538
Showing 1 changed file with 42 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,15 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
private static final String KEYBOARD_TYPE_URI = "url";
private static final InputFilter[] EMPTY_FILTERS = new InputFilter[0];
private static final int UNSET = -1;
private static final String[] DRAWABLE_FIELDS = {
"mCursorDrawable", "mSelectHandleLeft", "mSelectHandleRight", "mSelectHandleCenter"
};
private static final String[] DRAWABLE_RESOURCES = {
"mCursorDrawableRes",
"mTextSelectHandleLeftRes",
"mTextSelectHandleRightRes",
"mTextSelectHandleRes"
};

protected @Nullable ReactTextViewManagerCallback mReactTextViewManagerCallback;

Expand Down Expand Up @@ -507,34 +516,40 @@ public void setCursorColor(ReactEditText view, @Nullable Integer color) {
}

// The evil code that follows uses reflection to achieve this on Android 8.1 and below.
// Based on
// http://stackoverflow.com/questions/25996032/how-to-change-programatically-edittext-cursor-color-in-android.
try {
// Get the original cursor drawable resource.
Field cursorDrawableResField = TextView.class.getDeclaredField("mCursorDrawableRes");
cursorDrawableResField.setAccessible(true);
int drawableResId = cursorDrawableResField.getInt(view);

// The view has no cursor drawable.
if (drawableResId == 0) {
return;
}
// Based on https://tinyurl.com/3vff8lyu https://tinyurl.com/vehggzs9
for (int i = 0; i < DRAWABLE_RESOURCES.length; i++) {
try {
Field drawableResourceField = TextView.class.getDeclaredField(DRAWABLE_RESOURCES[i]);
drawableResourceField.setAccessible(true);
int resourceId = drawableResourceField.getInt(view);

Drawable drawable = ContextCompat.getDrawable(view.getContext(), drawableResId);
drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
Drawable[] drawables = {drawable, drawable};

// Update the current cursor drawable with the new one.
Field editorField = TextView.class.getDeclaredField("mEditor");
editorField.setAccessible(true);
Object editor = editorField.get(view);
Field cursorDrawableField = editor.getClass().getDeclaredField("mCursorDrawable");
cursorDrawableField.setAccessible(true);
cursorDrawableField.set(editor, drawables);
} catch (NoSuchFieldException ex) {
// Ignore errors to avoid crashing if these private fields don't exist on modified
// or future android versions.
} catch (IllegalAccessException ex) {
// The view has no cursor drawable.
if (resourceId == 0) {
return;
}

Drawable drawable = ContextCompat.getDrawable(view.getContext(), resourceId);

Drawable drawableCopy = drawable.mutate();
drawableCopy.setColorFilter(color, PorterDuff.Mode.SRC_IN);

Field editorField = TextView.class.getDeclaredField("mEditor");
editorField.setAccessible(true);
Object editor = editorField.get(view);

Field cursorDrawableField = editor.getClass().getDeclaredField(DRAWABLE_FIELDS[i]);
cursorDrawableField.setAccessible(true);
if (DRAWABLE_RESOURCES[i] == "mCursorDrawableRes") {
Drawable[] drawables = {drawableCopy, drawableCopy};
cursorDrawableField.set(editor, drawables);
} else {
cursorDrawableField.set(editor, drawableCopy);
}
} catch (NoSuchFieldException ex) {
// Ignore errors to avoid crashing if these private fields don't exist on modified
// or future android versions.
} catch (IllegalAccessException ex) {
}
}
}

Expand Down

0 comments on commit 5819538

Please sign in to comment.