diff --git a/android/app/src/main/java/com/expensify/chat/MainApplication.java b/android/app/src/main/java/com/expensify/chat/MainApplication.java index b24e8eb49eb1..a4f2bc97416d 100644 --- a/android/app/src/main/java/com/expensify/chat/MainApplication.java +++ b/android/app/src/main/java/com/expensify/chat/MainApplication.java @@ -37,6 +37,7 @@ protected List getPackages() { // packages.add(new MyReactNativePackage()); packages.add(new BootSplashPackage()); packages.add(new ExpensifyAppPackage()); + packages.add(new RNTextInputResetPackage()); return packages; } diff --git a/android/app/src/main/java/com/expensify/chat/RNTextInputResetModule.java b/android/app/src/main/java/com/expensify/chat/RNTextInputResetModule.java new file mode 100644 index 000000000000..37ec8f5c58f2 --- /dev/null +++ b/android/app/src/main/java/com/expensify/chat/RNTextInputResetModule.java @@ -0,0 +1,46 @@ +package com.expensify.chat; + +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.Callback; +import com.facebook.react.uimanager.UIManagerModule; +import com.facebook.react.uimanager.UIBlock; +import com.facebook.react.uimanager.NativeViewHierarchyManager; +import android.content.Context; +import android.view.View; +import android.widget.TextView; +import android.view.inputmethod.InputMethodManager; +import android.util.Log; + +public class RNTextInputResetModule extends ReactContextBaseJavaModule { + + private final ReactApplicationContext reactContext; + + public RNTextInputResetModule(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + } + + @Override + public String getName() { + return "RNTextInputReset"; + } + + // Props to https://github.com/MattFoley for this temporary hack + // https://github.com/facebook/react-native/pull/12462#issuecomment-298812731 + @ReactMethod + public void resetKeyboardInput(final int reactTagToReset) { + UIManagerModule uiManager = getReactApplicationContext().getNativeModule(UIManagerModule.class); + uiManager.addUIBlock(new UIBlock() { + @Override + public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) { + InputMethodManager imm = (InputMethodManager) getReactApplicationContext().getBaseContext().getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + View viewToReset = nativeViewHierarchyManager.resolveView(reactTagToReset); + imm.restartInput(viewToReset); + } + } + }); + } +} diff --git a/android/app/src/main/java/com/expensify/chat/RNTextInputResetPackage.java b/android/app/src/main/java/com/expensify/chat/RNTextInputResetPackage.java new file mode 100644 index 000000000000..8e5d9994fd4b --- /dev/null +++ b/android/app/src/main/java/com/expensify/chat/RNTextInputResetPackage.java @@ -0,0 +1,28 @@ +package com.expensify.chat; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; +import com.facebook.react.bridge.JavaScriptModule; + +public class RNTextInputResetPackage implements ReactPackage { + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + return Arrays.asList(new RNTextInputResetModule(reactContext)); + } + + // Deprecated from RN 0.47 + public List> createJSModules() { + return Collections.emptyList(); + } + + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } +} diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 1309d518b539..e77507b8bdfa 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {View, TouchableOpacity, InteractionManager, LayoutAnimation} from 'react-native'; +import {View, TouchableOpacity, InteractionManager, LayoutAnimation, NativeModules, findNodeHandle} from 'react-native'; import _ from 'underscore'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; @@ -139,6 +139,7 @@ const defaultProps = { ...withCurrentUserPersonalDetailsDefaultProps, }; +const {RNTextInputReset} = NativeModules; /** * Return the max available index for arrow manager. * @param {Number} numRows @@ -591,6 +592,12 @@ class ReportActionCompose extends React.Component { const commentAfterColonWithEmojiNameRemoved = this.state.value.slice(this.state.selection.end).replace(CONST.REGEX.EMOJI_REPLACER, CONST.SPACE); this.updateComment(`${commentBeforeColon}${emojiCode} ${commentAfterColonWithEmojiNameRemoved}`, true); + // In some Android phones keyboard, the text to search for the emoji is not cleared + // will be added after the user starts typing again on the keyboard. This package is + // a workaround to reset the keyboard natively. + if (RNTextInputReset) { + RNTextInputReset.resetKeyboardInput(findNodeHandle(this.textInput)); + } this.setState((prevState) => ({ selection: { start: prevState.colonIndex + emojiCode.length + CONST.SPACE_LENGTH,