Skip to content

Commit

Permalink
Fix rendering of TextInput in Android 4
Browse files Browse the repository at this point in the history
Summary:
This diff fixes the rendering of TextInput component for Android 4 devices.
This bug was caused by D18196901, when we changed the base class of ReactEditText from EditText to AppCompatEditText.
The root of the problem is that AppCompatEditText wraps the ReactContext received as a parameter in the construction of the View into a ContextWrapper object. This break the implicity assumption that the method View.getContext will return the same context that was used during the construction of the view.
https://android.googlesource.com/platform/frameworks/support/+/dd55716/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java#55

Changelog: [internal]

Reviewed By: ejanzer

Differential Revision: D19204032

fbshipit-source-id: eefb562b1da22e6cc58c75845c87dd032d727f49
  • Loading branch information
mdvacca authored and facebook-github-bot committed Dec 21, 2019
1 parent 282b8b0 commit a8fbbe2
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@

import static com.facebook.react.uimanager.common.UIManagerType.FABRIC;
import static com.facebook.react.uimanager.common.ViewUtil.getUIManagerType;
import com.facebook.react.bridge.CatalystInstance;

import android.content.Context;
import android.content.ContextWrapper;
import android.view.View;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.bridge.JSIModuleType;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactSoftException;
Expand Down Expand Up @@ -65,4 +69,20 @@ public static EventDispatcher getEventDispatcher(
UIManager uiManager = getUIManager(context, uiManagerType);
return uiManager == null ? null : (EventDispatcher) uiManager.getEventDispatcher();
}

/**
* @return The {@link ReactContext} associated to the {@link View} received as a parameter.
* <p>We can't rely that the method View.getContext() will return the same context that was
* passed as a parameter during the construction of the View.
* <p>For example the AppCompatEditText class wraps the context received as a parameter in the
* constructor of the View into a TintContextWrapper object. See:
* https://android.googlesource.com/platform/frameworks/support/+/dd55716/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java#55
*/
public static ReactContext getReactContext(View view) {
Context context = view.getContext();
if (!(context instanceof ReactContext) && context instanceof ContextWrapper) {
context = ((ContextWrapper) context).getBaseContext();
}
return (ReactContext) context;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

package com.facebook.react.views.textinput;

import static com.facebook.react.uimanager.UIManagerHelper.getReactContext;

import android.content.Context;
import android.graphics.Rect;
import android.graphics.Typeface;
Expand Down Expand Up @@ -114,7 +116,7 @@ public ReactEditText(Context context) {
mReactBackgroundManager = new ReactViewBackgroundManager(this);
mInputMethodManager =
(InputMethodManager)
Assertions.assertNotNull(getContext().getSystemService(Context.INPUT_METHOD_SERVICE));
Assertions.assertNotNull(context.getSystemService(Context.INPUT_METHOD_SERVICE));
mDefaultGravityHorizontal =
getGravity() & (Gravity.HORIZONTAL_GRAVITY_MASK | Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK);
mDefaultGravityVertical = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
Expand Down Expand Up @@ -219,7 +221,7 @@ protected void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) {

@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
ReactContext reactContext = (ReactContext) getContext();
ReactContext reactContext = getReactContext(this);
InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
if (inputConnection != null && mOnKeyPress) {
inputConnection =
Expand Down Expand Up @@ -601,7 +603,7 @@ private void setIntrinsicContentSize() {
// Since the LocalData object is constructed by getting values from the underlying EditText
// view, we don't need to construct one or apply it at all - it provides no use in Fabric.
if (mStateWrapper == null) {
ReactContext reactContext = (ReactContext) getContext();
ReactContext reactContext = getReactContext(this);
final ReactTextInputLocalData localData = new ReactTextInputLocalData(this);
UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
uiManager.setViewLocalData(getId(), localData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

package com.facebook.react.views.textinput;

import static com.facebook.react.uimanager.UIManagerHelper.getReactContext;

import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
Expand Down Expand Up @@ -1056,7 +1058,7 @@ private class ReactContentSizeWatcher implements ContentSizeWatcher {

public ReactContentSizeWatcher(ReactEditText editText) {
mEditText = editText;
ReactContext reactContext = (ReactContext) editText.getContext();
ReactContext reactContext = getReactContext(editText);
mEventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
}

Expand Down Expand Up @@ -1099,7 +1101,8 @@ private class ReactSelectionWatcher implements SelectionWatcher {

public ReactSelectionWatcher(ReactEditText editText) {
mReactEditText = editText;
ReactContext reactContext = (ReactContext) editText.getContext();

ReactContext reactContext = getReactContext(editText);
mEventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
}

Expand Down Expand Up @@ -1133,7 +1136,7 @@ private class ReactScrollWatcher implements ScrollWatcher {

public ReactScrollWatcher(ReactEditText editText) {
mReactEditText = editText;
ReactContext reactContext = (ReactContext) editText.getContext();
ReactContext reactContext = getReactContext(editText);
mEventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
}

Expand Down

0 comments on commit a8fbbe2

Please sign in to comment.