Enable-native-Android-autofill.patch 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. From: uazo <uazo@users.noreply.github.com>
  2. Date: Sun, 24 Oct 2021 16:54:04 +0000
  3. Subject: Enable native Android autofill
  4. There are 2 different types of autofill: one managed via GCM and the
  5. native Android one that uses the provider assigned by the user
  6. (which can be any user installed app like Bitwarden for example).
  7. In chromium GCM is active while in the WebView the latter.
  8. This patch uses the WebView code to activate native Android autofill.
  9. See also: https://github.com/bromite/bromite/issues/547
  10. ---
  11. chrome/android/BUILD.gn | 1 +
  12. .../settings/PasswordSettings.java | 58 ++++++++++++++++++-
  13. .../chromium/chrome/browser/tab/TabImpl.java | 43 ++++++++++++++
  14. .../browser/tab/TabViewAndroidDelegate.java | 14 +++++
  15. chrome/browser/BUILD.gn | 8 +++
  16. chrome/browser/android/tab_android.cc | 26 +++++++++
  17. chrome/browser/android/tab_android.h | 2 +
  18. .../strings/android_chrome_strings.grd | 3 +
  19. chrome/browser/ui/tab_helpers.cc | 6 +-
  20. .../autofill/core/common/autofill_prefs.cc | 5 ++
  21. .../autofill/core/common/autofill_prefs.h | 1 +
  22. .../embedder_support/view/ContentView.java | 48 +++++++++++++++
  23. .../chromium/ui/base/ViewAndroidDelegate.java | 8 +++
  24. 13 files changed, 221 insertions(+), 2 deletions(-)
  25. diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
  26. --- a/chrome/android/BUILD.gn
  27. +++ b/chrome/android/BUILD.gn
  28. @@ -415,6 +415,7 @@ android_library("chrome_java") {
  29. "//chrome/browser/xsurface:java",
  30. "//components/autofill/android:autofill_java",
  31. "//components/autofill_assistant/browser:proto_java",
  32. + "//components/android_autofill/browser:java",
  33. "//components/background_task_scheduler:background_task_scheduler_java",
  34. "//components/background_task_scheduler:background_task_scheduler_task_ids_java",
  35. "//components/bookmarks/common/android:bookmarks_java",
  36. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
  37. --- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
  38. +++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
  39. @@ -52,12 +52,18 @@ import org.chromium.ui.text.SpanApplier;
  40. import java.util.Locale;
  41. +import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
  42. +import org.chromium.chrome.browser.ui.messages.snackbar.INeedSnackbarManager;
  43. +import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
  44. +import org.chromium.chrome.browser.ApplicationLifetime;
  45. +
  46. /**
  47. * The "Passwords" screen in Settings, which allows the user to enable or disable password saving,
  48. * to view saved passwords (just the username and URL), and to delete saved passwords.
  49. */
  50. public class PasswordSettings extends PreferenceFragmentCompat
  51. - implements PasswordManagerHandler.PasswordListObserver, Preference.OnPreferenceClickListener {
  52. + implements PasswordManagerHandler.PasswordListObserver, Preference.OnPreferenceClickListener,
  53. + INeedSnackbarManager {
  54. // Keys for name/password dictionaries.
  55. public static final String PASSWORD_LIST_URL = "url";
  56. public static final String PASSWORD_LIST_NAME = "name";
  57. @@ -75,6 +81,10 @@ public class PasswordSettings extends PreferenceFragmentCompat
  58. public static final String PREF_TRUSTED_VAULT_OPT_IN = "trusted_vault_opt_in";
  59. public static final String PREF_KEY_MANAGE_ACCOUNT_LINK = "manage_account_link";
  60. + public static final String PREF_ANDROID_AUTOFILL_SWITCH = "android_autofill_switch";
  61. +
  62. + private SnackbarManager mSnackbarManager;
  63. + private Snackbar mSnackbar;
  64. // A PasswordEntryViewer receives a boolean value with this key. If set true, the the entry was
  65. // part of a search result.
  66. @@ -108,6 +118,7 @@ public class PasswordSettings extends PreferenceFragmentCompat
  67. private String mSearchQuery;
  68. private Preference mLinkPref;
  69. private ChromeSwitchPreference mSavePasswordsSwitch;
  70. + private ChromeSwitchPreference mEnableAndroidAutofillSwitch;
  71. private ChromeSwitchPreference mAutoSignInSwitch;
  72. private ChromeBasePreference mCheckPasswords;
  73. private ChromeBasePreference mTrustedVaultOptIn;
  74. @@ -272,6 +283,7 @@ public class PasswordSettings extends PreferenceFragmentCompat
  75. getPreferenceScreen().removeAll();
  76. if (mSearchQuery == null) {
  77. createSavePasswordsSwitch();
  78. + createEnableAndroidAutofillSwitch();
  79. createAutoSignInCheckbox();
  80. if (mPasswordCheck != null) {
  81. createCheckPasswords();
  82. @@ -511,6 +523,50 @@ public class PasswordSettings extends PreferenceFragmentCompat
  83. getPrefService().getBoolean(Pref.CREDENTIALS_ENABLE_SERVICE));
  84. }
  85. + private void createEnableAndroidAutofillSwitch() {
  86. + if (mSnackbar == null) {
  87. + mSnackbar = Snackbar.make(getActivity().getString(R.string.ui_relaunch_notice),
  88. + new SnackbarManager.SnackbarController() {
  89. + @Override
  90. + public void onDismissNoAction(Object actionData) { }
  91. +
  92. + @Override
  93. + public void onAction(Object actionData) {
  94. + ApplicationLifetime.terminate(true);
  95. + }
  96. + }, Snackbar.TYPE_NOTIFICATION, Snackbar.UMA_UNKNOWN)
  97. + .setSingleLine(false)
  98. + .setAction(getActivity().getString(R.string.relaunch),
  99. + /*actionData*/null)
  100. + .setDuration(/*durationMs*/70000);
  101. + }
  102. +
  103. + mEnableAndroidAutofillSwitch = new ChromeSwitchPreference(getStyledContext(), null);
  104. + mEnableAndroidAutofillSwitch.setKey(PREF_ANDROID_AUTOFILL_SWITCH);
  105. + mEnableAndroidAutofillSwitch.setTitle(R.string.enable_android_autofill);
  106. + mEnableAndroidAutofillSwitch.setOrder(ORDER_SWITCH);
  107. + mEnableAndroidAutofillSwitch.setSummaryOn(R.string.text_on);
  108. + mEnableAndroidAutofillSwitch.setSummaryOff(R.string.text_off);
  109. +
  110. + try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
  111. + getPreferenceScreen().addPreference(mEnableAndroidAutofillSwitch);
  112. + }
  113. +
  114. + mEnableAndroidAutofillSwitch.setChecked(
  115. + getPrefService().getBoolean(Pref.AUTOFILL_ANDROID_ENABLED));
  116. +
  117. + mEnableAndroidAutofillSwitch.setOnPreferenceChangeListener((preference, newValue) -> {
  118. + getPrefService().setBoolean(Pref.AUTOFILL_ANDROID_ENABLED, (boolean) newValue);
  119. + if (!mSnackbarManager.isShowing())
  120. + mSnackbarManager.showSnackbar(mSnackbar);
  121. + return true;
  122. + });
  123. + }
  124. +
  125. + public void setSnackbarManager(SnackbarManager manager) {
  126. + mSnackbarManager = manager;
  127. + }
  128. +
  129. private void createAutoSignInCheckbox() {
  130. mAutoSignInSwitch = new ChromeSwitchPreference(getStyledContext(), null);
  131. mAutoSignInSwitch.setKey(PREF_AUTOSIGNIN_SWITCH);
  132. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
  133. --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
  134. +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
  135. @@ -75,6 +75,18 @@ import org.chromium.url.GURL;
  136. import java.nio.ByteBuffer;
  137. +import android.os.Build;
  138. +import android.util.SparseArray;
  139. +import org.chromium.base.annotations.VerifiesOnO;
  140. +import org.chromium.ui.base.EventOffsetHandler;
  141. +import android.view.ViewStructure;
  142. +import android.view.autofill.AutofillValue;
  143. +import org.chromium.components.autofill.AutofillProvider;
  144. +import org.chromium.components.autofill.AutofillActionModeCallback;
  145. +import org.chromium.content_public.browser.SelectionPopupController;
  146. +import org.chromium.chrome.browser.preferences.Pref;
  147. +import org.chromium.components.user_prefs.UserPrefs;
  148. +
  149. /**
  150. * Implementation of the interface {@link Tab}. Contains and manages a {@link ContentView}.
  151. * This class is not intended to be extended.
  152. @@ -218,6 +230,8 @@ public class TabImpl implements Tab, TabObscuringHandler.Observer {
  153. /** Whether or not the user manually changed the user agent. */
  154. private boolean mUserForcedUserAgent;
  155. + AutofillProvider mAutofillProvider;
  156. +
  157. /**
  158. * Creates an instance of a {@link TabImpl}.
  159. *
  160. @@ -768,6 +782,11 @@ public class TabImpl implements Tab, TabObscuringHandler.Observer {
  161. for (TabObserver observer : mObservers) observer.onDestroyed(this);
  162. mObservers.clear();
  163. + if (mAutofillProvider != null) {
  164. + mAutofillProvider.destroy();
  165. + mAutofillProvider = null;
  166. + }
  167. +
  168. mUserDataHost.destroy();
  169. mTabViewManager.destroy();
  170. hideNativePage(false, null);
  171. @@ -1359,6 +1378,16 @@ public class TabImpl implements Tab, TabObscuringHandler.Observer {
  172. return tabsPtrArray;
  173. }
  174. + public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
  175. + if (mAutofillProvider != null)
  176. + mAutofillProvider.onProvideAutoFillVirtualStructure(structure, flags);
  177. + }
  178. +
  179. + public void autofill(final SparseArray<AutofillValue> values) {
  180. + if (mAutofillProvider != null)
  181. + mAutofillProvider.autofill(values);
  182. + }
  183. +
  184. /**
  185. * Initializes the {@link WebContents}. Completes the browser content components initialization
  186. * around a native WebContents pointer.
  187. @@ -1408,6 +1437,19 @@ public class TabImpl implements Tab, TabObscuringHandler.Observer {
  188. mDelegateFactory.createContextMenuPopulatorFactory(this), this));
  189. mWebContents.notifyRendererPreferenceUpdate();
  190. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
  191. + UserPrefs.get(Profile.getLastUsedRegularProfile())
  192. + .getBoolean(Pref.AUTOFILL_ANDROID_ENABLED) == true) {
  193. + SelectionPopupController selectionController =
  194. + SelectionPopupController.fromWebContents(mWebContents);
  195. +
  196. + mAutofillProvider = new AutofillProvider(getContext(), cv, webContents, "bromite");
  197. + TabImplJni.get().initializeAutofillIfNecessary(mNativeTabAndroid);
  198. + mAutofillProvider.setWebContents(webContents);
  199. + cv.setWebContents(webContents);
  200. + selectionController.setNonSelectionActionModeCallback(
  201. + new AutofillActionModeCallback(mThemedApplicationContext, mAutofillProvider));
  202. + }
  203. TabHelpers.initWebContentsHelpers(this);
  204. notifyContentChanged();
  205. } finally {
  206. @@ -1771,5 +1813,6 @@ public class TabImpl implements Tab, TabObscuringHandler.Observer {
  207. void setActiveNavigationEntryTitleForUrl(long nativeTabAndroid, String url, String title);
  208. void loadOriginalImage(long nativeTabAndroid);
  209. boolean handleNonNavigationAboutURL(GURL url);
  210. + void initializeAutofillIfNecessary(long nativeTabAndroid);
  211. }
  212. }
  213. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegate.java
  214. --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegate.java
  215. +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabViewAndroidDelegate.java
  216. @@ -14,6 +14,10 @@ import org.chromium.content_public.browser.RenderWidgetHostView;
  217. import org.chromium.ui.base.ViewAndroidDelegate;
  218. import org.chromium.ui.base.WindowAndroid;
  219. +import android.util.SparseArray;
  220. +import android.view.autofill.AutofillValue;
  221. +import android.view.ViewStructure;
  222. +
  223. /**
  224. * Implementation of the abstract class {@link ViewAndroidDelegate} for Chrome.
  225. */
  226. @@ -101,4 +105,14 @@ public class TabViewAndroidDelegate extends ViewAndroidDelegate {
  227. protected int getViewportInsetBottom() {
  228. return mApplicationViewportInsetBottomPx;
  229. }
  230. +
  231. + @Override
  232. + public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
  233. + mTab.onProvideAutofillVirtualStructure(structure, flags);
  234. + }
  235. +
  236. + @Override
  237. + public void autofill(final SparseArray<AutofillValue> values) {
  238. + mTab.autofill(values);
  239. + }
  240. }
  241. diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
  242. --- a/chrome/browser/BUILD.gn
  243. +++ b/chrome/browser/BUILD.gn
  244. @@ -2393,6 +2393,14 @@ static_library("browser") {
  245. "//ui/webui/resources/cr_components/most_visited:mojom",
  246. "//ui/webui/resources/js/browser_command:mojo_bindings",
  247. ]
  248. +
  249. + if (is_android) {
  250. + deps += [
  251. + "//components/android_autofill/browser",
  252. + "//components/android_autofill/browser:android"
  253. + ]
  254. + }
  255. +
  256. if (is_chromeos_ash) {
  257. testonly = enable_weston_test
  258. sources += [
  259. diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
  260. --- a/chrome/browser/android/tab_android.cc
  261. +++ b/chrome/browser/android/tab_android.cc
  262. @@ -65,6 +65,13 @@
  263. #include "url/android/gurl_android.h"
  264. #include "url/gurl.h"
  265. +#include "components/android_autofill/browser/android_autofill_manager.h"
  266. +#include "components/android_autofill/browser/autofill_provider.h"
  267. +#include "components/android_autofill/browser/autofill_provider_android.h"
  268. +#include "components/autofill/content/browser/content_autofill_driver_factory.h"
  269. +#include "chrome/browser/ui/autofill/chrome_autofill_client.h"
  270. +#include "chrome/browser/browser_process.h"
  271. +
  272. using base::android::AttachCurrentThread;
  273. using base::android::ConvertUTF8ToJavaString;
  274. using base::android::JavaParamRef;
  275. @@ -437,3 +444,22 @@ static void JNI_TabImpl_Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
  276. // This will automatically bind to the Java object and pass ownership there.
  277. new TabAndroid(env, obj);
  278. }
  279. +
  280. +void TabAndroid::InitializeAutofillIfNecessary(JNIEnv* env) {
  281. + if (!autofill::ContentAutofillDriverFactory::FromWebContents(
  282. + web_contents_.get())) {
  283. + content::WebContents* web_contents = web_contents_.get();
  284. + DCHECK(
  285. + !autofill::ContentAutofillDriverFactory::FromWebContents(web_contents));
  286. + DCHECK(autofill::AutofillProvider::FromWebContents(web_contents));
  287. +
  288. + autofill::ChromeAutofillClient::CreateForWebContents(web_contents);
  289. +
  290. + autofill::ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(
  291. + web_contents,
  292. + autofill::ChromeAutofillClient::FromWebContents(web_contents),
  293. + g_browser_process->GetApplicationLocale(),
  294. + autofill::BrowserAutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER,
  295. + base::BindRepeating(&autofill::AndroidAutofillManager::Create));
  296. + }
  297. +}
  298. diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
  299. --- a/chrome/browser/android/tab_android.h
  300. +++ b/chrome/browser/android/tab_android.h
  301. @@ -154,6 +154,8 @@ class TabAndroid : public base::SupportsUserData {
  302. void SetDevToolsAgentHost(scoped_refptr<content::DevToolsAgentHost> host);
  303. + void InitializeAutofillIfNecessary(JNIEnv* env);
  304. +
  305. private:
  306. JavaObjectWeakGlobalRef weak_java_tab_;
  307. diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
  308. --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
  309. +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
  310. @@ -582,6 +582,9 @@ CHAR_LIMIT guidelines:
  311. <message name="IDS_PASSWORD_SETTINGS_SAVE_PASSWORDS" desc="Title for the checkbox toggling whether passwords are saved or not. [CHAR_LIMIT=32]">
  312. Save passwords
  313. </message>
  314. + <message name="IDS_ENABLE_ANDROID_AUTOFILL" desc="Title for the checkbox toggling whether enable Android native autofill or not. [CHAR_LIMIT=32]">
  315. + Enable native Android autofill
  316. + </message>
  317. <message name="IDS_PASSWORDS_AUTO_SIGNIN_TITLE" desc="Title for checkbox to enable automatically signing the user in to websites">
  318. Auto Sign-in
  319. </message>
  320. diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
  321. --- a/chrome/browser/ui/tab_helpers.cc
  322. +++ b/chrome/browser/ui/tab_helpers.cc
  323. @@ -141,6 +141,9 @@
  324. #include "chrome/browser/ui/android/context_menu_helper.h"
  325. #include "chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_android.h"
  326. #include "chrome/browser/video_tutorials/video_tutorial_tab_helper.h"
  327. +#include "components/android_autofill/browser/android_autofill_manager.h"
  328. +#include "components/android_autofill/browser/autofill_provider.h"
  329. +#include "components/android_autofill/browser/autofill_provider_android.h"
  330. #else
  331. #include "chrome/browser/accuracy_tips/accuracy_service_factory.h"
  332. #include "chrome/browser/banners/app_banner_manager_desktop.h"
  333. @@ -265,7 +268,8 @@ void TabHelpers::AttachTabHelpers(WebContents* web_contents) {
  334. web_contents,
  335. autofill::ChromeAutofillClient::FromWebContents(web_contents),
  336. g_browser_process->GetApplicationLocale(),
  337. - autofill::BrowserAutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER);
  338. + autofill::BrowserAutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER,
  339. + base::BindRepeating(&autofill::AndroidAutofillManager::Create));
  340. chrome_browser_net::NetErrorTabHelper::CreateForWebContents(web_contents);
  341. ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
  342. web_contents,
  343. diff --git a/components/autofill/core/common/autofill_prefs.cc b/components/autofill/core/common/autofill_prefs.cc
  344. --- a/components/autofill/core/common/autofill_prefs.cc
  345. +++ b/components/autofill/core/common/autofill_prefs.cc
  346. @@ -128,6 +128,9 @@ const char kAutofillWalletImportStorageCheckboxState[] =
  347. const char kAutocompleteLastVersionRetentionPolicy[] =
  348. "autocomplete.retention_policy_last_version";
  349. +// Boolean that is true to enable native Android Autofill
  350. +const char kAutofillAndroidEnabled[] = "autofill.android_autofill_enabled";
  351. +
  352. void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
  353. // Synced prefs. Used for cross-device choices, e.g., credit card Autofill.
  354. registry->RegisterBooleanPref(
  355. @@ -160,6 +163,8 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
  356. registry->RegisterBooleanPref(
  357. prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, true);
  358. #endif
  359. + registry->RegisterBooleanPref(
  360. + prefs::kAutofillAndroidEnabled, true);
  361. registry->RegisterIntegerPref(
  362. prefs::kAutofillCreditCardSigninPromoImpressionCount, 0);
  363. registry->RegisterBooleanPref(prefs::kAutofillWalletImportEnabled, true);
  364. diff --git a/components/autofill/core/common/autofill_prefs.h b/components/autofill/core/common/autofill_prefs.h
  365. --- a/components/autofill/core/common/autofill_prefs.h
  366. +++ b/components/autofill/core/common/autofill_prefs.h
  367. @@ -47,6 +47,7 @@ extern const char kAutofillUploadEventsLastResetTimestamp[];
  368. extern const char kAutofillWalletImportEnabled[];
  369. extern const char kAutofillWalletImportStorageCheckboxState[];
  370. extern const char kAutocompleteLastVersionRetentionPolicy[];
  371. +extern const char kAutofillAndroidEnabled[];
  372. namespace sync_transport_opt_in {
  373. enum Flags {
  374. diff --git a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/view/ContentView.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/view/ContentView.java
  375. --- a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/view/ContentView.java
  376. +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/view/ContentView.java
  377. @@ -36,6 +36,12 @@ import org.chromium.content_public.browser.WebContentsAccessibility;
  378. import org.chromium.ui.base.EventForwarder;
  379. import org.chromium.ui.base.EventOffsetHandler;
  380. +import org.chromium.base.Log;
  381. +import org.chromium.base.annotations.VerifiesOnO;
  382. +import android.util.SparseArray;
  383. +import android.view.autofill.AutofillValue;
  384. +import org.chromium.ui.base.ViewAndroidDelegate;
  385. +
  386. /**
  387. * The containing view for {@link WebContents} that exists in the Android UI hierarchy and exposes
  388. * the various {@link View} functionality to it.
  389. @@ -82,6 +88,8 @@ public class ContentView extends FrameLayout
  390. */
  391. public static ContentView createContentView(Context context,
  392. @Nullable EventOffsetHandler eventOffsetHandler, @Nullable WebContents webContents) {
  393. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
  394. + return new ContentViewWithAutofill(context, eventOffsetHandler, webContents);
  395. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  396. return new ContentViewApi23(context, eventOffsetHandler, webContents);
  397. }
  398. @@ -549,4 +557,44 @@ public class ContentView extends FrameLayout
  399. if (wcax != null) wcax.onProvideVirtualStructure(structure, false);
  400. }
  401. }
  402. +
  403. + /**
  404. + * API level 26 implementation that includes autofill.
  405. + */
  406. + @VerifiesOnO
  407. + public static class ContentViewWithAutofill extends ContentViewApi23 {
  408. + private ViewAndroidDelegate viewAndroidDelegate;
  409. +
  410. + private ContentViewWithAutofill(Context context, EventOffsetHandler eventOffsetHandler, WebContents webContents) {
  411. + super(context, eventOffsetHandler, webContents);
  412. +
  413. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
  414. + // The Autofill system-level infrastructure has heuristics for which Views it considers
  415. + // important for autofill; only these Views will be queried for their autofill
  416. + // structure on notifications that a new (virtual) View was entered. By default,
  417. + // FrameLayout is not considered important for autofill. Thus, for ContentView to be
  418. + // queried for its autofill structure, we must explicitly inform the autofill system
  419. + // that this View is important for autofill.
  420. + setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_YES);
  421. + }
  422. + }
  423. +
  424. + @Override
  425. + public void setWebContents(WebContents webContents) {
  426. + viewAndroidDelegate = webContents.getViewAndroidDelegate();
  427. + super.setWebContents(webContents);
  428. + }
  429. +
  430. + @Override
  431. + public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
  432. + if (viewAndroidDelegate != null)
  433. + viewAndroidDelegate.onProvideAutofillVirtualStructure(structure, flags);
  434. + }
  435. +
  436. + @Override
  437. + public void autofill(final SparseArray<AutofillValue> values) {
  438. + if (viewAndroidDelegate != null)
  439. + viewAndroidDelegate.autofill(values);
  440. + }
  441. + }
  442. }
  443. diff --git a/ui/android/java/src/org/chromium/ui/base/ViewAndroidDelegate.java b/ui/android/java/src/org/chromium/ui/base/ViewAndroidDelegate.java
  444. --- a/ui/android/java/src/org/chromium/ui/base/ViewAndroidDelegate.java
  445. +++ b/ui/android/java/src/org/chromium/ui/base/ViewAndroidDelegate.java
  446. @@ -26,6 +26,10 @@ import org.chromium.base.annotations.JNINamespace;
  447. import org.chromium.base.compat.ApiHelperForN;
  448. import org.chromium.ui.mojom.CursorType;
  449. +import android.util.SparseArray;
  450. +import android.view.autofill.AutofillValue;
  451. +import android.view.ViewStructure;
  452. +
  453. /**
  454. * Class to acquire, position, and remove anchor views from the implementing View.
  455. */
  456. @@ -488,4 +492,8 @@ public class ViewAndroidDelegate {
  457. protected int[] getDisplayFeature() {
  458. return null;
  459. }
  460. +
  461. + public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {}
  462. +
  463. + public void autofill(final SparseArray<AutofillValue> values) {}
  464. }
  465. --
  466. 2.20.1