From f15145639dab1e8d7a1c79a127b7d45c91d025a8 Mon Sep 17 00:00:00 2001 From: Cassio Zen Date: Fri, 15 Feb 2019 09:10:15 -0800 Subject: [PATCH] Add autoComplete prop (#21575) Summary: TL;DR: Setting `autoComplete` will allow the system to suggest autofill options for the `` component. Android Oreo introduced the AutoFill Framework, for secure communication between an app and autofill services (e.g. Password managers). When using `` on Android Oreo+, the system already tries to autofill (based on heuristics), but there is no way to set configuring options or disable. The quick solution would be to just add the same Android attributes (`autofillHints` & `importantForAutofill`) in React Native TextInput, but that doesn't bond well with the cross-platform nature of the library. Introduces an `autoComplete` prop based on HTML's `autocomplete` attribute, mapping to Android `autofillHints` & `importantForAutofill` and serving as a proper placeholder for autofill/autocomplete in other platforms: Also gives you the ability to disable autofill by setting autocomplete="off". Pull Request resolved: https://github.com/facebook/react-native/pull/21575 Differential Revision: D14102949 Pulled By: hramos fbshipit-source-id: 7601aeaca0332a1f3ce8da8020dba037b700853a --- Libraries/Components/TextInput/TextInput.js | 54 +++++++++++++++++++ .../textinput/ReactTextInputManager.java | 35 ++++++++++++ 2 files changed, 89 insertions(+) diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 296b6ec72dc029..e9aa082f9cd580 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -223,6 +223,21 @@ type IOSProps = $ReadOnly<{| |}>; type AndroidProps = $ReadOnly<{| + autoCompleteType?: ?( + | 'cc-csc' + | 'cc-exp' + | 'cc-exp-month' + | 'cc-exp-year' + | 'cc-number' + | 'email' + | 'name' + | 'password' + | 'postal-code' + | 'street-address' + | 'tel' + | 'username' + | 'off' + ), returnKeyLabel?: ?string, numberOfLines?: ?number, disableFullscreenUI?: ?boolean, @@ -413,6 +428,45 @@ const TextInput = createReactClass({ 'words', 'characters', ]), + /** + * Determines which content to suggest on auto complete, e.g.`username`. + * To disable auto complete, use `off`. + * + * *Android Only* + * + * The following values work on Android only: + * + * - `username` + * - `password` + * - `email` + * - `name` + * - `tel` + * - `street-address` + * - `postal-code` + * - `cc-number` + * - `cc-csc` + * - `cc-exp` + * - `cc-exp-month` + * - `cc-exp-year` + * - `off` + * + * @platform android + */ + autoCompleteType: PropTypes.oneOf([ + 'cc-csc', + 'cc-exp', + 'cc-exp-month', + 'cc-exp-year', + 'cc-number', + 'email', + 'name', + 'password', + 'postal-code', + 'street-address', + 'tel', + 'username', + 'off', + ]), /** * If `false`, disables auto-correct. The default value is `true`. */ diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 3ad69adba042d3..74ac875be6b9d7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -529,6 +529,41 @@ public void setMaxLength(ReactEditText view, @Nullable Integer maxLength) { view.setFilters(newFilters); } + @ReactProp(name = "autoComplete") + public void setTextContentType(ReactEditText view, @Nullable String autocomplete) { + if (autocomplete == null) { + view.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO); + } else if ("username".equals(autocomplete)) { + view.setAutofillHints(View.AUTOFILL_HINT_USERNAME); + } else if ("password".equals(autocomplete)) { + view.setAutofillHints(View.AUTOFILL_HINT_PASSWORD); + } else if ("email".equals(autocomplete)) { + view.setAutofillHints(View.AUTOFILL_HINT_EMAIL_ADDRESS); + } else if ("name".equals(autocomplete)) { + view.setAutofillHints(View.AUTOFILL_HINT_NAME); + } else if ("tel".equals(autocomplete)) { + view.setAutofillHints(View.AUTOFILL_HINT_PHONE); + } else if ("street-address".equals(autocomplete)) { + view.setAutofillHints(View.AUTOFILL_HINT_POSTAL_ADDRESS); + } else if ("postal-code".equals(autocomplete)) { + view.setAutofillHints(View.AUTOFILL_HINT_POSTAL_CODE); + } else if ("cc-number".equals(autocomplete)) { + view.setAutofillHints(View.AUTOFILL_HINT_CREDIT_CARD_NUMBER); + } else if ("cc-csc".equals(autocomplete)) { + view.setAutofillHints(View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE); + } else if ("cc-exp".equals(autocomplete)) { + view.setAutofillHints(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE); + } else if ("cc-exp-month".equals(autocomplete)) { + view.setAutofillHints(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH); + } else if ("cc-exp-year".equals(autocomplete)) { + view.setAutofillHints(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR); + } else if ("off".equals(autocomplete)) { + view.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO); + } else { + throw new JSApplicationIllegalArgumentException("Invalid autocomplete option: " + autocomplete); + } + } + @ReactProp(name = "autoCorrect") public void setAutoCorrect(ReactEditText view, @Nullable Boolean autoCorrect) { // clear auto correct flags, set SUGGESTIONS or NO_SUGGESTIONS depending on value