Add features for components/android_autofill.

As we expand the functionality of android_autofill, we need features
to do experiments.

Bug: 1425869
Change-Id: I4a5ca4388f8e5cafcce90ce5a11ab0be65a69e70
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4353311
Reviewed-by: Dominic Battré <[email protected]>
Commit-Queue: Jan Keitel <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1119286}
diff --git a/components/android_autofill/PRESUBMIT.py b/components/android_autofill/PRESUBMIT.py
new file mode 100644
index 0000000..a4694057
--- /dev/null
+++ b/components/android_autofill/PRESUBMIT.py
@@ -0,0 +1,44 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Chromium presubmit script for src/components/android_autofill.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details on the presubmit API built into depot_tools.
+"""
+
+USE_PYTHON3 = True
+PRESUBMIT_VERSION = '2.0.0'
+
+def IsComponentsAndroidAutofillFile(f, name_suffix):
+  return (f.LocalPath().startswith('components/android_autofill/') and
+          f.LocalPath().endswith(name_suffix))
+
+def AnyAffectedFileMatches(input_api, matcher):
+  return any(matcher(f) for f in input_api.change.AffectedTestableFiles())
+
+def IsComponentsAndroidAutofillFileAffected(input_api, name_suffix):
+  return AnyAffectedFileMatches(
+      input_api, lambda f: IsComponentsAndroidAutofillFile(f, name_suffix))
+
+def CheckWebViewExposedExperiments(input_api, output_api):
+  """Checks that changes to android autofill features are exposed to webview."""
+
+  _PRODUCTION_SUPPORT_FILE = ('android_webview/java/src/org/chromium/' +
+      'android_webview/common/ProductionSupportedFlagList.java')
+
+  warnings = []
+  if (IsComponentsAndroidAutofillFileAffected(input_api, 'features.cc') and
+      not AnyAffectedFileMatches(
+          input_api, lambda f: f.LocalPath() == _PRODUCTION_SUPPORT_FILE)):
+    warnings += [
+        output_api.PresubmitPromptWarning(
+            (
+                'You may need to modify {} instructions if your feature affects'
+                ' WebView.'
+            ).format(_PRODUCTION_SUPPORT_FILE)
+        )
+    ]
+
+  return warnings
diff --git a/components/android_autofill/browser/BUILD.gn b/components/android_autofill/browser/BUILD.gn
index eb3ffdf..7c1a515 100644
--- a/components/android_autofill/browser/BUILD.gn
+++ b/components/android_autofill/browser/BUILD.gn
@@ -17,6 +17,7 @@
 android_library("java") {
   srcjar_deps = [ ":autofill_aidl" ]
   deps = [
+    ":features_java",
     "//base:base_java",
     "//base:jni_java",
     "//build/android:build_java",
@@ -48,6 +49,37 @@
   ]
 }
 
+android_library("features_java") {
+  sources = [
+    "java/src/org/chromium/components/autofill/AndroidAutofillFeatures.java",
+  ]
+  annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+  deps = [
+    ":features",
+    "//base:base_java",
+    "//base:jni_java",
+    "//build/android:build_java",
+  ]
+}
+
+static_library("features") {
+  sources = [
+    "android_autofill_features.cc",
+    "android_autofill_features.h",
+  ]
+
+  deps = [
+    ":jni_headers_features",
+    "//base",
+  ]
+}
+
+generate_jni("jni_headers_features") {
+  sources = [
+    "java/src/org/chromium/components/autofill/AndroidAutofillFeatures.java",
+  ]
+}
+
 static_library("android") {
   sources = [
     "autofill_provider_android.cc",
@@ -59,6 +91,7 @@
   ]
   public_deps = [ ":browser" ]
   deps = [
+    ":features",
     ":jni_headers",
     "//components/autofill/content/browser",
     "//content/public/browser",
diff --git a/components/android_autofill/browser/android_autofill_features.cc b/components/android_autofill/browser/android_autofill_features.cc
new file mode 100644
index 0000000..b3929e1
--- /dev/null
+++ b/components/android_autofill/browser/android_autofill_features.cc
@@ -0,0 +1,39 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/android_autofill/browser/android_autofill_features.h"
+
+#include <jni.h>
+
+#include "base/feature_list.h"
+#include "components/android_autofill/browser/jni_headers_features/AndroidAutofillFeatures_jni.h"
+
+namespace autofill::features {
+
+namespace {
+
+const base::Feature* kFeaturesExposedToJava[] = {
+    &kAndroidAutofillViewStructureWithFormHierarchyLayer,
+};
+
+}  // namespace
+
+// Adds an additional hierarchy layer for forms into the `ViewStructure` that
+// is passed to Android's `AutofillManager`.
+// If the feature is disabled, AutofillProvider.java returns a `ViewStructure`
+// of depth 1: All form field elements are represented as child nodes of the
+// filled `ViewStructure`.
+// If the feature is enabled, there is an additional hierarchy level:
+// * The child nodes of the filled `ViewStructure` correspond to forms.
+// * The child nodes of nodes representing forms correspond to form field
+//   elements of the respective form.
+BASE_FEATURE(kAndroidAutofillViewStructureWithFormHierarchyLayer,
+             "AndroidAutofillViewStructureWithFormHierarchyLayer",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+static jlong JNI_AndroidAutofillFeatures_GetFeature(JNIEnv* env, jint ordinal) {
+  return reinterpret_cast<jlong>(kFeaturesExposedToJava[ordinal]);
+}
+
+}  // namespace autofill::features
diff --git a/components/android_autofill/browser/android_autofill_features.h b/components/android_autofill/browser/android_autofill_features.h
new file mode 100644
index 0000000..8536480b
--- /dev/null
+++ b/components/android_autofill/browser/android_autofill_features.h
@@ -0,0 +1,16 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_ANDROID_AUTOFILL_BROWSER_ANDROID_AUTOFILL_FEATURES_H_
+#define COMPONENTS_ANDROID_AUTOFILL_BROWSER_ANDROID_AUTOFILL_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace autofill::features {
+
+BASE_DECLARE_FEATURE(kAndroidAutofillViewStructureWithFormHierarchyLayer);
+
+}  // namespace autofill::features
+
+#endif  // COMPONENTS_ANDROID_AUTOFILL_BROWSER_ANDROID_AUTOFILL_FEATURES_H_
diff --git a/components/android_autofill/browser/java/src/org/chromium/components/autofill/AndroidAutofillFeatures.java b/components/android_autofill/browser/java/src/org/chromium/components/autofill/AndroidAutofillFeatures.java
new file mode 100644
index 0000000..5f42fef
--- /dev/null
+++ b/components/android_autofill/browser/java/src/org/chromium/components/autofill/AndroidAutofillFeatures.java
@@ -0,0 +1,43 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.autofill;
+
+import org.chromium.base.Features;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
+
+/**
+ * Java accessor for base/feature_list.h state.
+ *
+ * This class provides methods to access values of feature flags registered in
+ * `kFeaturesExposedToJava` in components/android_autofill/browser/android_autofill_features.cc.
+ *
+ */
+@JNINamespace("autofill::features")
+public class AndroidAutofillFeatures extends Features {
+    public static final String ANDROID_AUTOFILL_VIEW_STRUCTURE_WITH_FORM_HIERARCHY_LAYER_NAME =
+            "AndroidAutofillViewStructureWithFormHierarchyLayer";
+
+    public static final AndroidAutofillFeatures
+            ANDROID_AUTOFILL_VIEW_STRUCTURE_WITH_FORM_HIERARCHY_LAYER = new AndroidAutofillFeatures(
+                    0, ANDROID_AUTOFILL_VIEW_STRUCTURE_WITH_FORM_HIERARCHY_LAYER_NAME);
+
+    private final int mOrdinal;
+
+    private AndroidAutofillFeatures(int ordinal, String name) {
+        super(name);
+        mOrdinal = ordinal;
+    }
+
+    @Override
+    protected long getFeaturePointer() {
+        return AndroidAutofillFeaturesJni.get().getFeature(mOrdinal);
+    }
+
+    @NativeMethods
+    interface Natives {
+        long getFeature(int ordinal);
+    }
+}