77
88package com .facebook .react .views .textinput ;
99
10- import static com .facebook .react .uimanager .UIManagerHelper .getReactContext ;
11-
1210import android .content .Context ;
1311import android .content .res .ColorStateList ;
1412import android .graphics .BlendMode ;
1715import android .graphics .PorterDuff ;
1816import android .graphics .drawable .Drawable ;
1917import android .os .Build ;
20- import android .text .Editable ;
2118import android .text .InputFilter ;
2219import android .text .InputType ;
2320import android .text .Layout ;
2421import android .text .Spannable ;
2522import android .text .SpannableStringBuilder ;
26- import android .text .TextWatcher ;
2723import android .view .Gravity ;
2824import android .view .View ;
2925import android .view .ViewGroup ;
3329import androidx .autofill .HintConstants ;
3430import androidx .core .content .ContextCompat ;
3531import com .facebook .common .logging .FLog ;
36- import com .facebook .infer .annotation .Assertions ;
3732import com .facebook .react .bridge .Dynamic ;
3833import com .facebook .react .bridge .ReactContext ;
3934import com .facebook .react .bridge .ReactSoftExceptionLogger ;
4035import com .facebook .react .bridge .ReadableArray ;
4136import com .facebook .react .bridge .ReadableType ;
42- import com .facebook .react .bridge .WritableMap ;
43- import com .facebook .react .bridge .WritableNativeMap ;
4437import com .facebook .react .common .MapBuilder ;
4538import com .facebook .react .common .ReactConstants ;
4639import com .facebook .react .common .mapbuffer .MapBuffer ;
5043import com .facebook .react .uimanager .LayoutShadowNode ;
5144import com .facebook .react .uimanager .LengthPercentage ;
5245import com .facebook .react .uimanager .LengthPercentageType ;
53- import com .facebook .react .uimanager .PixelUtil ;
5446import com .facebook .react .uimanager .ReactStylesDiffMap ;
5547import com .facebook .react .uimanager .Spacing ;
5648import com .facebook .react .uimanager .StateWrapper ;
6557import com .facebook .react .uimanager .style .BorderStyle ;
6658import com .facebook .react .uimanager .style .LogicalEdge ;
6759import com .facebook .react .views .imagehelper .ResourceDrawableIdHelper ;
68- import com .facebook .react .views .scroll .ScrollEvent ;
6960import com .facebook .react .views .scroll .ScrollEventType ;
7061import com .facebook .react .views .text .DefaultStyleValuesUtil ;
7162import com .facebook .react .views .text .ReactBaseTextShadowNode ;
@@ -453,7 +444,7 @@ private void setAutofillHints(ReactEditText view, String... hints) {
453444 @ ReactProp (name = "onSelectionChange" , defaultBoolean = false )
454445 public void setOnSelectionChange (final ReactEditText view , boolean onSelectionChange ) {
455446 if (onSelectionChange ) {
456- view .setSelectionWatcher (new ReactSelectionWatcher (view ));
447+ view .setSelectionWatcher (new ReactTextSelectionWatcher (view ));
457448 } else {
458449 view .setSelectionWatcher (null );
459450 }
@@ -467,7 +458,7 @@ public void setSubmitBehavior(ReactEditText view, @Nullable String submitBehavio
467458 @ ReactProp (name = "onContentSizeChange" , defaultBoolean = false )
468459 public void setOnContentSizeChange (final ReactEditText view , boolean onContentSizeChange ) {
469460 if (onContentSizeChange ) {
470- view .setContentSizeWatcher (new ReactContentSizeWatcher (view ));
461+ view .setContentSizeWatcher (new ReactTextContentSizeWatcher (view ));
471462 } else {
472463 view .setContentSizeWatcher (null );
473464 }
@@ -476,7 +467,7 @@ public void setOnContentSizeChange(final ReactEditText view, boolean onContentSi
476467 @ ReactProp (name = "onScroll" , defaultBoolean = false )
477468 public void setOnScroll (final ReactEditText view , boolean onScroll ) {
478469 if (onScroll ) {
479- view .setScrollWatcher (new ReactScrollWatcher (view ));
470+ view .setScrollWatcher (new ReactTextScrollWatcher (view ));
480471 } else {
481472 view .setScrollWatcher (null );
482473 }
@@ -1051,73 +1042,12 @@ private static void updateStagedInputTypeFlag(
10511042 view .setStagedInputType ((view .getStagedInputType () & ~flagsToUnset ) | flagsToSet );
10521043 }
10531044
1045+ @ Nullable
10541046 private static EventDispatcher getEventDispatcher (
10551047 ReactContext reactContext , ReactEditText editText ) {
10561048 return UIManagerHelper .getEventDispatcherForReactTag (reactContext , editText .getId ());
10571049 }
10581050
1059- private final class ReactTextInputTextWatcher implements TextWatcher {
1060- private final ReactEditText mEditText ;
1061- private final EventDispatcher mEventDispatcher ;
1062- private final int mSurfaceId ;
1063- @ Nullable private String mPreviousText ;
1064-
1065- public ReactTextInputTextWatcher (
1066- final ReactContext reactContext , final ReactEditText editText ) {
1067- mEventDispatcher = getEventDispatcher (reactContext , editText );
1068- mEditText = editText ;
1069- mPreviousText = null ;
1070- mSurfaceId = UIManagerHelper .getSurfaceId (reactContext );
1071- }
1072-
1073- @ Override
1074- public void beforeTextChanged (CharSequence s , int start , int count , int after ) {
1075- // Incoming charSequence gets mutated before onTextChanged() is invoked
1076- mPreviousText = s .toString ();
1077- }
1078-
1079- @ Override
1080- public void onTextChanged (CharSequence s , int start , int before , int count ) {
1081- if (mEditText .mDisableTextDiffing ) {
1082- return ;
1083- }
1084-
1085- // Rearranging the text (i.e. changing between singleline and multiline attributes) can
1086- // also trigger onTextChanged, call the event in JS only when the text actually changed
1087- if (count == 0 && before == 0 ) {
1088- return ;
1089- }
1090-
1091- Assertions .assertNotNull (mPreviousText );
1092- String newText = s .toString ().substring (start , start + count );
1093- String oldText = mPreviousText .substring (start , start + before );
1094- // Don't send same text changes
1095- if (count == before && newText .equals (oldText )) {
1096- return ;
1097- }
1098-
1099- StateWrapper stateWrapper = mEditText .getStateWrapper ();
1100-
1101- if (stateWrapper != null ) {
1102- WritableMap newStateData = new WritableNativeMap ();
1103- newStateData .putInt ("mostRecentEventCount" , mEditText .incrementAndGetEventCounter ());
1104- newStateData .putInt ("opaqueCacheId" , mEditText .getId ());
1105- stateWrapper .updateState (newStateData );
1106- }
1107-
1108- // The event that contains the event counter and updates it must be sent first.
1109- mEventDispatcher .dispatchEvent (
1110- new ReactTextChangedEvent (
1111- mSurfaceId ,
1112- mEditText .getId (),
1113- s .toString (),
1114- mEditText .incrementAndGetEventCounter ()));
1115- }
1116-
1117- @ Override
1118- public void afterTextChanged (Editable s ) {}
1119- }
1120-
11211051 @ Override
11221052 protected void addEventEmitters (
11231053 final ThemedReactContext reactContext , final ReactEditText editText ) {
@@ -1188,130 +1118,6 @@ protected void addEventEmitters(
11881118 });
11891119 }
11901120
1191- private static class ReactContentSizeWatcher implements ContentSizeWatcher {
1192- private final ReactEditText mEditText ;
1193- private final EventDispatcher mEventDispatcher ;
1194- private final int mSurfaceId ;
1195- private int mPreviousContentWidth = 0 ;
1196- private int mPreviousContentHeight = 0 ;
1197-
1198- public ReactContentSizeWatcher (ReactEditText editText ) {
1199- mEditText = editText ;
1200- ReactContext reactContext = getReactContext (editText );
1201- mEventDispatcher = getEventDispatcher (reactContext , editText );
1202- mSurfaceId = UIManagerHelper .getSurfaceId (reactContext );
1203- }
1204-
1205- @ Override
1206- public void onLayout () {
1207- if (mEventDispatcher == null ) {
1208- return ;
1209- }
1210-
1211- int contentWidth = mEditText .getWidth ();
1212- int contentHeight = mEditText .getHeight ();
1213-
1214- // Use instead size of text content within EditText when available
1215- if (mEditText .getLayout () != null ) {
1216- contentWidth =
1217- mEditText .getCompoundPaddingLeft ()
1218- + mEditText .getLayout ().getWidth ()
1219- + mEditText .getCompoundPaddingRight ();
1220- contentHeight =
1221- mEditText .getCompoundPaddingTop ()
1222- + mEditText .getLayout ().getHeight ()
1223- + mEditText .getCompoundPaddingBottom ();
1224- }
1225-
1226- if (contentWidth != mPreviousContentWidth || contentHeight != mPreviousContentHeight ) {
1227- mPreviousContentHeight = contentHeight ;
1228- mPreviousContentWidth = contentWidth ;
1229-
1230- mEventDispatcher .dispatchEvent (
1231- new ReactContentSizeChangedEvent (
1232- mSurfaceId ,
1233- mEditText .getId (),
1234- PixelUtil .toDIPFromPixel (contentWidth ),
1235- PixelUtil .toDIPFromPixel (contentHeight )));
1236- }
1237- }
1238- }
1239-
1240- private static class ReactSelectionWatcher implements SelectionWatcher {
1241- private final ReactEditText mReactEditText ;
1242- private final EventDispatcher mEventDispatcher ;
1243- private final int mSurfaceId ;
1244- private int mPreviousSelectionStart ;
1245- private int mPreviousSelectionEnd ;
1246-
1247- public ReactSelectionWatcher (ReactEditText editText ) {
1248- mReactEditText = editText ;
1249- ReactContext reactContext = getReactContext (editText );
1250- mEventDispatcher = getEventDispatcher (reactContext , editText );
1251- mSurfaceId = UIManagerHelper .getSurfaceId (reactContext );
1252- }
1253-
1254- @ Override
1255- public void onSelectionChanged (int start , int end ) {
1256- // Android will call us back for both the SELECTION_START span and SELECTION_END span in text
1257- // To prevent double calling back into js we cache the result of the previous call and only
1258- // forward it on if we have new values
1259-
1260- // Apparently Android might call this with an end value that is less than the start value
1261- // Lets normalize them. See https://github.com/facebook/react-native/issues/18579
1262- int realStart = Math .min (start , end );
1263- int realEnd = Math .max (start , end );
1264-
1265- if (mPreviousSelectionStart != realStart || mPreviousSelectionEnd != realEnd ) {
1266- mEventDispatcher .dispatchEvent (
1267- new ReactTextInputSelectionEvent (
1268- mSurfaceId , mReactEditText .getId (), realStart , realEnd ));
1269-
1270- mPreviousSelectionStart = realStart ;
1271- mPreviousSelectionEnd = realEnd ;
1272- }
1273- }
1274- }
1275-
1276- private static class ReactScrollWatcher implements ScrollWatcher {
1277- private final ReactEditText mReactEditText ;
1278- private final EventDispatcher mEventDispatcher ;
1279- private final int mSurfaceId ;
1280- private int mPreviousHorizontal ;
1281- private int mPreviousVert ;
1282-
1283- public ReactScrollWatcher (ReactEditText editText ) {
1284- mReactEditText = editText ;
1285- ReactContext reactContext = getReactContext (editText );
1286- mEventDispatcher = getEventDispatcher (reactContext , editText );
1287- mSurfaceId = UIManagerHelper .getSurfaceId (reactContext );
1288- }
1289-
1290- @ Override
1291- public void onScrollChanged (int horiz , int vert , int oldHoriz , int oldVert ) {
1292- if (mPreviousHorizontal != horiz || mPreviousVert != vert ) {
1293- ScrollEvent event =
1294- ScrollEvent .obtain (
1295- mSurfaceId ,
1296- mReactEditText .getId (),
1297- ScrollEventType .SCROLL ,
1298- horiz ,
1299- vert ,
1300- 0f , // can't get x velocity
1301- 0f , // can't get y velocity
1302- 0 , // can't get content width
1303- 0 , // can't get content height
1304- mReactEditText .getWidth (),
1305- mReactEditText .getHeight ());
1306-
1307- mEventDispatcher .dispatchEvent (event );
1308-
1309- mPreviousHorizontal = horiz ;
1310- mPreviousVert = vert ;
1311- }
1312- }
1313- }
1314-
13151121 @ Override
13161122 public @ Nullable Map <String , Object > getExportedViewConstants () {
13171123 return MapBuilder .of (
0 commit comments