diff options
author | Douglas Sigelbaum <sigelbaum@google.com> | 2017-09-13 20:18:55 -0700 |
---|---|---|
committer | Douglas Sigelbaum <sigelbaum@google.com> | 2017-09-18 15:17:32 -0700 |
commit | 1c511cbb2f4ce6b2399dc3bec748d7da8f669079 (patch) | |
tree | 0ec6b54cdfc7adedade3abaf7627a3a1e973fad9 /input/autofill | |
parent | db30f62f9ba914445c95255dff5b0be4a7d02dce (diff) | |
download | android-1c511cbb2f4ce6b2399dc3bec748d7da8f669079.tar.gz |
Autofill sample: Scaffolding for setting to add mock data.
* This makes it easier to test how your app responds to autofill data.
* Creates a dataset containing data for every View and W3C autofill hint.
* Refactored since there are 60+ hints and references to them were
* getting repetitive. Now all hint metadata is centralized.
* TODO: generate random autofill data for all hints.
Bug: 38182790
Test: manual
Change-Id: Ic525395a6270ba68ca1702aa5c60226037d6c0fb
Diffstat (limited to 'input/autofill')
16 files changed, 1104 insertions, 266 deletions
diff --git a/input/autofill/AutofillFramework/Application/build.gradle b/input/autofill/AutofillFramework/Application/build.gradle index b20c02dd..1dc66ebb 100644 --- a/input/autofill/AutofillFramework/Application/build.gradle +++ b/input/autofill/AutofillFramework/Application/build.gradle @@ -8,6 +8,7 @@ dependencies { compile 'com.android.support:design:26.0.1' compile 'com.android.support.constraint:constraint-layout:1.0.2' compile group: 'com.google.code.gson', name: 'gson', version: '2.8.1' + compile group: 'com.google.guava', name: 'guava', version: '22.0-android' } // The sample build uses multiple directories to @@ -23,11 +24,14 @@ android { defaultConfig { minSdkVersion 26 targetSdkVersion 26 + jackOptions { + enabled true + } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } sourceSets { diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadata.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadata.java index a0de246a..392a9622 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadata.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillFieldMetadata.java @@ -16,8 +16,6 @@ package com.example.android.autofillframework.multidatasetservice; import android.app.assist.AssistStructure.ViewNode; -import android.service.autofill.SaveInfo; -import android.view.View; import android.view.autofill.AutofillId; /** @@ -47,7 +45,7 @@ public class AutofillFieldMetadata { public void setHints(String[] hints) { mAutofillHints = hints; - updateSaveTypeFromHints(); + mSaveType = AutofillHints.getSaveTypeForHints(hints); } public int getSaveType() { @@ -78,73 +76,4 @@ public class AutofillFieldMetadata { public boolean isFocused() { return mFocused; } - - private void updateSaveTypeFromHints() { - mSaveType = 0; - if (mAutofillHints == null) { - return; - } - for (String hint : mAutofillHints) { - switch (hint) { - case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE: - case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY: - case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH: - case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR: - case View.AUTOFILL_HINT_CREDIT_CARD_NUMBER: - case View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE: - case W3cHints.CC_NAME: - case W3cHints.CC_GIVEN_NAME: - case W3cHints.CC_ADDITIONAL_NAME: - case W3cHints.CC_FAMILY_NAME: - case W3cHints.CC_NUMBER: - case W3cHints.CC_EXPIRATION: - case W3cHints.CC_EXPIRATION_MONTH: - case W3cHints.CC_EXPIRATION_YEAR: - case W3cHints.CC_CSC: - case W3cHints.CC_TYPE: - case W3cHints.TRANSACTION_CURRENCY: - case W3cHints.TRANSACTION_AMOUNT: - mSaveType |= SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD; - break; - case View.AUTOFILL_HINT_EMAIL_ADDRESS: - case W3cHints.EMAIL: - mSaveType |= SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS; - break; - case View.AUTOFILL_HINT_PASSWORD: - case W3cHints.NEW_PASSWORD: - case W3cHints.CURRENT_PASSWORD: - mSaveType |= SaveInfo.SAVE_DATA_TYPE_PASSWORD; - mSaveType &= ~SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS; - mSaveType &= ~SaveInfo.SAVE_DATA_TYPE_USERNAME; - break; - case View.AUTOFILL_HINT_POSTAL_ADDRESS: - case View.AUTOFILL_HINT_POSTAL_CODE: - case W3cHints.STREET_ADDRESS: - case W3cHints.ADDRESS_LINE1: - case W3cHints.ADDRESS_LINE2: - case W3cHints.ADDRESS_LINE3: - case W3cHints.ADDRESS_LEVEL4: - case W3cHints.ADDRESS_LEVEL3: - case W3cHints.ADDRESS_LEVEL2: - case W3cHints.ADDRESS_LEVEL1: - case W3cHints.COUNTRY: - case W3cHints.COUNTRY_NAME: - case W3cHints.POSTAL_CODE: - mSaveType |= SaveInfo.SAVE_DATA_TYPE_ADDRESS; - break; - case View.AUTOFILL_HINT_NAME: - case View.AUTOFILL_HINT_PHONE: - case View.AUTOFILL_HINT_USERNAME: - case W3cHints.HONORIFIC_PREFIX: - case W3cHints.GIVEN_NAME: - case W3cHints.ADDITIONAL_NAME: - case W3cHints.FAMILY_NAME: - case W3cHints.HONORIFIC_SUFFIX: - mSaveType |= SaveInfo.SAVE_DATA_TYPE_USERNAME; - break; - default: - mSaveType |= SaveInfo.SAVE_DATA_TYPE_GENERIC; - } - } - } } diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHelper.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHelper.java index b6632a11..12eb4c91 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHelper.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHelper.java @@ -22,7 +22,6 @@ import android.service.autofill.FillResponse; import android.service.autofill.SaveInfo; import android.support.annotation.DrawableRes; import android.util.Log; -import android.view.View; import android.view.autofill.AutofillId; import android.widget.RemoteViews; @@ -44,7 +43,8 @@ public final class AutofillHelper { * client View. */ public static Dataset newDataset(Context context, - AutofillFieldMetadataCollection autofillFields, FilledAutofillFieldCollection filledAutofillFieldCollection, boolean datasetAuth) { + AutofillFieldMetadataCollection autofillFields, + FilledAutofillFieldCollection filledAutofillFieldCollection, boolean datasetAuth) { String datasetName = filledAutofillFieldCollection.getDatasetName(); if (datasetName != null) { Dataset.Builder datasetBuilder; @@ -52,14 +52,16 @@ public final class AutofillHelper { datasetBuilder = new Dataset.Builder (newRemoteViews(context.getPackageName(), datasetName, R.drawable.ic_lock_black_24dp)); - IntentSender sender = AuthActivity.getAuthIntentSenderForDataset(context, datasetName); + IntentSender sender = + AuthActivity.getAuthIntentSenderForDataset(context, datasetName); datasetBuilder.setAuthentication(sender); } else { datasetBuilder = new Dataset.Builder (newRemoteViews(context.getPackageName(), datasetName, R.drawable.ic_person_black_24dp)); } - boolean setValueAtLeastOnce = filledAutofillFieldCollection.applyToFields(autofillFields, datasetBuilder); + boolean setValueAtLeastOnce = + filledAutofillFieldCollection.applyToFields(autofillFields, datasetBuilder); if (setValueAtLeastOnce) { return datasetBuilder.build(); } @@ -69,7 +71,8 @@ public final class AutofillHelper { public static RemoteViews newRemoteViews(String packageName, String remoteViewsText, @DrawableRes int drawableId) { - RemoteViews presentation = new RemoteViews(packageName, R.layout.multidataset_service_list_item); + RemoteViews presentation = + new RemoteViews(packageName, R.layout.multidataset_service_list_item); presentation.setTextViewText(R.id.text, remoteViewsText); presentation.setImageViewResource(R.id.icon, drawableId); return presentation; @@ -86,9 +89,11 @@ public final class AutofillHelper { if (clientFormDataMap != null) { Set<String> datasetNames = clientFormDataMap.keySet(); for (String datasetName : datasetNames) { - FilledAutofillFieldCollection filledAutofillFieldCollection = clientFormDataMap.get(datasetName); + FilledAutofillFieldCollection filledAutofillFieldCollection = + clientFormDataMap.get(datasetName); if (filledAutofillFieldCollection != null) { - Dataset dataset = newDataset(context, autofillFields, filledAutofillFieldCollection, datasetAuth); + Dataset dataset = newDataset(context, autofillFields, + filledAutofillFieldCollection, datasetAuth); if (dataset != null) { responseBuilder.addDataset(dataset); } @@ -110,85 +115,17 @@ public final class AutofillHelper { String[] filteredHints = new String[hints.length]; int i = 0; for (String hint : hints) { - if (AutofillHelper.isValidHint(hint)) { + if (AutofillHints.isValidHint(hint)) { filteredHints[i++] = hint; } else { Log.d(TAG, "Invalid autofill hint: " + hint); } } + if (i == 0) { + return null; + } String[] finalFilteredHints = new String[i]; System.arraycopy(filteredHints, 0, finalFilteredHints, 0, i); return finalFilteredHints; } - - public static boolean isValidHint(String hint) { - switch (hint) { - case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE: - case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY: - case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH: - case View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR: - case View.AUTOFILL_HINT_CREDIT_CARD_NUMBER: - case View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE: - case View.AUTOFILL_HINT_EMAIL_ADDRESS: - case View.AUTOFILL_HINT_PHONE: - case View.AUTOFILL_HINT_NAME: - case View.AUTOFILL_HINT_PASSWORD: - case View.AUTOFILL_HINT_POSTAL_ADDRESS: - case View.AUTOFILL_HINT_POSTAL_CODE: - case View.AUTOFILL_HINT_USERNAME: - case W3cHints.HONORIFIC_PREFIX: - case W3cHints.GIVEN_NAME: - case W3cHints.ADDITIONAL_NAME: - case W3cHints.FAMILY_NAME: - case W3cHints.HONORIFIC_SUFFIX: - case W3cHints.NEW_PASSWORD: - case W3cHints.CURRENT_PASSWORD: - case W3cHints.ORGANIZATION_TITLE: - case W3cHints.ORGANIZATION: - case W3cHints.STREET_ADDRESS: - case W3cHints.ADDRESS_LINE1: - case W3cHints.ADDRESS_LINE2: - case W3cHints.ADDRESS_LINE3: - case W3cHints.ADDRESS_LEVEL4: - case W3cHints.ADDRESS_LEVEL3: - case W3cHints.ADDRESS_LEVEL2: - case W3cHints.ADDRESS_LEVEL1: - case W3cHints.COUNTRY: - case W3cHints.COUNTRY_NAME: - case W3cHints.POSTAL_CODE: - case W3cHints.CC_NAME: - case W3cHints.CC_GIVEN_NAME: - case W3cHints.CC_ADDITIONAL_NAME: - case W3cHints.CC_FAMILY_NAME: - case W3cHints.CC_NUMBER: - case W3cHints.CC_EXPIRATION: - case W3cHints.CC_EXPIRATION_MONTH: - case W3cHints.CC_EXPIRATION_YEAR: - case W3cHints.CC_CSC: - case W3cHints.CC_TYPE: - case W3cHints.TRANSACTION_CURRENCY: - case W3cHints.TRANSACTION_AMOUNT: - case W3cHints.LANGUAGE: - case W3cHints.BDAY: - case W3cHints.BDAY_DAY: - case W3cHints.BDAY_MONTH: - case W3cHints.BDAY_YEAR: - case W3cHints.SEX: - case W3cHints.URL: - case W3cHints.PHOTO: - case W3cHints.TEL: - case W3cHints.TEL_COUNTRY_CODE: - case W3cHints.TEL_NATIONAL: - case W3cHints.TEL_AREA_CODE: - case W3cHints.TEL_LOCAL: - case W3cHints.TEL_LOCAL_PREFIX: - case W3cHints.TEL_LOCAL_SUFFIX: - case W3cHints.TEL_EXTENSION: - case W3cHints.EMAIL: - case W3cHints.IMPP: - return true; - default: - return false; - } - } } diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHintProperties.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHintProperties.java new file mode 100644 index 00000000..5a793774 --- /dev/null +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHintProperties.java @@ -0,0 +1,86 @@ +/* + * 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.autofillframework.multidatasetservice; + +import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillField; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * Holds the properties associated with an autofill hint in this Autofill Service. + */ +public final class AutofillHintProperties { + + private String mAutofillHint; + private FakeFieldGenerator mFakeFieldGenerator; + private Set<Integer> mValidTypes; + private int mSaveType; + private int mPartition; + + public AutofillHintProperties(String autofillHint, int saveType, int partitionNumber, + FakeFieldGenerator fakeFieldGenerator, Integer... validTypes) { + mAutofillHint = autofillHint; + mSaveType = saveType; + mPartition = partitionNumber; + mFakeFieldGenerator = fakeFieldGenerator; + mValidTypes = new HashSet<>(Arrays.asList(validTypes)); + } + + /** + * Generates dummy autofill field data that is relevant to the autofill hint. + */ + public FilledAutofillField generateFakeField(int seed) { + return mFakeFieldGenerator.generate(seed); + } + + /** + * Returns autofill hint associated with these properties. If you save a field that uses a W3C + * hint, there is a chance this will return a different but analogous hint, when applicable. + * For example, W3C has hint 'email' and {@link android.view.View} has hint 'emailAddress', so + * the W3C hint should map to the hint defined in {@link android.view.View} ('emailAddress'). + */ + public String getAutofillHint() { + return mAutofillHint; + } + + /** + * Returns how this hint maps to a {@link android.service.autofill.SaveInfo} type. + */ + public int getSaveType() { + return mSaveType; + } + + /** + * Returns which data partition this autofill hint should be a part of. See partitions defined + * in {@link AutofillHints}. + */ + public int getPartition() { + return mPartition; + } + + + /** + * Sometimes, data for a hint should only be stored as a certain AutofillValue type. For + * example, it is recommended that data representing a Credit Card Expiration date, annotated + * with the hint {@link android.view.View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, should + * only be stored as {@link android.view.View.AUTOFILL_TYPE_DATE}. + */ + public boolean isValidType(int type) { + return mValidTypes.contains(type); + } +} diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHints.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHints.java new file mode 100644 index 00000000..6480f3e6 --- /dev/null +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/AutofillHints.java @@ -0,0 +1,736 @@ +/* + * 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.autofillframework.multidatasetservice; + +import android.service.autofill.SaveInfo; +import android.view.View; + +import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillField; +import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection; +import com.google.common.collect.ImmutableMap; + +import java.util.Calendar; + +public final class AutofillHints { + public static final int PARTITION_OTHER = 0; + public static final int PARTITION_ADDRESS = 1; + public static final int PARTITION_EMAIL = 2; + public static final int PARTITION_CREDIT_CARD = 3; + public static final int[] PARTITIONS = { + PARTITION_OTHER, PARTITION_ADDRESS, PARTITION_EMAIL, PARTITION_CREDIT_CARD + }; + /* TODO: finish building fake data for all hints. */ + private static final ImmutableMap<String, AutofillHintProperties> sValidHints = + new ImmutableMap.Builder<String, AutofillHintProperties>() + .put(View.AUTOFILL_HINT_EMAIL_ADDRESS, new AutofillHintProperties( + View.AUTOFILL_HINT_EMAIL_ADDRESS, SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS, + PARTITION_EMAIL, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(View.AUTOFILL_HINT_EMAIL_ADDRESS); + filledAutofillField.setTextValue("email" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(View.AUTOFILL_HINT_NAME, new AutofillHintProperties( + View.AUTOFILL_HINT_NAME, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(View.AUTOFILL_HINT_NAME); + filledAutofillField.setTextValue("name" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(View.AUTOFILL_HINT_USERNAME, new AutofillHintProperties( + View.AUTOFILL_HINT_USERNAME, SaveInfo.SAVE_DATA_TYPE_USERNAME, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(View.AUTOFILL_HINT_USERNAME); + filledAutofillField.setTextValue("login" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(View.AUTOFILL_HINT_PASSWORD, new AutofillHintProperties( + View.AUTOFILL_HINT_PASSWORD, SaveInfo.SAVE_DATA_TYPE_PASSWORD, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(View.AUTOFILL_HINT_PASSWORD); + filledAutofillField.setTextValue("login" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(View.AUTOFILL_HINT_PHONE, new AutofillHintProperties( + View.AUTOFILL_HINT_PHONE, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(View.AUTOFILL_HINT_PHONE); + filledAutofillField.setTextValue("" + seed + "2345678910"); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(View.AUTOFILL_HINT_POSTAL_ADDRESS, new AutofillHintProperties( + View.AUTOFILL_HINT_POSTAL_ADDRESS, SaveInfo.SAVE_DATA_TYPE_ADDRESS, + PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(View.AUTOFILL_HINT_POSTAL_ADDRESS); + filledAutofillField.setTextValue( + "" + seed + " Fake Ln, Fake, FA, FAA 10001"); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(View.AUTOFILL_HINT_POSTAL_CODE, new AutofillHintProperties( + View.AUTOFILL_HINT_POSTAL_CODE, SaveInfo.SAVE_DATA_TYPE_ADDRESS, + PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(View.AUTOFILL_HINT_POSTAL_CODE); + filledAutofillField.setTextValue("1000" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(View.AUTOFILL_HINT_CREDIT_CARD_NUMBER, new AutofillHintProperties( + View.AUTOFILL_HINT_CREDIT_CARD_NUMBER, + SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, + PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = new FilledAutofillField( + View.AUTOFILL_HINT_CREDIT_CARD_NUMBER); + filledAutofillField.setTextValue("" + seed + "234567"); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE, new AutofillHintProperties( + View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE, + SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, + PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = new FilledAutofillField( + View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE); + filledAutofillField.setTextValue("" + seed + seed + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE, + new AutofillHintProperties( + View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE, + SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = new FilledAutofillField( + View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE); + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + seed); + filledAutofillField.setDateValue(calendar.getTimeInMillis()); + return filledAutofillField; + }, View.AUTOFILL_TYPE_DATE)) + .put(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH, + new AutofillHintProperties( + View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH, + SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField( + View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH); + CharSequence[] months = monthRange(); + filledAutofillField.setListValue(months, + seed % months.length); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR, new AutofillHintProperties( + View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR, + SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = new FilledAutofillField( + View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR); + Calendar calendar = Calendar.getInstance(); + int expYear = calendar.get(Calendar.YEAR) + seed; + calendar.set(Calendar.YEAR, expYear); + filledAutofillField.setDateValue(calendar.getTimeInMillis()); + filledAutofillField.setTextValue("" + expYear); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST, + View.AUTOFILL_TYPE_DATE)) + .put(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY, new AutofillHintProperties( + View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY, + SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = new FilledAutofillField( + View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY); + CharSequence[] days = dayRange(); + filledAutofillField.setListValue(days, seed % days.length); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.HONORIFIC_PREFIX, new AutofillHintProperties( + W3cHints.HONORIFIC_PREFIX, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = new FilledAutofillField( + W3cHints.HONORIFIC_PREFIX); + CharSequence[] examplePrefixes = {"Miss", "Ms.", "Mr.", "Mx.", + "Sr.", "Dr.", "Lady", "Lord"}; + filledAutofillField.setListValue(examplePrefixes, + seed % examplePrefixes.length); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.GIVEN_NAME, new AutofillHintProperties(W3cHints.GIVEN_NAME, + SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.GIVEN_NAME); + filledAutofillField.setTextValue("name" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.ADDITIONAL_NAME, new AutofillHintProperties( + W3cHints.ADDITIONAL_NAME, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.ADDITIONAL_NAME); + filledAutofillField.setTextValue("addtlname" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.FAMILY_NAME, new AutofillHintProperties( + W3cHints.FAMILY_NAME, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.FAMILY_NAME); + filledAutofillField.setTextValue("famname" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.HONORIFIC_SUFFIX, new AutofillHintProperties( + W3cHints.HONORIFIC_SUFFIX, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.HONORIFIC_SUFFIX); + CharSequence[] exampleSuffixes = {"san", "kun", "chan", "sama"}; + filledAutofillField.setListValue(exampleSuffixes, + seed % exampleSuffixes.length); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.NEW_PASSWORD, new AutofillHintProperties( + W3cHints.NEW_PASSWORD, SaveInfo.SAVE_DATA_TYPE_PASSWORD, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.NEW_PASSWORD); + filledAutofillField.setTextValue("login" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.CURRENT_PASSWORD, new AutofillHintProperties( + View.AUTOFILL_HINT_PASSWORD, SaveInfo.SAVE_DATA_TYPE_PASSWORD, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(View.AUTOFILL_HINT_PASSWORD); + filledAutofillField.setTextValue("login" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.ORGANIZATION_TITLE, new AutofillHintProperties( + W3cHints.ORGANIZATION_TITLE, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.ORGANIZATION_TITLE); + filledAutofillField.setTextValue("org" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.ORGANIZATION, new AutofillHintProperties(W3cHints.ORGANIZATION, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.ORGANIZATION); + filledAutofillField.setTextValue("org" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.STREET_ADDRESS, new AutofillHintProperties( + W3cHints.STREET_ADDRESS, SaveInfo.SAVE_DATA_TYPE_ADDRESS, + PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.STREET_ADDRESS); + filledAutofillField.setTextValue( + "" + seed + " Fake Ln, Fake, FA, FAA 10001"); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.ADDRESS_LINE1, new AutofillHintProperties(W3cHints.ADDRESS_LINE1, + SaveInfo.SAVE_DATA_TYPE_ADDRESS, + PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.ADDRESS_LINE1); + filledAutofillField.setTextValue("" + seed + " Fake Ln"); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.ADDRESS_LINE2, new AutofillHintProperties(W3cHints.ADDRESS_LINE2, + SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.ADDRESS_LINE2); + filledAutofillField.setTextValue("Apt. " + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.ADDRESS_LINE3, new AutofillHintProperties(W3cHints.ADDRESS_LINE3, + SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.ADDRESS_LINE3); + filledAutofillField.setTextValue("FA" + seed + ", FA, FAA"); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.ADDRESS_LEVEL4, new AutofillHintProperties( + W3cHints.ADDRESS_LEVEL4, SaveInfo.SAVE_DATA_TYPE_ADDRESS, + PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.ADDRESS_LEVEL4); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.ADDRESS_LEVEL3, new AutofillHintProperties( + W3cHints.ADDRESS_LEVEL3, SaveInfo.SAVE_DATA_TYPE_ADDRESS, + PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.ADDRESS_LEVEL3); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.ADDRESS_LEVEL2, new AutofillHintProperties( + W3cHints.ADDRESS_LEVEL2, SaveInfo.SAVE_DATA_TYPE_ADDRESS, + PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.ADDRESS_LEVEL2); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.ADDRESS_LEVEL1, new AutofillHintProperties( + W3cHints.ADDRESS_LEVEL1, SaveInfo.SAVE_DATA_TYPE_ADDRESS, + PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.ADDRESS_LEVEL1); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.COUNTRY, new AutofillHintProperties(W3cHints.COUNTRY, + SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.COUNTRY); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.COUNTRY_NAME, new AutofillHintProperties(W3cHints.COUNTRY_NAME, + SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.COUNTRY_NAME); + CharSequence[] exampleCountries = {"USA", "Mexico", "Canada"}; + filledAutofillField.setListValue(exampleCountries, + seed % exampleCountries.length); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.POSTAL_CODE, new AutofillHintProperties( + View.AUTOFILL_HINT_POSTAL_CODE, SaveInfo.SAVE_DATA_TYPE_ADDRESS, + PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(View.AUTOFILL_HINT_POSTAL_CODE); + filledAutofillField.setTextValue("" + seed + seed + seed + seed + + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.CC_NAME, new AutofillHintProperties(W3cHints.CC_NAME, + SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, + PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.CC_NAME); + filledAutofillField.setTextValue("firstname" + seed + "lastname" + + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.CC_GIVEN_NAME, new AutofillHintProperties(W3cHints.CC_GIVEN_NAME, + SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.CC_GIVEN_NAME); + filledAutofillField.setTextValue("givenname" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.CC_ADDITIONAL_NAME, new AutofillHintProperties( + W3cHints.CC_ADDITIONAL_NAME, SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, + PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.CC_ADDITIONAL_NAME); + filledAutofillField.setTextValue("addtlname" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.CC_FAMILY_NAME, new AutofillHintProperties( + W3cHints.CC_FAMILY_NAME, SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, + PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.CC_FAMILY_NAME); + filledAutofillField.setTextValue("familyname" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.CC_NUMBER, new AutofillHintProperties( + View.AUTOFILL_HINT_CREDIT_CARD_NUMBER, + SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = new FilledAutofillField( + View.AUTOFILL_HINT_CREDIT_CARD_NUMBER); + filledAutofillField.setTextValue("" + seed + "234567"); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.CC_EXPIRATION, new AutofillHintProperties( + View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE, + SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = new FilledAutofillField( + View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE); + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + seed); + filledAutofillField.setDateValue(calendar.getTimeInMillis()); + return filledAutofillField; + }, View.AUTOFILL_TYPE_DATE)) + .put(W3cHints.CC_EXPIRATION_MONTH, new AutofillHintProperties( + View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH, + SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = new FilledAutofillField( + View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH); + CharSequence[] months = monthRange(); + filledAutofillField.setListValue(months, + seed % months.length); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.CC_EXPIRATION_YEAR, new AutofillHintProperties( + View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR, + SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = new FilledAutofillField( + View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR); + Calendar calendar = Calendar.getInstance(); + int expYear = calendar.get(Calendar.YEAR) + seed; + calendar.set(Calendar.YEAR, expYear); + filledAutofillField.setDateValue(calendar.getTimeInMillis()); + filledAutofillField.setTextValue("" + expYear); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.CC_CSC, new AutofillHintProperties( + View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE, + SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = new FilledAutofillField( + View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE); + filledAutofillField.setTextValue("" + seed + seed + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.CC_TYPE, new AutofillHintProperties(W3cHints.CC_TYPE, + SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.CC_TYPE); + filledAutofillField.setTextValue("type" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.TRANSACTION_CURRENCY, new AutofillHintProperties( + W3cHints.TRANSACTION_CURRENCY, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.TRANSACTION_CURRENCY); + CharSequence[] exampleCurrencies = {"USD", "CAD", "KYD", "CRC"}; + filledAutofillField.setListValue(exampleCurrencies, + seed % exampleCurrencies.length); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.TRANSACTION_AMOUNT, new AutofillHintProperties( + W3cHints.TRANSACTION_AMOUNT, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.TRANSACTION_AMOUNT); + filledAutofillField.setTextValue("" + seed * 100); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.LANGUAGE, new AutofillHintProperties(W3cHints.LANGUAGE, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.LANGUAGE); + CharSequence[] exampleLanguages = {"Bulgarian", "Croatian", "Czech", + "Danish", "Dutch", "English", "Estonian"}; + filledAutofillField.setListValue(exampleLanguages, + seed % exampleLanguages.length); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.BDAY, new AutofillHintProperties(W3cHints.BDAY, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.BDAY); + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) - seed * 10); + calendar.set(Calendar.MONTH, seed % 12); + calendar.set(Calendar.DATE, seed % 27); + filledAutofillField.setDateValue(calendar.getTimeInMillis()); + return filledAutofillField; + }, View.AUTOFILL_TYPE_DATE)) + .put(W3cHints.BDAY_DAY, new AutofillHintProperties(W3cHints.BDAY_DAY, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.BDAY_DAY); + filledAutofillField.setTextValue("" + seed % 27); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.BDAY_MONTH, new AutofillHintProperties(W3cHints.BDAY_MONTH, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.BDAY_MONTH); + filledAutofillField.setTextValue("" + seed % 12); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.BDAY_YEAR, new AutofillHintProperties(W3cHints.BDAY_YEAR, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.BDAY_YEAR); + int year = Calendar.getInstance().get(Calendar.YEAR) - seed * 10; + filledAutofillField.setTextValue("" + year); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.SEX, new AutofillHintProperties(W3cHints.SEX, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.SEX); + filledAutofillField.setTextValue("Other"); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.URL, new AutofillHintProperties(W3cHints.URL, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.URL); + filledAutofillField.setTextValue("http://google.com"); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.PHOTO, new AutofillHintProperties(W3cHints.PHOTO, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.PHOTO); + filledAutofillField.setTextValue("photo" + seed + ".jpg"); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.PREFIX_SECTION, new AutofillHintProperties( + W3cHints.PREFIX_SECTION, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.PREFIX_SECTION); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.SHIPPING, new AutofillHintProperties(W3cHints.SHIPPING, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.SHIPPING); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.BILLING, new AutofillHintProperties(W3cHints.BILLING, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_ADDRESS, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.BILLING); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.PREFIX_HOME, new AutofillHintProperties(W3cHints.PREFIX_HOME, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.PREFIX_HOME); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.PREFIX_WORK, new AutofillHintProperties(W3cHints.PREFIX_WORK, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.PREFIX_WORK); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.PREFIX_FAX, new AutofillHintProperties(W3cHints.PREFIX_FAX, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.PREFIX_FAX); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.PREFIX_PAGER, new AutofillHintProperties(W3cHints.PREFIX_PAGER, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.PREFIX_PAGER); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.TEL, new AutofillHintProperties(W3cHints.TEL, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.TEL); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.TEL_COUNTRY_CODE, new AutofillHintProperties( + W3cHints.TEL_COUNTRY_CODE, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.TEL_COUNTRY_CODE); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.TEL_NATIONAL, new AutofillHintProperties(W3cHints.TEL_NATIONAL, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.TEL_NATIONAL); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.TEL_AREA_CODE, new AutofillHintProperties( + W3cHints.TEL_AREA_CODE, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.TEL_AREA_CODE); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.TEL_LOCAL, new AutofillHintProperties( + W3cHints.TEL_LOCAL, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.TEL_LOCAL); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.TEL_LOCAL_PREFIX, new AutofillHintProperties( + W3cHints.TEL_LOCAL_PREFIX, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.TEL_LOCAL_PREFIX); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.TEL_LOCAL_SUFFIX, new AutofillHintProperties( + W3cHints.TEL_LOCAL_SUFFIX, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.TEL_LOCAL_SUFFIX); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.TEL_EXTENSION, new AutofillHintProperties(W3cHints.TEL_EXTENSION, + SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.TEL_EXTENSION); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .put(W3cHints.EMAIL, new AutofillHintProperties( + View.AUTOFILL_HINT_EMAIL_ADDRESS, SaveInfo.SAVE_DATA_TYPE_GENERIC, + PARTITION_EMAIL, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(View.AUTOFILL_HINT_EMAIL_ADDRESS); + filledAutofillField.setTextValue("email" + seed); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT)) + .put(W3cHints.IMPP, new AutofillHintProperties(W3cHints.IMPP, + SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS, PARTITION_EMAIL, + (seed) -> { + FilledAutofillField filledAutofillField = + new FilledAutofillField(W3cHints.IMPP); + return filledAutofillField; + }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) + .build(); + + private AutofillHints() { + } + + public static boolean isValidTypeForHints(String[] hints, int type) { + if (hints != null) { + for (String hint : hints) { + if (hint != null && sValidHints.containsKey(hint)) { + boolean valid = sValidHints.get(hint).isValidType(type); + if (valid) { + return true; + } + } + } + } + return false; + } + + public static boolean isValidHint(String hint) { + return sValidHints.containsKey(hint); + } + + public static int getSaveTypeForHints(String[] hints) { + int saveType = 0; + if (hints != null) { + for (String hint : hints) { + if (hint != null && sValidHints.containsKey(hint)) { + saveType |= sValidHints.get(hint).getSaveType(); + } + } + } + return saveType; + } + + public static FilledAutofillField getFakeField(String hint, int seed) { + return sValidHints.get(hint).generateFakeField(seed); + } + + public static FilledAutofillFieldCollection getFakeFieldCollection(int partition, int seed) { + FilledAutofillFieldCollection filledAutofillFieldCollection = + new FilledAutofillFieldCollection(); + for (String hint : sValidHints.keySet()) { + if (hint != null && sValidHints.get(hint).getPartition() == partition) { + FilledAutofillField fakeField = getFakeField(hint, seed); + filledAutofillFieldCollection.add(fakeField); + } + } + return filledAutofillFieldCollection; + } + + public static String getStoredHintName(String hint) { + return sValidHints.get(hint).getAutofillHint(); + } + + private static CharSequence[] dayRange() { + CharSequence[] days = new CharSequence[27]; + for (int i = 0; i < days.length; i++) { + days[i] = Integer.toString(i); + } + return days; + } + + private static CharSequence[] monthRange() { + CharSequence[] months = new CharSequence[12]; + for (int i = 0; i < months.length; i++) { + months[i] = Integer.toString(i); + } + return months; + } +} diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/FakeFieldGenerator.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/FakeFieldGenerator.java new file mode 100644 index 00000000..383de216 --- /dev/null +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/FakeFieldGenerator.java @@ -0,0 +1,22 @@ +/* + * 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.autofillframework.multidatasetservice; + +import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillField; + +interface FakeFieldGenerator { + FilledAutofillField generate(int seed); +} diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/StructureParser.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/StructureParser.java index cd2ec1d4..00f17e33 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/StructureParser.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/StructureParser.java @@ -19,6 +19,7 @@ import android.app.assist.AssistStructure; import android.app.assist.AssistStructure.ViewNode; import android.app.assist.AssistStructure.WindowNode; import android.util.Log; +import android.view.autofill.AutofillValue; import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillField; import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection; @@ -67,7 +68,20 @@ final class StructureParser { if (forFill) { mAutofillFields.add(new AutofillFieldMetadata(viewNode)); } else { - mFilledAutofillFieldCollection.add(new FilledAutofillField(viewNode)); + FilledAutofillField filledAutofillField = + new FilledAutofillField(viewNode.getAutofillHints()); + AutofillValue autofillValue = viewNode.getAutofillValue(); + if (autofillValue.isText()) { + // Using toString of AutofillValue.getTextValue in order to save it to + // SharedPreferences. + filledAutofillField.setTextValue(autofillValue.getTextValue().toString()); + } else if (autofillValue.isDate()) { + filledAutofillField.setDateValue(autofillValue.getDateValue()); + } else if (autofillValue.isList()) { + filledAutofillField.setListValue(viewNode.getAutofillOptions(), + autofillValue.getListValue()); + } + mFilledAutofillFieldCollection.add(filledAutofillField); } } int childrenSize = viewNode.getChildCount(); diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/W3cHints.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/W3cHints.java index 0065ff74..14085544 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/W3cHints.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/W3cHints.java @@ -17,16 +17,14 @@ package com.example.android.autofillframework.multidatasetservice; public final class W3cHints { - private W3cHints() {} - // Supported W3C autofill tokens (https://html.spec.whatwg.org/multipage/forms.html#autofill) public static final String HONORIFIC_PREFIX = "honorific-prefix"; - public static final String NAME = "name"; // same as View.AUTOFILL_HINT_NAME + public static final String NAME = "name"; public static final String GIVEN_NAME = "given-name"; public static final String ADDITIONAL_NAME = "additional-name"; public static final String FAMILY_NAME = "family-name"; public static final String HONORIFIC_SUFFIX = "honorific-suffix"; - public static final String USERNAME = "username"; // same as View.AUTOFILL_HINT_USERNAME + public static final String USERNAME = "username"; public static final String NEW_PASSWORD = "new-password"; public static final String CURRENT_PASSWORD = "current-password"; public static final String ORGANIZATION_TITLE = "organization-title"; @@ -62,12 +60,10 @@ public final class W3cHints { public static final String SEX = "sex"; public static final String URL = "url"; public static final String PHOTO = "photo"; - // Optional W3C prefixes public static final String PREFIX_SECTION = "section-"; public static final String SHIPPING = "shipping"; public static final String BILLING = "billing"; - // W3C prefixes below... public static final String PREFIX_HOME = "home"; public static final String PREFIX_WORK = "work"; @@ -84,4 +80,7 @@ public final class W3cHints { public static final String TEL_EXTENSION = "tel_extension"; public static final String EMAIL = "email"; public static final String IMPP = "impp"; + + private W3cHints() { + } }
\ No newline at end of file diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/AutofillDataSource.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/AutofillDataSource.java index 99d1c261..b92a7365 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/AutofillDataSource.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/AutofillDataSource.java @@ -32,7 +32,7 @@ public interface AutofillDataSource { List<String> focusedAutofillHints, List<String> allAutofillHints); /** - * Saves LoginCredential under this datasetName. + * Stores a collection of Autofill fields. */ void saveFilledAutofillFieldCollection(Context context, FilledAutofillFieldCollection filledAutofillFieldCollection); diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillField.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillField.java index 9ae92a3d..117f3e48 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillField.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillField.java @@ -15,12 +15,18 @@ */ package com.example.android.autofillframework.multidatasetservice.model; -import android.app.assist.AssistStructure; +import android.util.Log; +import android.view.View; import android.view.autofill.AutofillValue; import com.example.android.autofillframework.multidatasetservice.AutofillHelper; +import com.example.android.autofillframework.multidatasetservice.AutofillHints; import com.google.gson.annotations.Expose; +import java.util.Arrays; + +import static com.example.android.autofillframework.CommonUtil.TAG; + /** * JSON serializable data class containing the same data as an {@link AutofillValue}. */ @@ -37,23 +43,19 @@ public class FilledAutofillField { */ private String[] mAutofillHints = null; - public FilledAutofillField(AssistStructure.ViewNode viewNode) { - mAutofillHints = AutofillHelper.filterForSupportedHints(viewNode.getAutofillHints()); - AutofillValue autofillValue = viewNode.getAutofillValue(); - if (autofillValue != null) { - if (autofillValue.isList()) { - CharSequence[] autofillOptions = viewNode.getAutofillOptions(); - int index = autofillValue.getListValue(); - if (autofillOptions != null && autofillOptions.length > 0) { - mTextValue = autofillOptions[index].toString(); - } - } else if (autofillValue.isDate()) { - mDateValue = autofillValue.getDateValue(); - } else if (autofillValue.isText()) { - // Using toString of AutofillValue.getTextValue in order to save it to - // SharedPreferences. - mTextValue = autofillValue.getTextValue().toString(); + public FilledAutofillField(String... hints) { + mAutofillHints = AutofillHelper.filterForSupportedHints(hints); + } + + public void setListValue(CharSequence[] autofillOptions, int listValue) { + /* Only set list value when a hint is allowed to store list values. */ + if (AutofillHints.isValidTypeForHints(mAutofillHints, View.AUTOFILL_TYPE_LIST)) { + if (autofillOptions != null && autofillOptions.length > 0) { + mTextValue = autofillOptions[listValue].toString(); } + } else { + Log.w(TAG, "List is invalid autofill type for hint(s) - " + + Arrays.toString(mAutofillHints)); } } @@ -65,14 +67,44 @@ public class FilledAutofillField { return mTextValue; } + public void setTextValue(CharSequence textValue) { + /* Only set text value when a hint is allowed to store text values. */ + if (AutofillHints.isValidTypeForHints(mAutofillHints, View.AUTOFILL_TYPE_TEXT)) { + mTextValue = textValue.toString(); + } else { + Log.w(TAG, "Text is invalid autofill type for hint(s) - " + + Arrays.toString(mAutofillHints)); + } + } + public Long getDateValue() { return mDateValue; } + public void setDateValue(Long dateValue) { + /* Only set date value when a hint is allowed to store date values. */ + if (AutofillHints.isValidTypeForHints(mAutofillHints, View.AUTOFILL_TYPE_DATE)) { + mDateValue = dateValue; + } else { + Log.w(TAG, "Date is invalid autofill type for hint(s) - " + + Arrays.toString(mAutofillHints)); + } + } + public Boolean getToggleValue() { return mToggleValue; } + public void setToggleValue(Boolean toggleValue) { + /* Only set toggle value when a hint is allowed to store toggle values. */ + if (AutofillHints.isValidTypeForHints(mAutofillHints, View.AUTOFILL_TYPE_TOGGLE)) { + mToggleValue = toggleValue; + } else { + Log.w(TAG, "Toggle is invalid autofill type for hint(s) - " + + Arrays.toString(mAutofillHints)); + } + } + public boolean isNull() { return mTextValue == null && mDateValue == null && mToggleValue == null; } @@ -88,7 +120,8 @@ public class FilledAutofillField { return false; if (mDateValue != null ? !mDateValue.equals(that.mDateValue) : that.mDateValue != null) return false; - return mToggleValue != null ? mToggleValue.equals(that.mToggleValue) : that.mToggleValue == null; + return mToggleValue != null ? mToggleValue.equals(that.mToggleValue) : + that.mToggleValue == null; } @Override diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillFieldCollection.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillFieldCollection.java index cc37c14c..527c30e5 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillFieldCollection.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/model/FilledAutofillFieldCollection.java @@ -24,9 +24,9 @@ import android.view.autofill.AutofillValue; import com.example.android.autofillframework.multidatasetservice.AutofillFieldMetadata; import com.example.android.autofillframework.multidatasetservice.AutofillFieldMetadataCollection; -import com.google.gson.annotations.Expose; -import com.example.android.autofillframework.multidatasetservice.AutofillHelper; +import com.example.android.autofillframework.multidatasetservice.AutofillHints; import com.example.android.autofillframework.multidatasetservice.W3cHints; +import com.google.gson.annotations.Expose; import java.util.HashMap; import java.util.List; @@ -142,52 +142,19 @@ public final class FilledAutofillFieldCollection { // Then check if the "actual" hint is supported. - if (AutofillHelper.isValidHint(hint)) { - mHintMap.put(transformHint(hint), filledAutofillField); + if (AutofillHints.isValidHint(hint)) { + mHintMap.put(AutofillHints.getStoredHintName(hint), filledAutofillField); } else { Log.e(TAG, "Invalid hint: " + autofillHints[i]); } } } - public String transformHint(String hint) { - switch (hint) { - case W3cHints.NEW_PASSWORD: - case W3cHints.CURRENT_PASSWORD: - return View.AUTOFILL_HINT_PASSWORD; - case W3cHints.STREET_ADDRESS: - return View.AUTOFILL_HINT_POSTAL_ADDRESS; - case W3cHints.POSTAL_CODE: - return View.AUTOFILL_HINT_POSTAL_CODE; - case W3cHints.CC_NAME: - case W3cHints.GIVEN_NAME: - case W3cHints.CC_GIVEN_NAME: - return View.AUTOFILL_HINT_NAME; - case W3cHints.CC_ADDITIONAL_NAME: - case W3cHints.CC_NUMBER: - return View.AUTOFILL_HINT_CREDIT_CARD_NUMBER; - case W3cHints.CC_EXPIRATION: - return View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE; - case W3cHints.CC_EXPIRATION_MONTH: - return View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH; - case W3cHints.CC_EXPIRATION_YEAR: - return View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR; - case W3cHints.CC_CSC: - return View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE; - case W3cHints.TEL: - return View.AUTOFILL_HINT_PHONE; - case W3cHints.EMAIL: - return View.AUTOFILL_HINT_EMAIL_ADDRESS; - default: - return hint; - } - } - /** * Populates a {@link Dataset.Builder} with appropriate values for each {@link AutofillId} * in a {@code AutofillFieldMetadataCollection}. - * * <p> + * * In other words, it constructs an autofill * {@link Dataset.Builder} by applying saved values (from this {@code FilledAutofillFieldCollection}) * to Views specified in a {@code AutofillFieldMetadataCollection}, which represents the current diff --git a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/SettingsActivity.java b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/SettingsActivity.java index 5224bea3..03df3279 100644 --- a/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/SettingsActivity.java +++ b/input/autofill/AutofillFramework/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/settings/SettingsActivity.java @@ -15,24 +15,32 @@ */ package com.example.android.autofillframework.multidatasetservice.settings; +import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; +import android.support.design.widget.Snackbar; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageView; +import android.widget.NumberPicker; import android.widget.Switch; import android.widget.TextView; import com.example.android.autofillframework.R; +import com.example.android.autofillframework.multidatasetservice.AutofillHints; import com.example.android.autofillframework.multidatasetservice.datasource.SharedPrefsAutofillRepository; import com.example.android.autofillframework.multidatasetservice.datasource.SharedPrefsPackageVerificationRepository; +import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillField; +import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection; public class SettingsActivity extends AppCompatActivity { + private static final String TAG = "SettingsActivity"; @Override public void onCreate(Bundle savedInstanceState) { @@ -43,42 +51,28 @@ public class SettingsActivity extends AppCompatActivity { R.id.settings_auth_responses_label, R.id.settings_auth_responses_switch, preferences.isResponseAuth(), - new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean b) { - preferences.setResponseAuth(b); - } - }); + (compoundButton, isResponseAuth) -> preferences.setResponseAuth(isResponseAuth)); setupSettingsSwitch(R.id.settings_auth_datasets_container, R.id.settings_auth_datasets_label, R.id.settings_auth_datasets_switch, preferences.isDatasetAuth(), - new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean b) { - preferences.setDatasetAuth(b); - } - }); + (compoundButton, isDatasetAuth) -> preferences.setDatasetAuth(isDatasetAuth)); + setupSettingsButton(R.id.settings_add_data_container, + R.id.settings_add_data_label, + R.id.settings_add_data_icon, + (view) -> buildAddDataDialog().show()); setupSettingsButton(R.id.settings_clear_data_container, R.id.settings_clear_data_label, R.id.settings_clear_data_icon, - new View.OnClickListener() { - @Override - public void onClick(View view) { - buildClearDataDialog().show(); - } - }); + (view) -> buildClearDataDialog().show()); setupSettingsButton(R.id.settings_auth_credentials_container, R.id.settings_auth_credentials_label, R.id.settings_auth_credentials_icon, - new View.OnClickListener() { - @Override - public void onClick(View view) { - if (preferences.getMasterPassword() != null) { - buildCurrentCredentialsDialog().show(); - } else { - buildNewCredentialsDialog().show(); - } + (view) -> { + if (preferences.getMasterPassword() != null) { + buildCurrentCredentialsDialog().show(); + } else { + buildNewCredentialsDialog().show(); } }); } @@ -88,19 +82,64 @@ public class SettingsActivity extends AppCompatActivity { .setMessage(R.string.settings_clear_data_confirmation) .setTitle(R.string.settings_clear_data_confirmation_title) .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - SharedPrefsAutofillRepository.getInstance().clear(SettingsActivity.this); - SharedPrefsPackageVerificationRepository.getInstance() - .clear(SettingsActivity.this); - MyPreferences.getInstance(SettingsActivity.this).clearCredentials(); - dialog.dismiss(); + .setPositiveButton(R.string.ok, (dialog, which) -> { + SharedPrefsAutofillRepository.getInstance().clear(SettingsActivity.this); + SharedPrefsPackageVerificationRepository.getInstance() + .clear(SettingsActivity.this); + MyPreferences.getInstance(SettingsActivity.this).clearCredentials(); + dialog.dismiss(); + }) + .create(); + } + + private AlertDialog buildAddDataDialog() { + NumberPicker numberOfDatasetsPicker = LayoutInflater + .from(SettingsActivity.this) + .inflate(R.layout.multidataset_service_settings_add_data_dialog, null) + .findViewById(R.id.number_of_datasets_picker); + numberOfDatasetsPicker.setMinValue(0); + numberOfDatasetsPicker.setMaxValue(10); + numberOfDatasetsPicker.setWrapSelectorWheel(false); + return new AlertDialog.Builder(SettingsActivity.this) + .setTitle(R.string.settings_add_data_title) + .setNegativeButton(R.string.cancel, null) + .setMessage(R.string.settings_select_number_of_datasets) + .setView(numberOfDatasetsPicker) + .setPositiveButton(R.string.ok, (dialog, which) -> { + int numOfDatasets = numberOfDatasetsPicker.getValue(); + boolean success = buildAndSaveMockedAutofillFieldCollection( + SettingsActivity.this, numOfDatasets); + dialog.dismiss(); + if (success) { + Snackbar.make(SettingsActivity.this.findViewById(R.id.settings_layout), + SettingsActivity.this.getResources().getQuantityString( + R.plurals.settings_add_data_success, numOfDatasets, + numOfDatasets), + Snackbar.LENGTH_SHORT).show(); } }) .create(); } + /** + * Builds mock autofill data and saves it to repository. + */ + private boolean buildAndSaveMockedAutofillFieldCollection(Context context, int numOfDatasets) { + if (numOfDatasets < 0 || numOfDatasets > 10) { + Log.w(TAG, "Number of Datasets out of range."); + return false; + } + for (int i = 0; i < numOfDatasets * 2; i += 2) { + for (int partition : AutofillHints.PARTITIONS) { + FilledAutofillFieldCollection filledAutofillFieldCollection = + AutofillHints.getFakeFieldCollection(partition, i); + SharedPrefsAutofillRepository.getInstance().saveFilledAutofillFieldCollection( + context, filledAutofillFieldCollection); + } + } + return true; + } + private AlertDialog.Builder prepareCredentialsDialog() { return new AlertDialog.Builder(SettingsActivity.this) .setTitle(R.string.settings_auth_change_credentials_title) @@ -137,13 +176,10 @@ public class SettingsActivity extends AppCompatActivity { return prepareCredentialsDialog() .setMessage(R.string.settings_auth_enter_new_password) .setView(newPasswordField) - .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String password = newPasswordField.getText().toString(); - MyPreferences.getInstance(SettingsActivity.this).setMasterPassword(password); - dialog.dismiss(); - } + .setPositiveButton(R.string.ok, (dialog, which) -> { + String password = newPasswordField.getText().toString(); + MyPreferences.getInstance(SettingsActivity.this).setMasterPassword(password); + dialog.dismiss(); }) .create(); } @@ -155,12 +191,7 @@ public class SettingsActivity extends AppCompatActivity { final Switch switchView = container.findViewById(switchId); switchView.setContentDescription(switchLabel); switchView.setChecked(checked); - container.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - switchView.performClick(); - } - }); + container.setOnClickListener((view) -> switchView.performClick()); switchView.setOnCheckedChangeListener(checkedChangeListener); } diff --git a/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_add_black_24dp.xml b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_add_black_24dp.xml new file mode 100644 index 00000000..e50269d8 --- /dev/null +++ b/input/autofill/AutofillFramework/Application/src/main/res/drawable/ic_add_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="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/> +</vector> diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_activity.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_activity.xml index 3704e40f..a16bf1f5 100644 --- a/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_activity.xml +++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_activity.xml @@ -23,6 +23,7 @@ android:importantForAutofill="no"> <LinearLayout + android:id="@+id/settings_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" @@ -116,6 +117,30 @@ android:text="@string/settings_data_header"/> <LinearLayout + android:id="@+id/settings_add_data_container" + style="@style/Settings.Container" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + android:id="@+id/settings_add_data_label" + style="@style/Settings.Label" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:text="@string/settings_add_data_label" /> + + <ImageView + android:id="@+id/settings_add_data_icon" + style="@style/Settings.Switch" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minHeight="@dimen/a11y_min_touch_target_dimen" + android:layout_marginStart="@dimen/padding_normal" + android:src="@drawable/ic_add_black_24dp"/> + </LinearLayout> + + <LinearLayout android:id="@+id/settings_clear_data_container" style="@style/Settings.Container" android:layout_width="match_parent" diff --git a/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_add_data_dialog.xml b/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_add_data_dialog.xml new file mode 100644 index 00000000..019a3674 --- /dev/null +++ b/input/autofill/AutofillFramework/Application/src/main/res/layout/multidataset_service_settings_add_data_dialog.xml @@ -0,0 +1,23 @@ +<?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. +--> +<NumberPicker + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/number_of_datasets_picker" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_marginStart="@dimen/padding_normal" + android:minHeight="@dimen/a11y_min_touch_target_dimen" />
\ No newline at end of file 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 4961104d..11b0942c 100644 --- a/input/autofill/AutofillFramework/Application/src/main/res/values/strings.xml +++ b/input/autofill/AutofillFramework/Application/src/main/res/values/strings.xml @@ -44,8 +44,15 @@ <string name="settings_cancel">Cancel</string> <string name="settings_save">Save</string> <string name="settings_authenticate_responses">Authenticate responses</string> - <string name="settings_authenticate_datasets">Authenticate datasets</string> - <string name="settings_clear_data_label">Clear all data (including credentials)</string> + <string name="settings_authenticate_datasets">Authenticate Datasets</string> + <string name="settings_add_data_label">Add fake Autofill data</string> + <string name="settings_add_data_title">Add Autofill Datasets</string> + <string name="settings_select_number_of_datasets">Select number of Datasets.</string> + <plurals name="settings_add_data_success"> + <item quantity="one">Added %d Dataset.</item> + <item quantity="other">Added %d Datasets.</item> + </plurals> + <string name="settings_clear_data_label">Clear all autofill data (including credentials)</string> <string name="settings_clear_data_confirmation">Are you sure you want to delete all autofill data from the sample service? </string> @@ -59,6 +66,7 @@ <string name="settings_auth_enter_current_password">Enter current password</string> <string name="settings_auth_enter_new_password">Enter new password</string> <string name="settings_auth_change_credentials_title">Change credentials</string> + <string name="settings_number_of_datasets_label">Number of Datasets</string> <string name="clear_label">Clear</string> <string name="login_label">Login</string> <string name="to_label">To</string> |