aboutsummaryrefslogtreecommitdiff
path: root/input/autofill
diff options
context:
space:
mode:
authorDouglas Sigelbaum <sigelbaum@google.com>2018-03-19 16:06:52 -0700
committerFelipe Leme <felipeal@google.com>2018-09-25 12:20:28 -0700
commit51ed7ec29ca8c34ddfe3da070ca699228515deae (patch)
treecb6a6221d0b71546014bb55c3a7cf3da94a6d4aa /input/autofill
parent91deb6d993b53450135965994ffb303cec3b18f7 (diff)
downloadandroid-51ed7ec29ca8c34ddfe3da070ca699228515deae.tar.gz
Autofill sample: Adds client activity for RecyclerView.
Uses a RecyclerView containing autofillable fields to exercise P DP2 API change (mutable AutofillIds). Bug: 74553154 Test: manual Change-Id: Ided48cbd3d22e99a598c95ce9dff73ea7986f23e
Diffstat (limited to 'input/autofill')
-rw-r--r--input/autofill/AutofillFramework/Application/src/main/AndroidManifest.xml2
-rw-r--r--input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/RecyclerViewActivity.java358
-rw-r--r--input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/widget/NavigationItem.java11
-rw-r--r--input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_format_list_bulleted_black_24dp.xml24
-rw-r--r--input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_common_cases.xml11
-rw-r--r--input/autofill/AutofillFramework/Application/src/main/res/layout/recycler_view_activity.xml66
-rw-r--r--input/autofill/AutofillFramework/Application/src/main/res/layout/user_data_field.xml58
-rw-r--r--input/autofill/AutofillFramework/Application/src/main/res/values/attrs.xml1
-rw-r--r--input/autofill/AutofillFramework/Application/src/main/res/values/strings.xml20
-rw-r--r--input/autofill/AutofillFramework/afservice/src/main/res/raw/default_field_types16
10 files changed, 564 insertions, 3 deletions
diff --git a/input/autofill/AutofillFramework/Application/src/main/AndroidManifest.xml b/input/autofill/AutofillFramework/Application/src/main/AndroidManifest.xml
index 4079e2e2..7c184686 100644
--- a/input/autofill/AutofillFramework/Application/src/main/AndroidManifest.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/AndroidManifest.xml
@@ -51,7 +51,7 @@
<activity android:name="com.example.android.autofill.app.commoncases.WebViewSignInActivity" />
<activity android:name="com.example.android.autofill.app.edgecases.MultipleStepsSignInActivity" />
<activity android:name="com.example.android.autofill.app.edgecases.MultipleStepsCreditCardActivity" />
-
+ <activity android:name="com.example.android.autofill.app.commoncases.RecyclerViewActivity" />
</application>
</manifest>
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/RecyclerViewActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/RecyclerViewActivity.java
new file mode 100644
index 00000000..c2ce43c9
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/commoncases/RecyclerViewActivity.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.autofill.app.commoncases;
+
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
+import android.support.annotation.StringRes;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.recyclerview.extensions.ListAdapter;
+import android.support.v7.util.DiffUtil;
+import android.support.v7.widget.DividerItemDecoration;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextWatcher;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillManager;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.example.android.autofill.app.R;
+import com.example.android.autofill.app.WelcomeActivity;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This is mostly a normal Activity containing a RecyclerView. The only difference is, the rows in
+ * the RecyclerView have autofillable fields. Therefore, when we bind data to a recycled view, we
+ * need to also set the {@link AutofillId} on the view.
+ */
+@RequiresApi(28)
+public class RecyclerViewActivity extends AppCompatActivity {
+ private AutofillManager mAfm;
+ private List<FieldMetadata> mFields;
+ private FieldAdapter mFieldAdapter;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.recycler_view_activity);
+ RecyclerView recyclerView = findViewById(R.id.recyclerView);
+ mAfm = getSystemService(AutofillManager.class);
+
+ // Init RecyclerView
+ LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
+ DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
+ recyclerView.getContext(), layoutManager.getOrientation());
+ recyclerView.addItemDecoration(dividerItemDecoration);
+ mFields = initList();
+ mFieldAdapter = new FieldAdapter(mFields);
+ recyclerView.setAdapter(mFieldAdapter);
+ recyclerView.setLayoutManager(layoutManager);
+
+ // Init submit and clear buttons.
+ findViewById(R.id.submitButton).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ submit();
+ }
+ });
+ findViewById(R.id.clearButton).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ AutofillManager afm = getSystemService(AutofillManager.class);
+ if (afm != null) {
+ afm.cancel();
+ }
+ resetFields();
+ }
+ });
+ }
+
+ private void resetFields() {
+ for (FieldMetadata fieldMetadata : mFields) {
+ fieldMetadata.setEnteredText("");
+ }
+ mFieldAdapter.notifyDataSetChanged();
+ }
+
+ private void submit() {
+ Intent intent = WelcomeActivity.getStartActivityIntent(RecyclerViewActivity.this);
+ startActivity(intent);
+ finish();
+ }
+
+ public List<FieldMetadata> initList() {
+ return Arrays.asList(
+ new FieldMetadata(
+ mAfm.getNextAutofillId(),
+ View.AUTOFILL_HINT_NAME,
+ R.string.recycler_view_label_name,
+ R.drawable.ic_person_black_24dp,
+ InputType.TYPE_CLASS_TEXT
+ ),
+ new FieldMetadata(
+ mAfm.getNextAutofillId(),
+ "bday-month",
+ R.string.recycler_view_label_birthday_month,
+ R.drawable.ic_person_black_24dp,
+ InputType.TYPE_CLASS_NUMBER
+ ),
+ new FieldMetadata(
+ mAfm.getNextAutofillId(),
+ View.AUTOFILL_HINT_EMAIL_ADDRESS,
+ R.string.recycler_view_label_email,
+ R.drawable.ic_person_black_24dp,
+ InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+ ),
+ new FieldMetadata(
+ mAfm.getNextAutofillId(),
+ View.AUTOFILL_HINT_PHONE,
+ R.string.recycler_view_label_phone,
+ R.drawable.ic_person_black_24dp,
+ InputType.TYPE_CLASS_PHONE
+ ),
+ new FieldMetadata(
+ mAfm.getNextAutofillId(),
+ "tel_extension",
+ R.string.recycler_view_label_tel_extension,
+ R.drawable.ic_person_black_24dp,
+ InputType.TYPE_CLASS_PHONE
+ ),
+ new FieldMetadata(
+ mAfm.getNextAutofillId(),
+ View.AUTOFILL_HINT_CREDIT_CARD_NUMBER,
+ R.string.recycler_view_label_cc_number,
+ R.drawable.ic_person_black_24dp,
+ InputType.TYPE_CLASS_NUMBER
+ ),
+ new FieldMetadata(
+ mAfm.getNextAutofillId(),
+ View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE,
+ R.string.recycler_view_label_cc_sc,
+ R.drawable.ic_person_black_24dp,
+ InputType.TYPE_CLASS_NUMBER
+ ),
+ new FieldMetadata(
+ mAfm.getNextAutofillId(),
+ View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH,
+ R.string.recycler_view_label_cc_exp_month,
+ R.drawable.ic_person_black_24dp,
+ InputType.TYPE_CLASS_NUMBER
+ ),
+ new FieldMetadata(
+ mAfm.getNextAutofillId(),
+ View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR,
+ R.string.recycler_view_label_cc_exp_year,
+ R.drawable.ic_person_black_24dp,
+ InputType.TYPE_CLASS_NUMBER
+ ),
+ new FieldMetadata(
+ mAfm.getNextAutofillId(),
+ "address-line1",
+ R.string.recycler_view_label_address_line_1,
+ R.drawable.ic_person_black_24dp,
+ InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS
+ ),
+ new FieldMetadata(
+ mAfm.getNextAutofillId(),
+ "address-line2",
+ R.string.recycler_view_label_address_line_2,
+ R.drawable.ic_person_black_24dp,
+ InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS
+ ),
+ new FieldMetadata(
+ mAfm.getNextAutofillId(),
+ "address-line3",
+ R.string.recycler_view_label_address_line_3,
+ R.drawable.ic_person_black_24dp,
+ InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS
+ ),
+ new FieldMetadata(
+ mAfm.getNextAutofillId(),
+ View.AUTOFILL_HINT_POSTAL_CODE,
+ R.string.recycler_view_label_postal_code,
+ R.drawable.ic_person_black_24dp,
+ InputType.TYPE_CLASS_NUMBER
+ ),
+ new FieldMetadata(
+ mAfm.getNextAutofillId(),
+ "bday-year",
+ R.string.recycler_view_label_birthday_year,
+ R.drawable.ic_person_black_24dp,
+ InputType.TYPE_CLASS_NUMBER
+ )
+ );
+ }
+
+ static class FieldAdapter extends ListAdapter<FieldMetadata, FieldViewHolder> {
+ private List<FieldMetadata> mFields;
+ public FieldAdapter(List<FieldMetadata> fields) {
+ super(new FieldDiff());
+ mFields = fields;
+ submitList(mFields);
+ }
+
+ @NonNull
+ @Override
+ public FieldViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return new FieldViewHolder(LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.user_data_field, parent, false),
+ new FieldWatcher(mFields));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull FieldViewHolder holder, int position) {
+ holder.bind(getItem(position));
+ }
+ }
+
+ static class FieldViewHolder extends RecyclerView.ViewHolder {
+ ImageView mIcon;
+ TextView mLabel;
+ EditText mField;
+ FieldWatcher mWatcher;
+
+ public FieldViewHolder(@NonNull View itemView, FieldWatcher textWatcher) {
+ super(itemView);
+ mIcon = itemView.findViewById(R.id.icon);
+ mLabel = itemView.findViewById(R.id.label);
+ mField = itemView.findViewById(R.id.field);
+ mWatcher = textWatcher;
+ mField.addTextChangedListener(mWatcher);
+ }
+
+ void bind(FieldMetadata fieldMetadata) {
+ mWatcher.updatePosition(getAdapterPosition());
+ Drawable drawable = mIcon.getResources().getDrawable(fieldMetadata.getIconRes());
+ mIcon.setImageDrawable(drawable);
+ mLabel.setText(fieldMetadata.getLabelRes());
+ mField.setAutofillHints(fieldMetadata.getAutofillHint());
+ mField.setInputType(fieldMetadata.getInputType());
+ mField.setText(fieldMetadata.getEnteredText());
+
+ // IMPORTANT: setAutofillId of recycled View.
+ mField.setAutofillId(fieldMetadata.getAutofillId());
+ }
+ }
+
+ /**
+ * TextWatcher implementation to ensure EditTexts get recycled properly.
+ */
+ static class FieldWatcher implements TextWatcher {
+ private int mPosition;
+ private List<FieldMetadata> mFields;
+
+ public FieldWatcher(List<FieldMetadata> fields) {
+ mFields = fields;
+ }
+
+ public void updatePosition(int position) {
+ this.mPosition = position;
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ // NO-OP
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ mFields.get(mPosition).setEnteredText(charSequence);
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ // NO-OP
+ }
+ }
+
+ /**
+ * Model class that holds all of the data needed for a row in the {@link RecyclerView}.
+ */
+ static class FieldMetadata {
+ AutofillId mAutofillId;
+ String mAutofillHint;
+ @StringRes int mLabelRes;
+ @DrawableRes int mIconRes;
+ int mInputType;
+ CharSequence mEnteredText = "";
+
+ FieldMetadata(AutofillId autofillId, String autofillHint, @StringRes int labelRes,
+ @DrawableRes int iconRes, int inputType) {
+ mAutofillId = autofillId;
+ mAutofillHint = autofillHint;
+ mLabelRes = labelRes;
+ mIconRes = iconRes;
+ mInputType = inputType;
+ }
+
+ public AutofillId getAutofillId() {
+ return mAutofillId;
+ }
+
+ public String getAutofillHint() {
+ return mAutofillHint;
+ }
+
+ public int getLabelRes() {
+ return mLabelRes;
+ }
+
+ public int getIconRes() {
+ return mIconRes;
+ }
+
+ public int getInputType() {
+ return mInputType;
+ }
+
+ public void setEnteredText(CharSequence enteredText) {
+ mEnteredText = enteredText;
+ }
+
+ public CharSequence getEnteredText() {
+ return mEnteredText;
+ }
+ }
+
+ static class FieldDiff extends DiffUtil.ItemCallback<FieldMetadata> {
+ @Override
+ public boolean areItemsTheSame(@NonNull FieldMetadata oldItem,
+ @NonNull FieldMetadata newItem) {
+ return oldItem == newItem;
+ }
+
+ @Override
+ public boolean areContentsTheSame(@NonNull FieldMetadata oldItem,
+ @NonNull FieldMetadata newItem) {
+ return oldItem.equals(newItem);
+ }
+ }
+}
diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/widget/NavigationItem.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/widget/NavigationItem.java
index 9fea6bf4..16472771 100644
--- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/widget/NavigationItem.java
+++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofill/app/view/widget/NavigationItem.java
@@ -20,10 +20,12 @@ import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
+import android.support.v4.os.BuildCompat;
import android.support.v7.widget.CardView;
import android.util.AttributeSet;
import android.util.Log;
@@ -54,6 +56,15 @@ public class NavigationItem extends FrameLayout {
super(context, attrs, defStyleAttr, defStyleRes);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NavigationItem,
defStyleAttr, defStyleRes);
+ int activityMinSdk = typedArray.getInteger(R.styleable.NavigationItem_minSdk, 26);
+
+ // TODO: Remove BuildCompat.isAtLeastP() check when API 28 is finalized.
+ int deviceMinSdk = BuildCompat.isAtLeastP() ? 28 : Build.VERSION.SDK_INT;
+ if (deviceMinSdk < activityMinSdk) {
+ // If device's SDK is lower than the minSdk specified by the NavigationItem, hide it.
+ setVisibility(View.GONE);
+ return;
+ }
String labelText = typedArray.getString(R.styleable.NavigationItem_labelText);
String infoText = typedArray.getString(R.styleable.NavigationItem_infoText);
Drawable logoDrawable = typedArray.getDrawable(R.styleable.NavigationItem_itemLogo);
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_format_list_bulleted_black_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_format_list_bulleted_black_24dp.xml
new file mode 100644
index 00000000..b53c0be0
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_format_list_bulleted_black_24dp.xml
@@ -0,0 +1,24 @@
+<!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M4,10.5c-0.83,0 -1.5,0.67 -1.5,1.5s0.67,1.5 1.5,1.5 1.5,-0.67 1.5,-1.5 -0.67,-1.5 -1.5,-1.5zM4,4.5c-0.83,0 -1.5,0.67 -1.5,1.5S3.17,7.5 4,7.5 5.5,6.83 5.5,6 4.83,4.5 4,4.5zM4,16.5c-0.83,0 -1.5,0.68 -1.5,1.5s0.68,1.5 1.5,1.5 1.5,-0.68 1.5,-1.5 -0.67,-1.5 -1.5,-1.5zM7,19h14v-2L7,17v2zM7,13h14v-2L7,11v2zM7,5v2h14L21,5L7,5z"/>
+</vector>
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_common_cases.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_common_cases.xml
index 2d8078eb..5b2223c3 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_common_cases.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/fragment_common_cases.xml
@@ -96,5 +96,16 @@
app:itemLogo="@drawable/ic_view_module_black_24dp"
app:labelText="@string/navigation_button_date_picker_credit_card_label"
app:destinationActivityName="com.example.android.autofill.app.commoncases.CreditCardDatePickerActivity" />
+
+ <com.example.android.autofill.app.view.widget.NavigationItem
+ android:id="@+id/recyclerViewButton"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:imageColor="@android:color/holo_orange_light"
+ app:infoText="@string/recycler_view_info"
+ app:itemLogo="@drawable/ic_format_list_bulleted_black_24dp"
+ app:labelText="@string/navigation_button_recycler_view_label"
+ app:destinationActivityName="com.example.android.autofill.app.commoncases.RecyclerViewActivity"
+ app:minSdk="28"/>
</LinearLayout>
</ScrollView> \ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/recycler_view_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/recycler_view_activity.xml
new file mode 100644
index 00000000..50090ef4
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/recycler_view_activity.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:weightSum="1">
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/recyclerView"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="0.8"
+ tools:listItem="@layout/user_data_field" />
+
+ <android.support.constraint.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.2">
+
+ <TextView
+ android:id="@+id/clearButton"
+ style="@style/Widget.AppCompat.Button.Borderless"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/spacing_normal"
+ android:layout_marginStart="@dimen/spacing_normal"
+ android:layout_marginTop="@dimen/spacing_normal"
+ android:text="@string/clear_label"
+ android:textColor="@android:color/holo_blue_dark"
+ app:layout_constraintEnd_toStartOf="@+id/submitButton"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintHorizontal_chainStyle="packed"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="parent" />
+
+ <TextView
+ android:id="@+id/submitButton"
+ style="@style/Widget.AppCompat.Button.Borderless"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/spacing_normal"
+ android:layout_marginStart="@dimen/spacing_normal"
+ android:text="@string/submit_label"
+ android:textColor="@android:color/holo_blue_dark"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintStart_toEndOf="@+id/clearButton"
+ app:layout_constraintTop_toTopOf="@+id/clearButton" />
+ </android.support.constraint.ConstraintLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/user_data_field.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/user_data_field.xml
new file mode 100644
index 00000000..26f0b2e7
--- /dev/null
+++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/user_data_field.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/activity_vertical_margin"
+ android:layout_marginBottom="@dimen/activity_vertical_margin"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/spacing_normal"
+ android:layout_marginStart="@dimen/spacing_normal"
+ android:layout_marginEnd="@dimen/spacing_normal"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/field"
+ app:layout_constraintBottom_toBottomOf="@+id/field"
+ tools:background="@drawable/ic_person_black_24dp" />
+
+ <TextView
+ android:id="@+id/label"
+ style="@style/TextAppearance.AppCompat.Body1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/spacing_normal"
+ android:layout_marginEnd="@dimen/spacing_normal"
+ app:layout_constraintBottom_toBottomOf="@+id/field"
+ app:layout_constraintTop_toTopOf="@+id/field"
+ app:layout_constraintStart_toEndOf="@+id/icon"
+ tools:text="@string/recycler_view_label_name" />
+
+ <EditText
+ android:id="@+id/field"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/spacing_normal"
+ android:layout_marginEnd="@dimen/spacing_normal"
+ android:ems="10"
+ app:layout_constraintStart_toEndOf="@+id/label"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:text="Doug" />
+</android.support.constraint.ConstraintLayout> \ No newline at end of file
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/values/attrs.xml b/input/autofill/AutofillFramework/Application/src/main/res/values/attrs.xml
index bfadd1a1..01328b83 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/values/attrs.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/values/attrs.xml
@@ -20,6 +20,7 @@
<attr name="destinationActivityName" format="string" />
<attr name="itemLogo" format="integer" />
<attr name="imageColor" format="reference" />
+ <attr name="minSdk" format="integer" />
</declare-styleable>
<declare-styleable name="InfoButton">
<attr name="dialogText" format="string" />
diff --git a/input/autofill/AutofillFramework/Application/src/main/res/values/strings.xml b/input/autofill/AutofillFramework/Application/src/main/res/values/strings.xml
index a8441ba4..7f2c6465 100644
--- a/input/autofill/AutofillFramework/Application/src/main/res/values/strings.xml
+++ b/input/autofill/AutofillFramework/Application/src/main/res/values/strings.xml
@@ -27,6 +27,7 @@
<string name="navigation_button_email_compose_label">Sample Email Compose Using EditTexts</string>
<string name="navigation_button_compound_view_credit_card_label">Sample Credit Card Check Out Using Compound Views</string>
<string name="navigation_button_date_picker_credit_card_label">Sample Credit Card Check Out Using Date Picker</string>
+ <string name="navigation_button_recycler_view_label">Sample Credit Card Form Using RecyclerView</string>
<string name="navigation_button_multiple_partitions_label">Sample Page with Multiple Data Partitions</string>
<string name="navigation_button_web_view_login_label">Sample Login Using a WebView</string>
<string name="navigation_button_anti_pattern_credit_card_label">Sample Credit Card Anti Pattern</string>
@@ -109,6 +110,11 @@
While the EditText is optimized out of the box for autofill, this example shows how to
use it to autofill a date field.
</string>
+ <string name="recycler_view_info">
+ This is a sample form that has a list of fields in a RecyclerView. It demos the new APIs in
+ API 28 that allow you to dynamically change the AutofillId associated with a View. This is
+ needed when Views are being recycled, as they are in a RecyclerView.
+ </string>
<string name="multiple_partitions">
This is a sample page that contains multiple partitions (login credentials, address,
credit card info) and can be used to make sure that only one partition can be autofilled
@@ -207,4 +213,18 @@
<item>27</item>
</string-array>
+ <string name="recycler_view_label_name">Name</string>
+ <string name="recycler_view_label_birthday_month">Birthday Month</string>
+ <string name="recycler_view_label_birthday_year">Birthday Year</string>
+ <string name="recycler_view_label_email">Email</string>
+ <string name="recycler_view_label_phone">Telephone</string>
+ <string name="recycler_view_label_tel_extension">Tel. Extension</string>
+ <string name="recycler_view_label_cc_number">CC Number</string>
+ <string name="recycler_view_label_cc_sc">CSC</string>
+ <string name="recycler_view_label_cc_exp_month">CC Exp Month</string>
+ <string name="recycler_view_label_cc_exp_year">CC Exp Year</string>
+ <string name="recycler_view_label_address_line_1">Address Line 1</string>
+ <string name="recycler_view_label_address_line_2">Address Line 2</string>
+ <string name="recycler_view_label_address_line_3">Address Line 3</string>
+ <string name="recycler_view_label_postal_code">Postal Code</string>
</resources>
diff --git a/input/autofill/AutofillFramework/afservice/src/main/res/raw/default_field_types b/input/autofill/AutofillFramework/afservice/src/main/res/raw/default_field_types
index 637edead..a0e6b267 100644
--- a/input/autofill/AutofillFramework/afservice/src/main/res/raw/default_field_types
+++ b/input/autofill/AutofillFramework/afservice/src/main/res/raw/default_field_types
@@ -388,8 +388,20 @@
3
],
"fakeData": {
- "dateTemplate": "curr_time",
- "strictExampleSet": []
+ "strictExampleSet": [
+ "2000",
+ "1995",
+ "1990",
+ "1985",
+ "1980",
+ "1975",
+ "1970",
+ "1965",
+ "1960",
+ "1955",
+ "1950",
+ "1945"
+ ]
},
"partition": 0,
"saveInfo": 0,