diff options
author | Douglas Sigelbaum <sigelbaum@google.com> | 2017-12-13 12:13:36 -0800 |
---|---|---|
committer | Douglas Sigelbaum <sigelbaum@google.com> | 2018-01-22 15:11:43 -0800 |
commit | 591f74c8fbea899f7590351bc48141641266349b (patch) | |
tree | a26095c12d2eafeefa978e0b77d19684f610d30f /input/autofill | |
parent | e83dc7e94d3d93109fa78b7a744142d430d7367d (diff) | |
download | android-591f74c8fbea899f7590351bc48141641266349b.tar.gz |
Autofill sample: Refactor to allow for more heuristics.
* Moved default autofill hints and fake data to JSON that populates
* local DB.
* Made new tables in DB to represent heuristic types.
* TODO: Fix bug where adding fake data doesn't work the first time.
Bug: 71907097
Test: Manual
Change-Id: Iffae737662e402cf17e63a6d5d0f0a276d6807bc
Diffstat (limited to 'input/autofill')
26 files changed, 2105 insertions, 907 deletions
diff --git a/input/autofill/AutofillFramework/afservice/src/androidTest/java/com/example/android/autofill/service/data/source/local/AutofillDaoTest.java b/input/autofill/AutofillFramework/afservice/src/androidTest/java/com/example/android/autofill/service/data/source/local/AutofillDaoTest.java index 936da2b1..e8a501d2 100644 --- a/input/autofill/AutofillFramework/afservice/src/androidTest/java/com/example/android/autofill/service/data/source/local/AutofillDaoTest.java +++ b/input/autofill/AutofillFramework/afservice/src/androidTest/java/com/example/android/autofill/service/data/source/local/AutofillDaoTest.java @@ -74,7 +74,7 @@ public class AutofillDaoTest { datasetWithFilledAutofillFields.filledAutofillFields = Arrays.asList(mUsernameField, mPasswordField); datasetWithFilledAutofillFields.filledAutofillFields - .sort(Comparator.comparing(FilledAutofillField::getHint)); + .sort(Comparator.comparing(FilledAutofillField::getFieldType)); // When inserting a page's autofill fields. mDatabase.autofillDao().saveAutofillDataset(mDataset); @@ -87,7 +87,7 @@ public class AutofillDaoTest { List<DatasetWithFilledAutofillFields> loadedDatasets = mDatabase.autofillDao() .getDatasets(allHints); loadedDatasets.get(0).filledAutofillFields.sort( - Comparator.comparing(FilledAutofillField::getHint)); + Comparator.comparing(FilledAutofillField::getFieldType)); assertThat(loadedDatasets, contains(datasetWithFilledAutofillFields)); assertThat(loadedDatasets, hasSize(1)); } diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AuthActivity.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AuthActivity.java index 2bcebaff..284769dd 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AuthActivity.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AuthActivity.java @@ -36,14 +36,19 @@ import com.example.android.autofill.service.data.ClientViewMetadataBuilder; import com.example.android.autofill.service.data.DataCallback; import com.example.android.autofill.service.data.adapter.DatasetAdapter; import com.example.android.autofill.service.data.adapter.ResponseAdapter; +import com.example.android.autofill.service.data.source.DefaultFieldTypesSource; +import com.example.android.autofill.service.data.source.local.DefaultFieldTypesLocalJsonSource; import com.example.android.autofill.service.data.source.local.DigitalAssetLinksRepository; import com.example.android.autofill.service.data.source.local.LocalAutofillDataSource; import com.example.android.autofill.service.data.source.local.dao.AutofillDao; import com.example.android.autofill.service.data.source.local.db.AutofillDatabase; import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields; +import com.example.android.autofill.service.model.FieldTypeWithHints; import com.example.android.autofill.service.settings.MyPreferences; import com.example.android.autofill.service.util.AppExecutors; +import com.google.gson.GsonBuilder; +import java.util.HashMap; import java.util.List; import static android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE; @@ -94,7 +99,11 @@ public class AuthActivity extends AppCompatActivity { setContentView(R.layout.multidataset_service_auth_activity); SharedPreferences sharedPreferences = getSharedPreferences(LocalAutofillDataSource.SHARED_PREF_KEY, Context.MODE_PRIVATE); - AutofillDao autofillDao = AutofillDatabase.getInstance(this).autofillDao(); + DefaultFieldTypesSource defaultFieldTypesSource = + DefaultFieldTypesLocalJsonSource.getInstance(getResources(), + new GsonBuilder().create()); + AutofillDao autofillDao = AutofillDatabase.getInstance(this, + defaultFieldTypesSource, new AppExecutors()).autofillDao(); mLocalAutofillDataSource = LocalAutofillDataSource.getInstance(sharedPreferences, autofillDao, new AppExecutors()); mDalRepository = DigitalAssetLinksRepository.getInstance(getPackageManager()); @@ -139,21 +148,33 @@ public class AuthActivity extends AppCompatActivity { boolean forResponse = intent.getBooleanExtra(EXTRA_FOR_RESPONSE, true); AssistStructure structure = intent.getParcelableExtra(EXTRA_ASSIST_STRUCTURE); ClientParser clientParser = new ClientParser(structure); - ClientViewMetadataBuilder builder = new ClientViewMetadataBuilder(clientParser); - mClientViewMetadata = builder.buildClientViewMetadata(); - mDatasetAdapter = new DatasetAdapter(clientParser); - mResponseAdapter = new ResponseAdapter(this, mClientViewMetadata, mPackageName, - mDatasetAdapter); mReplyIntent = new Intent(); - if (forResponse) { - fetchAllDatasetsAndSetIntent(); - } else { - String datasetName = intent.getStringExtra(EXTRA_DATASET_NAME); - fetchDatasetAndSetIntent(datasetName); - } + mLocalAutofillDataSource.getFieldTypeByAutofillHints(new DataCallback<HashMap<String, FieldTypeWithHints>>() { + @Override + public void onLoaded(HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint) { + ClientViewMetadataBuilder builder = new ClientViewMetadataBuilder(clientParser, + fieldTypesByAutofillHint); + mClientViewMetadata = builder.buildClientViewMetadata(); + mDatasetAdapter = new DatasetAdapter(clientParser); + mResponseAdapter = new ResponseAdapter(AuthActivity.this, + mClientViewMetadata, mPackageName, mDatasetAdapter); + if (forResponse) { + fetchAllDatasetsAndSetIntent(fieldTypesByAutofillHint); + } else { + String datasetName = intent.getStringExtra(EXTRA_DATASET_NAME); + fetchDatasetAndSetIntent(fieldTypesByAutofillHint, datasetName); + } + } + + @Override + public void onDataNotAvailable(String msg, Object... params) { + + } + }); } - private void fetchDatasetAndSetIntent(String datasetName) { + private void fetchDatasetAndSetIntent( + HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint, String datasetName) { mLocalAutofillDataSource.getAutofillDataset(mClientViewMetadata.getAllHints(), datasetName, new DataCallback<DatasetWithFilledAutofillFields>() { @Override @@ -161,7 +182,8 @@ public class AuthActivity extends AppCompatActivity { String datasetName = dataset.autofillDataset.getDatasetName(); RemoteViews remoteViews = RemoteViewsHelper.viewsWithNoAuth( mPackageName, datasetName); - setDatasetIntent(mDatasetAdapter.buildDataset(dataset, remoteViews)); + setDatasetIntent(mDatasetAdapter.buildDataset(fieldTypesByAutofillHint, + dataset, remoteViews)); finish(); } @@ -173,14 +195,15 @@ public class AuthActivity extends AppCompatActivity { }); } - private void fetchAllDatasetsAndSetIntent() { + private void fetchAllDatasetsAndSetIntent( + HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint) { mLocalAutofillDataSource.getAutofillDatasets(mClientViewMetadata.getAllHints(), new DataCallback<List<DatasetWithFilledAutofillFields>>() { @Override public void onLoaded(List<DatasetWithFilledAutofillFields> datasets) { boolean datasetAuth = mPreferences.isDatasetAuth(); - FillResponse fillResponse = mResponseAdapter.buildResponse(datasets, - datasetAuth); + FillResponse fillResponse = mResponseAdapter.buildResponse( + fieldTypesByAutofillHint, datasets, datasetAuth); setResponseIntent(fillResponse); finish(); } diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AutofillHintProperties.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AutofillHintProperties.java index 9b593426..8314eb30 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AutofillHintProperties.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AutofillHintProperties.java @@ -85,4 +85,8 @@ public final class AutofillHintProperties { public boolean isValidType(int type) { return mValidTypes.contains(type); } + + public Set<Integer> getTypes() { + return mValidTypes; + } } diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AutofillHints.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AutofillHints.java index 39b189c7..cd4231d1 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AutofillHints.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/AutofillHints.java @@ -15,18 +15,19 @@ */ package com.example.android.autofill.service; -import android.service.autofill.SaveInfo; import android.support.annotation.NonNull; -import android.view.View; +import com.example.android.autofill.service.model.FakeData; +import com.example.android.autofill.service.model.FieldType; +import com.example.android.autofill.service.model.FieldTypeWithHints; import com.example.android.autofill.service.model.FilledAutofillField; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import java.util.ArrayList; import java.util.Calendar; +import java.util.HashMap; import java.util.List; import java.util.Objects; +import java.util.UUID; import static com.example.android.autofill.service.util.Util.logd; import static com.example.android.autofill.service.util.Util.logw; @@ -41,657 +42,64 @@ public final class AutofillHints { 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, datasetId) -> { - String textValue = "email" + seed; - return new FilledAutofillField(datasetId, - View.AUTOFILL_HINT_EMAIL_ADDRESS, textValue); - - }, 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, datasetId) -> { - String textValue = "name" + seed; - return new FilledAutofillField(datasetId, View.AUTOFILL_HINT_NAME, - textValue); - - }, 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, datasetId) -> { - String textValue = "login" + seed; - return new FilledAutofillField(datasetId, - View.AUTOFILL_HINT_USERNAME, textValue); - - }, 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, datasetId) -> { - String textValue = "login" + seed; - return new FilledAutofillField(datasetId, - View.AUTOFILL_HINT_PASSWORD, textValue); - - }, View.AUTOFILL_TYPE_TEXT)) - .put(View.AUTOFILL_HINT_PHONE, new AutofillHintProperties( - View.AUTOFILL_HINT_PHONE, SaveInfo.SAVE_DATA_TYPE_GENERIC, - PARTITION_OTHER, - (seed, datasetId) -> { - String textValue = "" + seed + "2345678910"; - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_PHONE, textValue); - }, 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, datasetId) -> { - String textValue = - "" + seed + " Fake Ln, Fake, FA, FAA 10001"; - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_POSTAL_ADDRESS, textValue); - }, 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, datasetId) -> { - String textValue = "1000" + seed; - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_POSTAL_CODE, textValue); - }, 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, datasetId) -> { - String textValue = "" + seed + "234567"; - return new FilledAutofillField( - datasetId, - View.AUTOFILL_HINT_CREDIT_CARD_NUMBER, textValue); - }, 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, datasetId) -> { - String textValue = "" + seed + seed + seed; - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE, - textValue); - }, 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, datasetId) -> { - Calendar calendar = Calendar.getInstance(); - calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + seed); - Long dateValue = calendar.getTimeInMillis(); - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE, - dateValue); - }, 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, datasetId) -> { - CharSequence[] months = monthRange(); - int month = seed % months.length; - Calendar calendar = Calendar.getInstance(); - calendar.set(Calendar.MONTH, month); - String textValue = Integer.toString(month); - Long dateValue = calendar.getTimeInMillis(); - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH, - textValue, dateValue); - }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST, - View.AUTOFILL_TYPE_DATE)) - .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, datasetId) -> { - Calendar calendar = Calendar.getInstance(); - int expYear = calendar.get(Calendar.YEAR) + seed; - calendar.set(Calendar.YEAR, expYear); - Long dateValue = calendar.getTimeInMillis(); - String textValue = Integer.toString(expYear); - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR, - textValue, dateValue); - }, 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, datasetId) -> { - CharSequence[] days = dayRange(); - int day = seed % days.length; - Calendar calendar = Calendar.getInstance(); - calendar.set(Calendar.DATE, day); - String textValue = Integer.toString(day); - Long dateValue = calendar.getTimeInMillis(); - return new FilledAutofillField(datasetId, - View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY, - textValue, dateValue); - }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST, - View.AUTOFILL_TYPE_DATE)) - .put(W3cHints.HONORIFIC_PREFIX, new AutofillHintProperties( - W3cHints.HONORIFIC_PREFIX, SaveInfo.SAVE_DATA_TYPE_GENERIC, - PARTITION_OTHER, - (seed, datasetId) -> { - CharSequence[] examplePrefixes = {"Miss", "Ms.", "Mr.", "Mx.", - "Sr.", "Dr.", "Lady", "Lord"}; - String textValueFromList = - examplePrefixes[seed % examplePrefixes.length].toString(); - return new FilledAutofillField( - datasetId, W3cHints.HONORIFIC_PREFIX, textValueFromList); - }, 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, datasetId) -> { - String textValue = "name" + seed; - return new FilledAutofillField( - datasetId, W3cHints.GIVEN_NAME, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.ADDITIONAL_NAME, new AutofillHintProperties( - W3cHints.ADDITIONAL_NAME, SaveInfo.SAVE_DATA_TYPE_GENERIC, - PARTITION_OTHER, - (seed, datasetId) -> { - String textValue = "addtlname" + seed; - return new FilledAutofillField( - datasetId, W3cHints.ADDITIONAL_NAME, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.FAMILY_NAME, new AutofillHintProperties( - W3cHints.FAMILY_NAME, SaveInfo.SAVE_DATA_TYPE_GENERIC, - PARTITION_OTHER, - (seed, datasetId) -> { - String textValue = "famname" + seed; - return new FilledAutofillField( - datasetId, W3cHints.FAMILY_NAME, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.HONORIFIC_SUFFIX, new AutofillHintProperties( - W3cHints.HONORIFIC_SUFFIX, SaveInfo.SAVE_DATA_TYPE_GENERIC, - PARTITION_OTHER, - (seed, datasetId) -> { - CharSequence[] exampleSuffixes = {"san", "kun", "chan", "sama"}; - String textValueFromListValue = - exampleSuffixes[seed % exampleSuffixes.length].toString(); - return new FilledAutofillField( - datasetId, W3cHints.HONORIFIC_SUFFIX, - textValueFromListValue); - }, 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, datasetId) -> { - String textValue = "login" + seed; - return new FilledAutofillField( - datasetId, W3cHints.NEW_PASSWORD, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.CURRENT_PASSWORD, new AutofillHintProperties( - View.AUTOFILL_HINT_PASSWORD, SaveInfo.SAVE_DATA_TYPE_PASSWORD, - PARTITION_OTHER, - (seed, datasetId) -> { - String textValue = "login" + seed; - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_PASSWORD, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.ORGANIZATION_TITLE, new AutofillHintProperties( - W3cHints.ORGANIZATION_TITLE, SaveInfo.SAVE_DATA_TYPE_GENERIC, - PARTITION_OTHER, - (seed, datasetId) -> { - String textValue = "org" + seed; - return new FilledAutofillField( - datasetId, W3cHints.ORGANIZATION_TITLE, textValue); - }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) - .put(W3cHints.ORGANIZATION, new AutofillHintProperties(W3cHints.ORGANIZATION, - SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, - (seed, datasetId) -> { - String textValue = "org" + seed; - return new FilledAutofillField( - datasetId, W3cHints.ORGANIZATION, textValue); - }, 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, datasetId) -> { - String textValue = - "" + seed + " Fake Ln, Fake, FA, FAA 10001"; - return new FilledAutofillField( - datasetId, W3cHints.STREET_ADDRESS, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.ADDRESS_LINE1, new AutofillHintProperties(W3cHints.ADDRESS_LINE1, - SaveInfo.SAVE_DATA_TYPE_ADDRESS, - PARTITION_ADDRESS, - (seed, datasetId) -> { - String textValue = "" + seed + " Fake Ln"; - return new FilledAutofillField( - datasetId, W3cHints.ADDRESS_LINE1, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.ADDRESS_LINE2, new AutofillHintProperties(W3cHints.ADDRESS_LINE2, - SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS, - (seed, datasetId) -> { - String textValue = "Bldg. " + seed; - return new FilledAutofillField( - datasetId, W3cHints.ADDRESS_LINE2, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.ADDRESS_LINE3, new AutofillHintProperties(W3cHints.ADDRESS_LINE3, - SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS, - (seed, datasetId) -> { - String textValue = "Suite " + seed; - return new FilledAutofillField( - datasetId, W3cHints.ADDRESS_LINE3, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.ADDRESS_LEVEL4, new AutofillHintProperties( - W3cHints.ADDRESS_LEVEL4, SaveInfo.SAVE_DATA_TYPE_ADDRESS, - PARTITION_ADDRESS, - (seed, datasetId) -> { - String textValue = "city " + seed; - return new FilledAutofillField( - datasetId, W3cHints.ADDRESS_LEVEL4, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.ADDRESS_LEVEL3, new AutofillHintProperties( - W3cHints.ADDRESS_LEVEL3, SaveInfo.SAVE_DATA_TYPE_ADDRESS, - PARTITION_ADDRESS, - (seed, datasetId) -> { - String textValue = "county " + seed; - return new FilledAutofillField( - datasetId, W3cHints.ADDRESS_LEVEL3, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.ADDRESS_LEVEL2, new AutofillHintProperties( - W3cHints.ADDRESS_LEVEL2, SaveInfo.SAVE_DATA_TYPE_ADDRESS, - PARTITION_ADDRESS, - (seed, datasetId) -> { - String textValue = "state " + seed; - return new FilledAutofillField( - datasetId, W3cHints.ADDRESS_LEVEL2, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.ADDRESS_LEVEL1, new AutofillHintProperties( - W3cHints.ADDRESS_LEVEL1, SaveInfo.SAVE_DATA_TYPE_ADDRESS, - PARTITION_ADDRESS, - (seed, datasetId) -> { - String textValue = "country " + seed; - return new FilledAutofillField( - datasetId, W3cHints.ADDRESS_LEVEL1, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.COUNTRY, new AutofillHintProperties(W3cHints.COUNTRY, - SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS, - (seed, datasetId) -> { - String textValue = "country " + seed; - return new FilledAutofillField( - datasetId, W3cHints.COUNTRY, textValue); - }, 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, datasetId) -> { - CharSequence[] exampleCountries = {"USA", "Mexico", "Canada"}; - String textValue = exampleCountries[seed % exampleCountries.length] - .toString(); - return new FilledAutofillField( - datasetId, W3cHints.COUNTRY_NAME, textValue); - }, 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, datasetId) -> { - String textValue = "" + seed + seed + seed + seed + seed; - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_POSTAL_CODE, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.CC_NAME, new AutofillHintProperties(W3cHints.CC_NAME, - SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, - PARTITION_CREDIT_CARD, - (seed, datasetId) -> { - String textValue = "firstname" + seed + "lastname" + seed; - return new FilledAutofillField( - datasetId, W3cHints.CC_NAME, textValue); - }, 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, datasetId) -> { - String textValue = "givenname" + seed; - return new FilledAutofillField( - datasetId, W3cHints.CC_GIVEN_NAME, textValue); - }, 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, datasetId) -> { - String textValue = "addtlname" + seed; - return new FilledAutofillField( - datasetId, W3cHints.CC_ADDITIONAL_NAME, textValue); - }, 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, datasetId) -> { - String textValue = "familyname" + seed; - return new FilledAutofillField( - datasetId, W3cHints.CC_FAMILY_NAME, textValue); - }, 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, datasetId) -> { - String textValue = "" + seed + "234567"; - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_CREDIT_CARD_NUMBER, - textValue); - }, 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, datasetId) -> { - Calendar calendar = Calendar.getInstance(); - calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + seed); - Long dateValue = calendar.getTimeInMillis(); - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE, - dateValue); - }, 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, datasetId) -> { - CharSequence[] months = monthRange(); - String textValueFromListValue = months[seed % months.length] - .toString(); - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH, - textValueFromListValue); - }, 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, datasetId) -> { - Calendar calendar = Calendar.getInstance(); - int expYear = calendar.get(Calendar.YEAR) + seed; - calendar.set(Calendar.YEAR, expYear); - Long dateValue = calendar.getTimeInMillis(); - String textValue = "" + expYear; - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR, - textValue, dateValue); - }, 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, datasetId) -> { - String textValue = "" + seed + seed + seed; - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE, - textValue); - - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.CC_TYPE, new AutofillHintProperties(W3cHints.CC_TYPE, - SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD, - (seed, datasetId) -> { - String textValue = "type" + seed; - return new FilledAutofillField( - datasetId, W3cHints.CC_TYPE, textValue); - }, 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, datasetId) -> { - CharSequence[] exampleCurrencies = {"USD", "CAD", "KYD", "CRC"}; - String textValueFromListValue = - exampleCurrencies[seed % exampleCurrencies.length] - .toString(); - return new FilledAutofillField( - datasetId, W3cHints.TRANSACTION_CURRENCY, - textValueFromListValue); - }, 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, datasetId) -> { - String textValue = "" + seed * 100; - return new FilledAutofillField( - datasetId, W3cHints.TRANSACTION_AMOUNT, textValue); - }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) - .put(W3cHints.LANGUAGE, new AutofillHintProperties(W3cHints.LANGUAGE, - SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, - (seed, datasetId) -> { - CharSequence[] exampleLanguages = {"Bulgarian", "Croatian", "Czech", - "Danish", "Dutch", "English", "Estonian"}; - String textValueFromListValue = - exampleLanguages[seed % exampleLanguages.length].toString(); - return new FilledAutofillField( - datasetId, W3cHints.LANGUAGE, textValueFromListValue); - }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) - .put(W3cHints.BDAY, new AutofillHintProperties(W3cHints.BDAY, - SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, - (seed, datasetId) -> { - 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); - Long dateValue = calendar.getTimeInMillis(); - return new FilledAutofillField(datasetId, W3cHints.BDAY, dateValue); - }, View.AUTOFILL_TYPE_DATE)) - .put(W3cHints.BDAY_DAY, new AutofillHintProperties(W3cHints.BDAY_DAY, - SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, - (seed, datasetId) -> { - String textValue = "" + seed % 27; - return new FilledAutofillField( - datasetId, W3cHints.BDAY_DAY, textValue); - }, 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, datasetId) -> { - String textValue = "" + seed % 12; - return new FilledAutofillField( - datasetId, W3cHints.BDAY_MONTH, textValue); - - }, 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, datasetId) -> { - int year = Calendar.getInstance().get(Calendar.YEAR) - seed * 10; - String textValue = "" + year; - return new FilledAutofillField( - datasetId, W3cHints.BDAY_YEAR, textValue); - }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) - .put(W3cHints.SEX, new AutofillHintProperties(W3cHints.SEX, - SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, - (seed, datasetId) -> { - String textValue = "Other"; - return new FilledAutofillField( - datasetId, W3cHints.SEX, textValue); - }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) - .put(W3cHints.URL, new AutofillHintProperties(W3cHints.URL, - SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, - (seed, datasetId) -> { - String textValue = "http://google.com"; - return new FilledAutofillField( - datasetId, W3cHints.URL, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.PHOTO, new AutofillHintProperties(W3cHints.PHOTO, - SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, - (seed, datasetId) -> { - String textValue = "photo" + seed + ".jpg"; - return new FilledAutofillField( - datasetId, W3cHints.PHOTO, textValue); - }, 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, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.PREFIX_SECTION); - }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) - .put(W3cHints.SHIPPING, new AutofillHintProperties(W3cHints.SHIPPING, - SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_ADDRESS, - (seed, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.SHIPPING); - }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) - .put(W3cHints.BILLING, new AutofillHintProperties(W3cHints.BILLING, - SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_ADDRESS, - (seed, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.BILLING); - }, 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, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.PREFIX_HOME); - }, 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, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.PREFIX_WORK); - }, 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, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.PREFIX_FAX); - }, 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, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.PREFIX_PAGER); - }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) - .put(W3cHints.TEL, new AutofillHintProperties(W3cHints.TEL, - SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER, - (seed, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.TEL); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.TEL_COUNTRY_CODE, new AutofillHintProperties( - W3cHints.TEL_COUNTRY_CODE, SaveInfo.SAVE_DATA_TYPE_GENERIC, - PARTITION_OTHER, - (seed, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.TEL_COUNTRY_CODE); - }, 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, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.TEL_NATIONAL); - }, 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, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.TEL_AREA_CODE); - }, 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, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.TEL_LOCAL); - }, 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, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.TEL_LOCAL_PREFIX); - }, 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, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.TEL_LOCAL_SUFFIX); - }, 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, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.TEL_EXTENSION); - }, 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, datasetId) -> { - String textValue = "email" + seed; - return new FilledAutofillField( - datasetId, View.AUTOFILL_HINT_EMAIL_ADDRESS, textValue); - }, View.AUTOFILL_TYPE_TEXT)) - .put(W3cHints.IMPP, new AutofillHintProperties(W3cHints.IMPP, - SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS, PARTITION_EMAIL, - (seed, datasetId) -> { - return new FilledAutofillField( - datasetId, W3cHints.IMPP); - }, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST)) - .build(); private AutofillHints() { } - public static boolean isValidTypeForHints(@NonNull String hint, int type) { - if (sValidHints.containsKey(hint)) { - boolean valid = sValidHints.get(hint).isValidType(type); - if (valid) { - return true; + public static FilledAutofillField generateFakeField(FieldTypeWithHints fieldTypeWithHints, + int seed, String datasetId) { + FakeData fakeData = fieldTypeWithHints.fieldType.getFakeData(); + String fieldTypeName = fieldTypeWithHints.fieldType.getTypeName(); + String text = null; + Long date = null; + Boolean toggle = null; + if (fakeData.strictExampleSet != null && fakeData.strictExampleSet.strings != null && + fakeData.strictExampleSet.strings.size() > 0 && + !fakeData.strictExampleSet.strings.get(0).isEmpty()) { + List<String> choices = fakeData.strictExampleSet.strings; + text = choices.get(seed % choices.size()); + } else if (fakeData.textTemplate != null) { + text = fakeData.textTemplate.replace("seed", "" + seed) + .replace("curr_time", "" + Calendar.getInstance().getTimeInMillis()); + } else if (fakeData.dateTemplate != null) { + if (fakeData.dateTemplate.contains("curr_time")) { + date = Calendar.getInstance().getTimeInMillis(); } } - return false; - } - - public static boolean isValidHint(@NonNull String hint) { - return sValidHints.containsKey(hint); - } - - public static int getSaveTypeForHint(@NonNull String hint) { - if (sValidHints.containsKey(hint)) { - return sValidHints.get(hint).getSaveType(); - } else { - return 0; - } - } - - public static FilledAutofillField generateFakeField(@NonNull String hint, int seed, - String datasetId) { - if (isValidHint(hint)) { - return sValidHints.get(hint).generateFakeField(seed, datasetId); - } else { - return null; - } - } - - public static ImmutableSet<String> getHints() { - return sValidHints.keySet(); + FilledAutofillField filledAutofillField = new FilledAutofillField(datasetId, fieldTypeName, + text, date, toggle); + boolean isNull = filledAutofillField.isNull(); + return filledAutofillField; } - public static List<String> convertToStoredHintNames(@NonNull List<String> hints) { - return convertToStoredHintNames(hints, PARTITION_ALL); + public static String getFieldTypeNameFromAutofillHints( + HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint, + @NonNull List<String> hints) { + return getFieldTypeNameFromAutofillHints(fieldTypesByAutofillHint, hints, PARTITION_ALL); } - public static List<String> convertToStoredHintNames(@NonNull List<String> hints, int partition) { - return removePrefixes(hints) + public static String getFieldTypeNameFromAutofillHints( + HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint, + @NonNull List<String> hints, int partition) { + List<String> fieldTypeNames = removePrefixes(hints) .stream() - .filter(sValidHints::containsKey) - .map(sValidHints::get) + .filter(fieldTypesByAutofillHint::containsKey) + .map(fieldTypesByAutofillHint::get) .filter(Objects::nonNull) - .filter((properties) -> matchesPartition(properties, partition)) - .map(AutofillHintProperties::getAutofillHint) + .filter((fieldTypeWithHints) -> + matchesPartition(fieldTypeWithHints.fieldType.getPartition(), partition)) + .map(FieldTypeWithHints::getFieldType).map(FieldType::getTypeName) .collect(toList()); + if (fieldTypeNames != null && fieldTypeNames.size() > 0) { + return fieldTypeNames.get(0); + } else { + return null; + } } - public static boolean matchesPartition(@NonNull String hint, int partition) { - return isValidHint(hint) && matchesPartition(sValidHints.get(hint), partition); - } - - private static boolean matchesPartition(@NonNull AutofillHintProperties properties, - int partition) { - return partition == PARTITION_ALL || properties.getPartition() == partition; + public static boolean matchesPartition(int partition, int otherPartition) { + return partition == PARTITION_ALL || otherPartition == PARTITION_ALL || + partition == otherPartition; } private static List<String> removePrefixes(@NonNull List<String> hints) { @@ -726,22 +134,6 @@ public final class AutofillHints { return hintsWithoutPrefixes; } - 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; - } - private static boolean isW3cSectionPrefix(@NonNull String hint) { return hint.startsWith(W3cHints.PREFIX_SECTION); } diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/MyAutofillService.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/MyAutofillService.java index 14c0a142..b50c8482 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/MyAutofillService.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/MyAutofillService.java @@ -19,7 +19,6 @@ import android.app.assist.AssistStructure; import android.content.Context; import android.content.IntentSender; import android.content.SharedPreferences; -import android.os.Bundle; import android.os.CancellationSignal; import android.service.autofill.AutofillService; import android.service.autofill.FillCallback; @@ -38,7 +37,9 @@ import com.example.android.autofill.service.data.ClientViewMetadataBuilder; import com.example.android.autofill.service.data.DataCallback; import com.example.android.autofill.service.data.adapter.DatasetAdapter; import com.example.android.autofill.service.data.adapter.ResponseAdapter; +import com.example.android.autofill.service.data.source.DefaultFieldTypesSource; import com.example.android.autofill.service.data.source.PackageVerificationDataSource; +import com.example.android.autofill.service.data.source.local.DefaultFieldTypesLocalJsonSource; import com.example.android.autofill.service.data.source.local.DigitalAssetLinksRepository; import com.example.android.autofill.service.data.source.local.LocalAutofillDataSource; import com.example.android.autofill.service.data.source.local.SharedPrefsPackageVerificationRepository; @@ -47,10 +48,13 @@ import com.example.android.autofill.service.data.source.local.db.AutofillDatabas import com.example.android.autofill.service.model.DalCheck; import com.example.android.autofill.service.model.DalInfo; import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields; +import com.example.android.autofill.service.model.FieldTypeWithHints; import com.example.android.autofill.service.settings.MyPreferences; import com.example.android.autofill.service.util.AppExecutors; import com.example.android.autofill.service.util.Util; +import com.google.gson.GsonBuilder; +import java.util.HashMap; import java.util.List; import static com.example.android.autofill.service.util.Util.DalCheckRequirement; @@ -80,7 +84,11 @@ public class MyAutofillService extends AutofillService { Util.setLoggingLevel(mPreferences.getLoggingLevel()); SharedPreferences localAfDataSourceSharedPrefs = getSharedPreferences(LocalAutofillDataSource.SHARED_PREF_KEY, Context.MODE_PRIVATE); - AutofillDao autofillDao = AutofillDatabase.getInstance(this).autofillDao(); + DefaultFieldTypesSource defaultFieldTypesSource = + DefaultFieldTypesLocalJsonSource.getInstance(getResources(), + new GsonBuilder().create()); + AutofillDao autofillDao = AutofillDatabase.getInstance(this, + defaultFieldTypesSource, new AppExecutors()).autofillDao(); mLocalAutofillDataSource = LocalAutofillDataSource.getInstance(localAfDataSourceSharedPrefs, autofillDao, new AppExecutors()); mDalRepository = DigitalAssetLinksRepository.getInstance(getPackageManager()); @@ -95,26 +103,48 @@ public class MyAutofillService extends AutofillService { fillContexts.stream().map(FillContext::getStructure).collect(toList()); AssistStructure latestStructure = fillContexts.get(fillContexts.size() - 1).getStructure(); ClientParser parser = new ClientParser(structures); - DatasetAdapter datasetAdapter = new DatasetAdapter(parser); - ClientViewMetadataBuilder clientViewMetadataBuilder = new ClientViewMetadataBuilder(parser); - mClientViewMetadata = clientViewMetadataBuilder.buildClientViewMetadata(); - mResponseAdapter = new ResponseAdapter(this, mClientViewMetadata, - getPackageName(), datasetAdapter); - String packageName = latestStructure.getActivityComponent().getPackageName(); - if (!mPackageVerificationRepository.putPackageSignatures(packageName)) { - callback.onFailure(getString(R.string.invalid_package_signature)); - return; - } - if (logVerboseEnabled()) { - logv("onFillRequest(): clientState=%s", - bundleToString(request.getClientState())); - dumpStructure(latestStructure); - } - cancellationSignal.setOnCancelListener(() -> - logw("Cancel autofill not implemented in this sample.") - ); + + // Check user's settings for authenticating Responses and Datasets. boolean responseAuth = mPreferences.isResponseAuth(); + boolean datasetAuth = mPreferences.isDatasetAuth(); + mLocalAutofillDataSource.getFieldTypeByAutofillHints( + new DataCallback<HashMap<String, FieldTypeWithHints>>() { + @Override + public void onLoaded(HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint) { + DatasetAdapter datasetAdapter = new DatasetAdapter(parser); + ClientViewMetadataBuilder clientViewMetadataBuilder = + new ClientViewMetadataBuilder(parser, fieldTypesByAutofillHint); + mClientViewMetadata = clientViewMetadataBuilder.buildClientViewMetadata(); + mResponseAdapter = new ResponseAdapter(MyAutofillService.this, + mClientViewMetadata, getPackageName(), datasetAdapter); + String packageName = latestStructure.getActivityComponent().getPackageName(); + if (!mPackageVerificationRepository.putPackageSignatures(packageName)) { + callback.onFailure(getString(R.string.invalid_package_signature)); + return; + } + if (logVerboseEnabled()) { + logv("onFillRequest(): clientState=%s", + bundleToString(request.getClientState())); + dumpStructure(latestStructure); + } + cancellationSignal.setOnCancelListener(() -> + logw("Cancel autofill not implemented in this sample.") + ); + fetchDataAndGenerateResponse(fieldTypesByAutofillHint, responseAuth, + datasetAuth, callback); + } + + @Override + public void onDataNotAvailable(String msg, Object... params) { + + } + }); + } + + private void fetchDataAndGenerateResponse( + HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint, boolean responseAuth, + boolean datasetAuth, FillCallback callback) { if (responseAuth) { // If the entire Autofill Response is authenticated, AuthActivity is used // to generate Response. @@ -126,13 +156,12 @@ public class MyAutofillService extends AutofillService { callback.onSuccess(response); } } else { - boolean datasetAuth = mPreferences.isDatasetAuth(); mLocalAutofillDataSource.getAutofillDatasets(mClientViewMetadata.getAllHints(), new DataCallback<List<DatasetWithFilledAutofillFields>>() { @Override public void onLoaded(List<DatasetWithFilledAutofillFields> datasets) { - FillResponse response = mResponseAdapter.buildResponse(datasets, - datasetAuth); + FillResponse response = mResponseAdapter.buildResponse( + fieldTypesByAutofillHint, datasets, datasetAuth); callback.onSuccess(response); } @@ -152,20 +181,32 @@ public class MyAutofillService extends AutofillService { fillContexts.stream().map(FillContext::getStructure).collect(toList()); AssistStructure latestStructure = fillContexts.get(fillContexts.size() - 1).getStructure(); ClientParser parser = new ClientParser(structures); - Bundle clientState = request.getClientState(); - mAutofillDataBuilder = new ClientAutofillDataBuilder(parser, clientState); - ClientViewMetadataBuilder clientViewMetadataBuilder = new ClientViewMetadataBuilder(parser); - mClientViewMetadata = clientViewMetadataBuilder.buildClientViewMetadata(); - String packageName = latestStructure.getActivityComponent().getPackageName(); - if (!mPackageVerificationRepository.putPackageSignatures(packageName)) { - callback.onFailure(getString(R.string.invalid_package_signature)); - return; - } - if (logVerboseEnabled()) { - logv("onSaveRequest(): clientState=%s", bundleToString(clientState)); - } - dumpStructure(latestStructure); - checkWebDomainAndBuildAutofillData(packageName, callback); + mLocalAutofillDataSource.getFieldTypeByAutofillHints( + new DataCallback<HashMap<String, FieldTypeWithHints>>() { + @Override + public void onLoaded(HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint) { + mAutofillDataBuilder = new ClientAutofillDataBuilder(fieldTypesByAutofillHint, parser); + ClientViewMetadataBuilder clientViewMetadataBuilder = + new ClientViewMetadataBuilder(parser, fieldTypesByAutofillHint); + mClientViewMetadata = clientViewMetadataBuilder.buildClientViewMetadata(); + String packageName = latestStructure.getActivityComponent().getPackageName(); + if (!mPackageVerificationRepository.putPackageSignatures(packageName)) { + callback.onFailure(getString(R.string.invalid_package_signature)); + return; + } + if (logVerboseEnabled()) { + logv("onSaveRequest(): clientState=%s", + bundleToString(request.getClientState())); + } + dumpStructure(latestStructure); + checkWebDomainAndBuildAutofillData(packageName, callback); + } + + @Override + public void onDataNotAvailable(String msg, Object... params) { + loge("Should not happen - could not find field types."); + } + }); } private void checkWebDomainAndBuildAutofillData(String packageName, SaveCallback callback) { diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/W3cHints.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/W3cHints.java index 1721477c..fd8e9457 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/W3cHints.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/W3cHints.java @@ -16,50 +16,6 @@ package com.example.android.autofill.service; public final class 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"; - 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"; - public static final String NEW_PASSWORD = "new-password"; - public static final String CURRENT_PASSWORD = "current-password"; - public static final String ORGANIZATION_TITLE = "organization-title"; - public static final String ORGANIZATION = "organization"; - public static final String STREET_ADDRESS = "street-address"; - public static final String ADDRESS_LINE1 = "address-line1"; - public static final String ADDRESS_LINE2 = "address-line2"; - public static final String ADDRESS_LINE3 = "address-line3"; - public static final String ADDRESS_LEVEL4 = "address-level4"; - public static final String ADDRESS_LEVEL3 = "address-level3"; - public static final String ADDRESS_LEVEL2 = "address-level2"; - public static final String ADDRESS_LEVEL1 = "address-level1"; - public static final String COUNTRY = "country"; - public static final String COUNTRY_NAME = "country-name"; - public static final String POSTAL_CODE = "postal-code"; - public static final String CC_NAME = "cc-name"; - public static final String CC_GIVEN_NAME = "cc-given-name"; - public static final String CC_ADDITIONAL_NAME = "cc-additional-name"; - public static final String CC_FAMILY_NAME = "cc-family-name"; - public static final String CC_NUMBER = "cc-number"; - public static final String CC_EXPIRATION = "cc-exp"; - public static final String CC_EXPIRATION_MONTH = "cc-exp-month"; - public static final String CC_EXPIRATION_YEAR = "cc-exp-year"; - public static final String CC_CSC = "cc-csc"; - public static final String CC_TYPE = "cc-type"; - public static final String TRANSACTION_CURRENCY = "transaction-currency"; - public static final String TRANSACTION_AMOUNT = "transaction-amount"; - public static final String LANGUAGE = "language"; - public static final String BDAY = "bday"; - public static final String BDAY_DAY = "bday-day"; - public static final String BDAY_MONTH = "bday-month"; - public static final String BDAY_YEAR = "bday-year"; - 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"; diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientAutofillDataBuilder.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientAutofillDataBuilder.java index 09c685e9..0ee922f3 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientAutofillDataBuilder.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientAutofillDataBuilder.java @@ -17,7 +17,6 @@ package com.example.android.autofill.service.data; import android.app.assist.AssistStructure; -import android.os.Bundle; import android.support.annotation.NonNull; import android.view.View; import android.view.autofill.AutofillValue; @@ -25,82 +24,42 @@ import android.view.autofill.AutofillValue; import com.example.android.autofill.service.AutofillHints; import com.example.android.autofill.service.ClientParser; import com.example.android.autofill.service.model.AutofillDataset; +import com.example.android.autofill.service.model.AutofillHint; import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields; +import com.example.android.autofill.service.model.FieldType; +import com.example.android.autofill.service.model.FieldTypeWithHints; import com.example.android.autofill.service.model.FilledAutofillField; -import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; -import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.UUID; import javax.annotation.Nullable; -import static com.example.android.autofill.service.AutofillHints.convertToStoredHintNames; import static com.example.android.autofill.service.util.Util.loge; public class ClientAutofillDataBuilder implements AutofillDataBuilder { private final ClientParser mClientParser; - private final Bundle mClientState; + private final HashMap<String, FieldTypeWithHints> mFieldTypesByAutofillHint; - private AssistStructure.ViewNode usernameNode; - private AssistStructure.ViewNode passwordNode; - - public ClientAutofillDataBuilder(ClientParser clientParser, Bundle clientState) { + public ClientAutofillDataBuilder(HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint, + ClientParser clientParser) { mClientParser = clientParser; - mClientState = clientState; + mFieldTypesByAutofillHint = fieldTypesByAutofillHint; } @Override public List<DatasetWithFilledAutofillFields> buildDatasetsByPartition(int datasetNumber) { ImmutableList.Builder<DatasetWithFilledAutofillFields> listBuilder = new ImmutableList.Builder<>(); -// if (mClientState != null) { -// mClientState.setClassLoader(ClientViewMetadata.class.getClassLoader()); -// ArrayList<ClientViewMetadata> clientViewMetadataList = mClientState.getParcelableArrayList( -// ResponseAdapter.CLIENT_STATES_KEY); -// if (clientViewMetadataList != null && clientViewMetadataList.size() == 2) { -// ClientViewMetadata usernameMetadata = clientViewMetadataList.get(0); -// ClientViewMetadata passwordMetadata = clientViewMetadataList.get(1); -// boolean possibleMultiPage = -// usernameMetadata.getMultiPageMetadata().isPartOfMultiPage() && -// passwordMetadata.getMultiPageMetadata().isPartOfMultiPage(); -// AutofillId usernameId = usernameMetadata.getMultiPageMetadata().getUsernameId(); -// AutofillId passwordId = passwordMetadata.getMultiPageMetadata().getPasswordId(); -// if (possibleMultiPage && usernameId != null && passwordId != null) { -// mClientParser.parse((node) -> { -// if (usernameId.equals(node.getAutofillId())) { -// usernameNode = node; -// } else if (passwordId.equals(node.getAutofillId())) { -// passwordNode = node; -// } -// }); -// String username = null, password = null; -// if (usernameNode != null && usernameNode.getAutofillValue() != null) { -// username = usernameNode.getAutofillValue().getTextValue().toString(); -// } -// if (passwordNode != null && passwordNode.getAutofillValue() != null) { -// password = passwordNode.getAutofillValue().getTextValue().toString(); -// } -// -// if (username != null && password != null) { -// logd("user: %s, pass: %s", username, password); -// // TODO: save it -// } else { -// logw(" missing user (%s) or pass (%s)", username, password); -// } -// } -// } -// } - - for (int partition : AutofillHints.PARTITIONS) { AutofillDataset autofillDataset = new AutofillDataset(UUID.randomUUID().toString(), "dataset-" + datasetNumber + "." + partition); - DatasetWithFilledAutofillFields datasetWithFilledAutofillFields = + DatasetWithFilledAutofillFields dataset = buildDatasetForPartition(autofillDataset, partition); - if (datasetWithFilledAutofillFields != null) { - listBuilder.add(datasetWithFilledAutofillFields); + if (dataset != null && dataset.filledAutofillFields != null) { + listBuilder.add(dataset); } } return listBuilder.build(); @@ -118,21 +77,14 @@ public class ClientAutofillDataBuilder implements AutofillDataBuilder { mClientParser.parse((node) -> parseAutofillFields(node, datasetWithFilledAutofillFields, partition) ); - if (datasetWithFilledAutofillFields.filledAutofillFields == null) { - return null; - } else { - return datasetWithFilledAutofillFields; - } + return datasetWithFilledAutofillFields; + } private void parseAutofillFields(AssistStructure.ViewNode viewNode, DatasetWithFilledAutofillFields datasetWithFilledAutofillFields, int partition) { String[] hints = viewNode.getAutofillHints(); - if (hints == null) { - return; - } - List<String> filteredHints = convertToStoredHintNames(Arrays.asList(hints), partition); - if (filteredHints == null || filteredHints.size() == 0) { + if (hints == null || hints.length == 0) { return; } AutofillValue autofillValue = viewNode.getAutofillValue(); @@ -156,44 +108,49 @@ public class ClientAutofillDataBuilder implements AutofillDataBuilder { } } appendViewMetadata(datasetWithFilledAutofillFields, - filteredHints, textValue, dateValue, toggleValue, + hints, partition, textValue, dateValue, toggleValue, autofillOptions, listIndex); } private void appendViewMetadata(@NonNull DatasetWithFilledAutofillFields - datasetWithFilledAutofillFields, @NonNull List<String> hints, + datasetWithFilledAutofillFields, @NonNull String[] hints, int partition, @Nullable String textValue, @Nullable Long dateValue, @Nullable Boolean toggleValue, @Nullable CharSequence[] autofillOptions, @Nullable Integer listIndex) { - for (int i = 0; i < hints.size(); i++) { - String hint = hints.get(i); + for (int i = 0; i < hints.length; i++) { + String hint = hints[i]; // Then check if the "actual" hint is supported. - if (AutofillHints.isValidHint(hint)) { - // Only add the field if the hint is supported by the type. - if (textValue != null) { - Preconditions.checkArgument(AutofillHints.isValidTypeForHints(hint, - View.AUTOFILL_TYPE_TEXT), - "Text is invalid type for hint '%s'", hint); + FieldTypeWithHints fieldTypeWithHints = mFieldTypesByAutofillHint.get(hint); + if (fieldTypeWithHints != null) { + FieldType fieldType = fieldTypeWithHints.fieldType; + if (!AutofillHints.matchesPartition(fieldType.getPartition(), partition)) { + continue; } + // Only add the field if the hint is supported by the type. + if (textValue != null) { + if (!fieldType.getAutofillTypes().ints.contains(View.AUTOFILL_TYPE_TEXT)) { + loge("Text is invalid type for hint '%s'", hint); + } + } if (autofillOptions != null && listIndex != null && autofillOptions.length > listIndex) { - Preconditions.checkArgument(AutofillHints.isValidTypeForHints(hint, - View.AUTOFILL_TYPE_LIST), - "List is invalid type for hint '%s'", hint); + if (!fieldType.getAutofillTypes().ints.contains(View.AUTOFILL_TYPE_LIST)) { + loge("List is invalid type for hint '%s'", hint); + } textValue = autofillOptions[listIndex].toString(); } if (dateValue != null) { - Preconditions.checkArgument(AutofillHints.isValidTypeForHints(hint, - View.AUTOFILL_TYPE_DATE), - "Date is invalid type for hint '%s'", hint); + if (!fieldType.getAutofillTypes().ints.contains(View.AUTOFILL_TYPE_DATE)) { + loge("Date is invalid type for hint '%s'", hint); + } } if (toggleValue != null) { - Preconditions.checkArgument(AutofillHints.isValidTypeForHints(hint, - View.AUTOFILL_TYPE_TOGGLE), - "Toggle is invalid type for hint '%s'", hint); + if (!fieldType.getAutofillTypes().ints.contains(View.AUTOFILL_TYPE_TOGGLE)) { + loge("Toggle is invalid type for hint '%s'", hint); + } } String datasetId = datasetWithFilledAutofillFields.autofillDataset.getId(); datasetWithFilledAutofillFields.add(new FilledAutofillField(datasetId, - hint, textValue, dateValue, toggleValue)); + fieldType.getTypeName(), textValue, dateValue, toggleValue)); } else { loge("Invalid hint: %s", hint); } diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadataBuilder.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadataBuilder.java index 0c54c020..71f931bd 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadataBuilder.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/ClientViewMetadataBuilder.java @@ -23,17 +23,23 @@ import android.view.autofill.AutofillId; import com.example.android.autofill.service.AutofillHints; import com.example.android.autofill.service.ClientParser; +import com.example.android.autofill.service.model.FieldType; +import com.example.android.autofill.service.model.FieldTypeWithHints; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import static com.example.android.autofill.service.util.Util.logd; public class ClientViewMetadataBuilder { private ClientParser mClientParser; + private HashMap<String, FieldTypeWithHints> mFieldTypesByAutofillHint; - public ClientViewMetadataBuilder(ClientParser parser) { + public ClientViewMetadataBuilder(ClientParser parser, + HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint) { mClientParser = parser; + mFieldTypesByAutofillHint = fieldTypesByAutofillHint; } public ClientViewMetadata buildClientViewMetadata() { @@ -68,9 +74,10 @@ public class ClientViewMetadataBuilder { String[] hints = root.getAutofillHints(); if (hints != null) { for (String hint : hints) { - if (AutofillHints.isValidHint(hint)) { + FieldTypeWithHints fieldTypeWithHints = mFieldTypesByAutofillHint.get(hint); + if (fieldTypeWithHints != null && fieldTypeWithHints.fieldType != null) { allHints.add(hint); - autofillSaveType.value |= AutofillHints.getSaveTypeForHint(hint); + autofillSaveType.value |= fieldTypeWithHints.fieldType.getSaveInfo(); autofillIds.add(root.getAutofillId()); } } diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/FakeAutofillDataBuilder.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/FakeAutofillDataBuilder.java index 580df901..bbe1a74e 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/FakeAutofillDataBuilder.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/FakeAutofillDataBuilder.java @@ -17,8 +17,10 @@ package com.example.android.autofill.service.data; import com.example.android.autofill.service.AutofillHints; +import com.example.android.autofill.service.data.source.local.LocalAutofillDataSource; import com.example.android.autofill.service.model.AutofillDataset; import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields; +import com.example.android.autofill.service.model.FieldTypeWithHints; import com.example.android.autofill.service.model.FilledAutofillField; import com.google.common.collect.ImmutableList; @@ -26,9 +28,11 @@ import java.util.List; import java.util.UUID; public class FakeAutofillDataBuilder implements AutofillDataBuilder { + private final List<FieldTypeWithHints> mFieldTypesWithHints; private final int mSeed; - public FakeAutofillDataBuilder(int seed) { + public FakeAutofillDataBuilder(List<FieldTypeWithHints> fieldTypesWithHints, int seed) { + mFieldTypesWithHints = fieldTypesWithHints; mSeed = seed; } @@ -41,7 +45,11 @@ public class FakeAutofillDataBuilder implements AutofillDataBuilder { "dataset-" + datasetNumber + "." + partition); DatasetWithFilledAutofillFields datasetWithFilledAutofillFields = buildCollectionForPartition(autofillDataset, partition); - listBuilder.add(datasetWithFilledAutofillFields); + if (datasetWithFilledAutofillFields != null && + datasetWithFilledAutofillFields.filledAutofillFields != null && + !datasetWithFilledAutofillFields.filledAutofillFields.isEmpty()) { + listBuilder.add(datasetWithFilledAutofillFields); + } } return listBuilder.build(); } @@ -51,10 +59,11 @@ public class FakeAutofillDataBuilder implements AutofillDataBuilder { DatasetWithFilledAutofillFields datasetWithFilledAutofillFields = new DatasetWithFilledAutofillFields(); datasetWithFilledAutofillFields.autofillDataset = dataset; - for (String hint : AutofillHints.getHints()) { - if (AutofillHints.matchesPartition(hint, partition)) { - FilledAutofillField fakeField = AutofillHints.generateFakeField(hint, mSeed, - dataset.getId()); + for (FieldTypeWithHints fieldTypeWithHints: mFieldTypesWithHints) { + if (AutofillHints.matchesPartition(fieldTypeWithHints.getFieldType().getPartition(), + partition)) { + FilledAutofillField fakeField = + AutofillHints.generateFakeField(fieldTypeWithHints, mSeed, dataset.getId()); datasetWithFilledAutofillFields.add(fakeField); } } diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/DatasetAdapter.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/DatasetAdapter.java index 8f0cf714..7ad5ab3e 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/DatasetAdapter.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/DatasetAdapter.java @@ -28,9 +28,12 @@ import android.widget.RemoteViews; import com.example.android.autofill.service.AutofillHints; import com.example.android.autofill.service.ClientParser; import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields; +import com.example.android.autofill.service.model.FieldType; +import com.example.android.autofill.service.model.FieldTypeWithHints; import com.example.android.autofill.service.model.FilledAutofillField; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -50,22 +53,26 @@ public class DatasetAdapter { /** * Wraps autofill data in a {@link Dataset} object which can then be sent back to the client. */ - public Dataset buildDataset(DatasetWithFilledAutofillFields datasetWithFilledAutofillFields, + public Dataset buildDataset(HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint, + DatasetWithFilledAutofillFields datasetWithFilledAutofillFields, RemoteViews remoteViews) { - return buildDataset(datasetWithFilledAutofillFields, remoteViews, null); + return buildDataset(fieldTypesByAutofillHint, datasetWithFilledAutofillFields, remoteViews, + null); } /** * Wraps autofill data in a {@link Dataset} object with an IntentSender, which can then be * sent back to the client. */ - public Dataset buildDataset(DatasetWithFilledAutofillFields datasetWithFilledAutofillFields, + public Dataset buildDataset(HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint, + DatasetWithFilledAutofillFields datasetWithFilledAutofillFields, RemoteViews remoteViews, IntentSender intentSender) { Dataset.Builder datasetBuilder = new Dataset.Builder(remoteViews); if (intentSender != null) { datasetBuilder.setAuthentication(intentSender); } - boolean setAtLeastOneValue = bindDataset(datasetWithFilledAutofillFields, datasetBuilder); + boolean setAtLeastOneValue = bindDataset(fieldTypesByAutofillHint, + datasetWithFilledAutofillFields, datasetBuilder); if (!setAtLeastOneValue) { return null; } @@ -75,30 +82,35 @@ public class DatasetAdapter { /** * Build an autofill {@link Dataset} using saved data and the client's AssistStructure. */ - private boolean bindDataset(DatasetWithFilledAutofillFields datasetWithFilledAutofillFields, + private boolean bindDataset(HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint, + DatasetWithFilledAutofillFields datasetWithFilledAutofillFields, Dataset.Builder datasetBuilder) { MutableBoolean setValueAtLeastOnce = new MutableBoolean(false); - Map<String, FilledAutofillField> map = datasetWithFilledAutofillFields.filledAutofillFields - .stream().collect(toMap(FilledAutofillField::getHint, Function.identity())); + Map<String, FilledAutofillField> filledAutofillFieldsByTypeName = + datasetWithFilledAutofillFields.filledAutofillFields.stream() + .collect(toMap(FilledAutofillField::getFieldTypeName, Function.identity())); mClientParser.parse((node) -> - parseAutofillFields(node, map, datasetBuilder, setValueAtLeastOnce) + parseAutofillFields(node, fieldTypesByAutofillHint, filledAutofillFieldsByTypeName, + datasetBuilder, setValueAtLeastOnce) ); return setValueAtLeastOnce.value; } private void parseAutofillFields(AssistStructure.ViewNode viewNode, - Map<String, FilledAutofillField> map, Dataset.Builder builder, - MutableBoolean setValueAtLeastOnce) { + HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint, + Map<String, FilledAutofillField> filledAutofillFieldsByTypeName, + Dataset.Builder builder, MutableBoolean setValueAtLeastOnce) { String[] rawHints = viewNode.getAutofillHints(); if (rawHints == null || rawHints.length == 0) { logv("No af hints at ViewNode - %s", viewNode.getIdEntry()); return; } - List<String> hints = AutofillHints.convertToStoredHintNames(Arrays.asList(rawHints)); - // For simplicity, even if the viewNode has multiple autofill hints, only look at the first - // one. - String autofillHint = hints.get(0); - FilledAutofillField field = map.get(autofillHint); + String fieldTypeName = AutofillHints.getFieldTypeNameFromAutofillHints( + fieldTypesByAutofillHint, Arrays.asList(rawHints)); + if (fieldTypeName == null) { + return; + } + FilledAutofillField field = filledAutofillFieldsByTypeName.get(fieldTypeName); if (field == null) { return; } diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/ResponseAdapter.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/ResponseAdapter.java index 967d0ba9..bffd7cb1 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/ResponseAdapter.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/adapter/ResponseAdapter.java @@ -28,7 +28,9 @@ import com.example.android.autofill.service.AuthActivity; import com.example.android.autofill.service.RemoteViewsHelper; import com.example.android.autofill.service.data.ClientViewMetadata; import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields; +import com.example.android.autofill.service.model.FieldTypeWithHints; +import java.util.HashMap; import java.util.List; public class ResponseAdapter { @@ -49,8 +51,8 @@ public class ResponseAdapter { * Wraps autofill data in a Response object (essentially a series of Datasets) which can then * be sent back to the client View. */ - public FillResponse buildResponse(List<DatasetWithFilledAutofillFields> datasets, - boolean datasetAuth) { + public FillResponse buildResponse(HashMap<String, FieldTypeWithHints> fieldTypesByAutofillHint, + List<DatasetWithFilledAutofillFields> datasets, boolean datasetAuth) { FillResponse.Builder responseBuilder = new FillResponse.Builder(); if (datasets != null) { for (DatasetWithFilledAutofillFields datasetWithFilledAutofillFields : datasets) { @@ -63,13 +65,13 @@ public class ResponseAdapter { mContext, datasetName); RemoteViews remoteViews = RemoteViewsHelper.viewsWithAuth( mPackageName, datasetName); - dataset = mDatasetAdapter.buildDataset(datasetWithFilledAutofillFields, - remoteViews, intentSender); + dataset = mDatasetAdapter.buildDataset(fieldTypesByAutofillHint, + datasetWithFilledAutofillFields, remoteViews, intentSender); } else { RemoteViews remoteViews = RemoteViewsHelper.viewsWithNoAuth( mPackageName, datasetName); - dataset = mDatasetAdapter.buildDataset(datasetWithFilledAutofillFields, - remoteViews); + dataset = mDatasetAdapter.buildDataset(fieldTypesByAutofillHint, + datasetWithFilledAutofillFields, remoteViews); } if (dataset != null) { responseBuilder.addDataset(dataset); diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/AutofillDataSource.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/AutofillDataSource.java index 31b30b44..eb2a5ada 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/AutofillDataSource.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/AutofillDataSource.java @@ -17,7 +17,9 @@ package com.example.android.autofill.service.data.source; import com.example.android.autofill.service.data.DataCallback; import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields; +import com.example.android.autofill.service.model.FieldTypeWithHints; +import java.util.HashMap; import java.util.List; public interface AutofillDataSource { @@ -44,6 +46,14 @@ public interface AutofillDataSource { datasetsWithFilledAutofillFields); /** + * Gets all autofill field types. + */ + void getFieldTypes(DataCallback<List<FieldTypeWithHints>> fieldTypesCallback); + + void getFieldTypeByAutofillHints( + DataCallback<HashMap<String, FieldTypeWithHints>> fieldTypeMapCallback); + + /** * Clears all data. */ void clear(); diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DefaultFieldTypesSource.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DefaultFieldTypesSource.java new file mode 100644 index 00000000..22cbeadc --- /dev/null +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/DefaultFieldTypesSource.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2018 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.service.data.source; + +import com.example.android.autofill.service.model.DefaultFieldTypeWithHints; + +import java.util.List; + +public interface DefaultFieldTypesSource { + List<DefaultFieldTypeWithHints> getDefaultFieldTypes(); +} diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/DefaultFieldTypesLocalJsonSource.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/DefaultFieldTypesLocalJsonSource.java new file mode 100644 index 00000000..edda7d8e --- /dev/null +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/DefaultFieldTypesLocalJsonSource.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 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.service.data.source.local; + +import android.content.res.Resources; + +import com.example.android.autofill.service.R; +import com.example.android.autofill.service.data.source.DefaultFieldTypesSource; +import com.example.android.autofill.service.model.DefaultFieldTypeWithHints; +import com.example.android.autofill.service.model.FieldType; +import com.example.android.autofill.service.model.FieldTypeWithHints; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.lang.reflect.Type; +import java.util.List; + +import static com.example.android.autofill.service.util.Util.loge; + +public class DefaultFieldTypesLocalJsonSource implements DefaultFieldTypesSource { + private static DefaultFieldTypesLocalJsonSource sInstance; + + private final Resources mResources; + private final Gson mGson; + + private DefaultFieldTypesLocalJsonSource(Resources resources, Gson gson) { + mResources = resources; + mGson = gson; + } + + public static DefaultFieldTypesLocalJsonSource getInstance(Resources resources, Gson gson) { + if (sInstance == null) { + sInstance = new DefaultFieldTypesLocalJsonSource(resources, gson); + } + return sInstance; + } + + @Override + public List<DefaultFieldTypeWithHints> getDefaultFieldTypes() { + Type fieldTypeListType = TypeToken.getParameterized(List.class, + DefaultFieldTypeWithHints.class).getType(); + InputStream is = mResources.openRawResource(R.raw.default_field_types); + List<DefaultFieldTypeWithHints> fieldTypes = null; + try(Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) { + fieldTypes = mGson.fromJson(reader, fieldTypeListType); + } catch (IOException e) { + loge(e, "Exception during deserialization of FieldTypes."); + } + return fieldTypes; + } +} diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/LocalAutofillDataSource.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/LocalAutofillDataSource.java index 758b5123..c9b80958 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/LocalAutofillDataSource.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/LocalAutofillDataSource.java @@ -24,11 +24,16 @@ import com.example.android.autofill.service.data.DataCallback; import com.example.android.autofill.service.data.source.AutofillDataSource; import com.example.android.autofill.service.data.source.local.dao.AutofillDao; import com.example.android.autofill.service.model.AutofillDataset; +import com.example.android.autofill.service.model.AutofillHint; import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields; +import com.example.android.autofill.service.model.FieldType; +import com.example.android.autofill.service.model.FieldTypeWithHints; import com.example.android.autofill.service.model.FilledAutofillField; import com.example.android.autofill.service.util.AppExecutors; +import java.util.HashMap; import java.util.List; +import java.util.stream.Collectors; import static com.example.android.autofill.service.util.Util.logw; @@ -71,11 +76,14 @@ public class LocalAutofillDataSource implements AutofillDataSource { @Override public void getAutofillDatasets(List<String> allAutofillHints, DataCallback<List<DatasetWithFilledAutofillFields>> datasetsCallback) { - final List<String> storedAllAutofillHints = - AutofillHints.convertToStoredHintNames(allAutofillHints); mAppExecutors.diskIO().execute(() -> { - List<DatasetWithFilledAutofillFields> datasetsWithFilledAutofillFields = mAutofillDao - .getDatasets(storedAllAutofillHints); + final List<String> typeNames = getFieldTypesForAutofillHints(allAutofillHints) + .stream() + .map(FieldTypeWithHints::getFieldType) + .map(FieldType::getTypeName) + .collect(Collectors.toList()); + List<DatasetWithFilledAutofillFields> datasetsWithFilledAutofillFields = + mAutofillDao.getDatasets(typeNames); mAppExecutors.mainThread().execute(() -> datasetsCallback.onLoaded(datasetsWithFilledAutofillFields) ); @@ -122,6 +130,51 @@ public class LocalAutofillDataSource implements AutofillDataSource { } @Override + public void getFieldTypes(DataCallback<List<FieldTypeWithHints>> fieldTypesCallback) { + mAppExecutors.diskIO().execute(() -> { + List<FieldTypeWithHints> fieldTypeWithHints = mAutofillDao.getFieldTypesWithHints(); + if (fieldTypeWithHints != null) { + fieldTypesCallback.onLoaded(fieldTypeWithHints); + } else { + fieldTypesCallback.onDataNotAvailable("Field Types not found."); + } + }); + } + + @Override + public void getFieldTypeByAutofillHints( + DataCallback<HashMap<String, FieldTypeWithHints>> fieldTypeMapCallback) { + mAppExecutors.diskIO().execute(() -> { + HashMap<String, FieldTypeWithHints> hintMap = getFieldTypeByAutofillHints(); + if (hintMap != null) { + fieldTypeMapCallback.onLoaded(hintMap); + } else { + fieldTypeMapCallback.onDataNotAvailable("FieldTypes not found"); + } + }); + } + + private HashMap<String, FieldTypeWithHints> getFieldTypeByAutofillHints() { + HashMap<String, FieldTypeWithHints> hintMap = new HashMap<>(); + List<FieldTypeWithHints> fieldTypeWithHints = + mAutofillDao.getFieldTypesWithHints(); + if (fieldTypeWithHints != null) { + for (FieldTypeWithHints fieldType : fieldTypeWithHints) { + for (AutofillHint hint : fieldType.autofillHints) { + hintMap.put(hint.mAutofillHint, fieldType); + } + } + return hintMap; + } else { + return null; + } + } + + private List<FieldTypeWithHints> getFieldTypesForAutofillHints(List<String> autofillHints) { + return mAutofillDao.getFieldTypesForAutofillHints(autofillHints); + } + + @Override public void clear() { mAppExecutors.diskIO().execute(() -> { mAutofillDao.clearAll(); diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/dao/AutofillDao.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/dao/AutofillDao.java index 385638b0..9baffb46 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/dao/AutofillDao.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/dao/AutofillDao.java @@ -22,7 +22,10 @@ import android.arch.persistence.room.OnConflictStrategy; import android.arch.persistence.room.Query; import com.example.android.autofill.service.model.AutofillDataset; +import com.example.android.autofill.service.model.AutofillHint; import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields; +import com.example.android.autofill.service.model.FieldType; +import com.example.android.autofill.service.model.FieldTypeWithHints; import com.example.android.autofill.service.model.FilledAutofillField; import java.util.Collection; @@ -38,7 +41,7 @@ public interface AutofillDao { */ @Query("SELECT DISTINCT id, datasetName FROM FilledAutofillField, AutofillDataset" + " WHERE AutofillDataset.id = FilledAutofillField.datasetId" + - " AND FilledAutofillField.hint IN (:allAutofillHints)") + " AND FilledAutofillField.fieldTypeName IN (:allAutofillHints)") List<DatasetWithFilledAutofillFields> getDatasets(List<String> allAutofillHints); /** @@ -50,13 +53,22 @@ public interface AutofillDao { * all of the views on the page. * @param datasetName Filtering parameter; only return datasets with this name. */ - @Query("SELECT DISTINCT id, datasetname FROM FilledAutofillField, AutofillDataset" + + @Query("SELECT DISTINCT id, datasetName FROM FilledAutofillField, AutofillDataset" + " WHERE AutofillDataset.id = FilledAutofillField.datasetId" + " AND AutofillDataset.datasetName = (:datasetName)" + - " AND FilledAutofillField.hint IN (:allAutofillHints)") + " AND FilledAutofillField.fieldTypeName IN (:allAutofillHints)") List<DatasetWithFilledAutofillFields> getDatasetsWithName( List<String> allAutofillHints, String datasetName); + @Query("SELECT DISTINCT typeName, autofillTypes, saveInfo, partition, strictExampleSet, textTemplate, dateTemplate FROM FieldType, AutofillHint WHERE " + + "FieldType.typeName = AutofillHint.fieldTypeName") + List<FieldTypeWithHints> getFieldTypesWithHints(); + + @Query("SELECT DISTINCT typeName, autofillTypes, saveInfo, partition, strictExampleSet, textTemplate, dateTemplate FROM FieldType, AutofillHint WHERE " + + "FieldType.typeName = AutofillHint.fieldTypeName " + + "AND AutofillHint.autofillHint IN (:autofillHints)") + List<FieldTypeWithHints> getFieldTypesForAutofillHints(List<String> autofillHints); + /** * @param autofillFields Collection of autofill fields to be saved to the db. */ @@ -66,6 +78,12 @@ public interface AutofillDao { @Insert(onConflict = OnConflictStrategy.REPLACE) void saveAutofillDataset(AutofillDataset datasets); + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertAutofillHints(List<AutofillHint> autofillHints); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertFieldTypes(List<FieldType> fieldTypes); + @Query("DELETE FROM AutofillDataset") void clearAll(); }
\ No newline at end of file diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/db/AutofillDatabase.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/db/AutofillDatabase.java index 83eda9e6..178e375d 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/db/AutofillDatabase.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/db/AutofillDatabase.java @@ -16,32 +16,97 @@ package com.example.android.autofill.service.data.source.local.db; +import android.arch.persistence.db.SupportSQLiteDatabase; import android.arch.persistence.room.Database; import android.arch.persistence.room.Room; import android.arch.persistence.room.RoomDatabase; +import android.arch.persistence.room.TypeConverters; import android.content.Context; +import android.support.annotation.NonNull; +import com.example.android.autofill.service.data.source.DefaultFieldTypesSource; import com.example.android.autofill.service.data.source.local.dao.AutofillDao; import com.example.android.autofill.service.model.AutofillDataset; +import com.example.android.autofill.service.model.AutofillHint; +import com.example.android.autofill.service.model.DefaultFieldTypeWithHints; +import com.example.android.autofill.service.model.FakeData; +import com.example.android.autofill.service.model.FieldType; import com.example.android.autofill.service.model.FilledAutofillField; +import com.example.android.autofill.service.util.AppExecutors; -@Database(entities = {FilledAutofillField.class, AutofillDataset.class}, version = 1) +import java.util.ArrayList; +import java.util.List; + +import static com.example.android.autofill.service.data.source.local.db.Converters.IntList; +import static java.util.stream.Collectors.toList; + +@Database(entities = { + FilledAutofillField.class, + AutofillDataset.class, + FieldType.class, + AutofillHint.class +}, version = 1) +@TypeConverters({Converters.class}) public abstract class AutofillDatabase extends RoomDatabase { private static final Object sLock = new Object(); private static AutofillDatabase sInstance; - public static AutofillDatabase getInstance(Context context) { - synchronized (sLock) { - if (sInstance == null) { - sInstance = Room.databaseBuilder(context.getApplicationContext(), - AutofillDatabase.class, "AutofillSample.db") - .build(); + public static AutofillDatabase getInstance(Context context, + DefaultFieldTypesSource defaultFieldTypesSource, + AppExecutors appExecutors) { + if (sInstance == null) { + synchronized (sLock) { + if (sInstance == null) { + sInstance = Room.databaseBuilder(context.getApplicationContext(), + AutofillDatabase.class, "AutofillSample.db") + .addCallback(new RoomDatabase.Callback() { + @Override + public void onCreate(@NonNull SupportSQLiteDatabase db) { + appExecutors.diskIO().execute(() -> { + List<DefaultFieldTypeWithHints> fieldTypes = + defaultFieldTypesSource.getDefaultFieldTypes(); + AutofillDatabase autofillDatabase = + getInstance(context, defaultFieldTypesSource, + appExecutors); + autofillDatabase.saveDefaultFieldTypes(fieldTypes); + }); + } + + @Override + public void onOpen(@NonNull SupportSQLiteDatabase db) { + super.onOpen(db); + } + }) + .build(); + } } - return sInstance; } + return sInstance; } - public abstract AutofillDao autofillDao(); + private void saveDefaultFieldTypes(List<DefaultFieldTypeWithHints> defaultFieldTypes) { + List<FieldType> storedFieldTypes = new ArrayList<>(); + List<AutofillHint> storedAutofillHints = new ArrayList<>(); + for (DefaultFieldTypeWithHints defaultType : defaultFieldTypes) { + DefaultFieldTypeWithHints.DefaultFieldType defaultFieldType = defaultType.fieldType; + List<String> autofillHints = defaultType.autofillHints; + IntList autofillTypes = new IntList(defaultFieldType.autofillTypes); + DefaultFieldTypeWithHints.DefaultFakeData defaultFakeData = defaultType.fieldType.fakeData; + FakeData fakeData = new FakeData(new Converters.StringList( + defaultFakeData.strictExampleSet), defaultFakeData.textTemplate, + defaultFakeData.dateTemplate); + FieldType storedFieldType = new FieldType(defaultFieldType.typeName, autofillTypes, + defaultFieldType.saveInfo, defaultFieldType.partition, fakeData); + storedFieldTypes.add(storedFieldType); + storedAutofillHints.addAll(autofillHints.stream() + .map((autofillHint) -> new AutofillHint(autofillHint, + storedFieldType.getTypeName())).collect(toList())); + } + AutofillDao autofillDao = autofillDao(); + autofillDao.insertFieldTypes(storedFieldTypes); + autofillDao.insertAutofillHints(storedAutofillHints); + } + public abstract AutofillDao autofillDao(); }
\ No newline at end of file diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/db/Converters.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/db/Converters.java new file mode 100644 index 00000000..2829f8bd --- /dev/null +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/data/source/local/db/Converters.java @@ -0,0 +1,100 @@ +/* + * 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.service.data.source.local.db; + +import android.arch.persistence.room.TypeConverter; + +import java.util.Arrays; +import java.util.List; + +import static java.util.stream.Collectors.toList; + +/** + * Type converter for Room database. + */ +public class Converters { + + /** + * If database returns a {@link String} containing a comma delimited list of ints, this converts + * the {@link String} to an {@link IntList}. + */ + @TypeConverter + public static IntList storedStringToIntList(String value) { + List<String> strings = Arrays.asList(value.split("\\s*,\\s*")); + List<Integer> ints = strings.stream().map(Integer::parseInt).collect(toList()); + return new IntList(ints); + } + + /** + * Converts the {@link IntList} back into a String containing a comma delimited list of + * ints. + */ + @TypeConverter + public static String intListToStoredString(IntList list) { + StringBuilder stringBuilder = new StringBuilder(); + for (Integer integer : list.ints) { + stringBuilder.append(integer).append(","); + } + return stringBuilder.toString(); + } + + /** + * If database returns a {@link String} containing a comma delimited list of Strings, this + * converts the {@link String} to a {@link StringList}. + */ + @TypeConverter + public static StringList storedStringToStringList(String value) { + List<String> strings = Arrays.asList(value.split("\\s*,\\s*")); + return new StringList(strings); + } + + + /** + * Converts the {@link StringList} back into a {@link String} containing a comma delimited + * list of {@link String}s. + */ + @TypeConverter + public static String stringListToStoredString(StringList list) { + StringBuilder stringBuilder = new StringBuilder(); + for (String string : list.strings) { + stringBuilder.append(string).append(","); + } + return stringBuilder.toString(); + } + + /** + * Wrapper class for {@code List<Integer>} so it can work with Room type converters. + */ + public static class IntList { + public final List<Integer> ints; + + public IntList(List<Integer> ints) { + this.ints = ints; + } + } + + /** + * Wrapper class for {@code List<String>} so it can work with Room type converters. + */ + public static class StringList { + public final List<String> strings; + + public StringList(List<String> ints) { + this.strings = ints; + } + } +} diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/AutofillHint.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/AutofillHint.java new file mode 100644 index 00000000..be4aa7d9 --- /dev/null +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/AutofillHint.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 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.service.model; + +import android.arch.persistence.room.ColumnInfo; +import android.arch.persistence.room.Entity; +import android.arch.persistence.room.ForeignKey; +import android.support.annotation.NonNull; + +@Entity(primaryKeys = {"autofillHint"}, foreignKeys = @ForeignKey( + entity = FieldType.class, parentColumns = "typeName", childColumns = "fieldTypeName", + onDelete = ForeignKey.CASCADE)) +public class AutofillHint { + + @NonNull + @ColumnInfo(name = "autofillHint") + public String mAutofillHint; + + @NonNull + @ColumnInfo(name = "fieldTypeName") + public String mFieldTypeName; + + public AutofillHint(@NonNull String autofillHint, @NonNull String fieldTypeName) { + this.mAutofillHint = autofillHint; + this.mFieldTypeName = fieldTypeName; + } +} diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DefaultFieldTypeWithHints.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DefaultFieldTypeWithHints.java new file mode 100644 index 00000000..70ad382e --- /dev/null +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/DefaultFieldTypeWithHints.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2018 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.service.model; + +import java.util.List; + +/** + * JSON model class, representing an autofillable field type. It is called "Default" because only + * default field types will be included in the packaged JSON. After the JSON is initially read and + * written to the DB, the field types can be dynamically added, modified, and removed. + *<p> + * It contains all of the metadata about the field type. For example, if the field type is + * "country", this is the JSON object associated with it: + <pre class="prettyprint"> + { + "autofillHints": [ + "country" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "countryseed" + }, + "partition": 1, + "saveInfo": 2, + "typeName": "country" + } + } + </pre> + */ +public class DefaultFieldTypeWithHints { + public DefaultFieldType fieldType; + public List<String> autofillHints; + + public static class DefaultFieldType { + public String typeName; + public List<Integer> autofillTypes; + public int saveInfo; + public int partition; + public DefaultFakeData fakeData; + } + + public static class DefaultFakeData { + public List<String> strictExampleSet; + public String textTemplate; + public String dateTemplate; + + public DefaultFakeData(List<String> strictExampleSet, String textTemplate, + String dateTemplate) { + this.strictExampleSet = strictExampleSet; + this.textTemplate = textTemplate; + this.dateTemplate = dateTemplate; + } + } +} diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FakeData.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FakeData.java new file mode 100644 index 00000000..5d0837b2 --- /dev/null +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FakeData.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 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.service.model; + +import com.example.android.autofill.service.data.source.local.db.Converters; + +public class FakeData { + public Converters.StringList strictExampleSet; + public String textTemplate; + public String dateTemplate; + + public FakeData(Converters.StringList strictExampleSet, String textTemplate, String dateTemplate) { + this.strictExampleSet = strictExampleSet; + this.textTemplate = textTemplate; + this.dateTemplate = dateTemplate; + } +}
\ No newline at end of file diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FieldType.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FieldType.java new file mode 100644 index 00000000..4d285f34 --- /dev/null +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FieldType.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 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.service.model; + +import android.arch.persistence.room.ColumnInfo; +import android.arch.persistence.room.Embedded; +import android.arch.persistence.room.Entity; +import android.support.annotation.NonNull; + +import static com.example.android.autofill.service.data.source.local.db.Converters.IntList; + +@Entity(primaryKeys = {"typeName"}) +public class FieldType { + @NonNull + @ColumnInfo(name = "typeName") + private final String mTypeName; + + @NonNull + @ColumnInfo(name = "autofillTypes") + private final IntList mAutofillTypes; + + @NonNull + @ColumnInfo(name = "saveInfo") + private final Integer mSaveInfo; + + @NonNull + @ColumnInfo(name = "partition") + private final Integer mPartition; + + @NonNull + @Embedded + private final FakeData mFakeData; + + public FieldType(@NonNull String typeName, @NonNull IntList autofillTypes, + @NonNull Integer saveInfo, @NonNull Integer partition, @NonNull FakeData fakeData) { + mTypeName = typeName; + mAutofillTypes = autofillTypes; + mSaveInfo = saveInfo; + mPartition = partition; + mFakeData = fakeData; + } + + @NonNull + public String getTypeName() { + return mTypeName; + } + + @NonNull + public IntList getAutofillTypes() { + return mAutofillTypes; + } + + @NonNull + public Integer getSaveInfo() { + return mSaveInfo; + } + + @NonNull + public Integer getPartition() { + return mPartition; + } + + @NonNull + public FakeData getFakeData() { + return mFakeData; + } +}
\ No newline at end of file diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FieldTypeWithHints.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FieldTypeWithHints.java new file mode 100644 index 00000000..308a50b5 --- /dev/null +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FieldTypeWithHints.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 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.service.model; + +import android.arch.persistence.room.Embedded; +import android.arch.persistence.room.Relation; + +import java.util.List; + +public class FieldTypeWithHints { + @Embedded + public FieldType fieldType; + + @Relation(parentColumn = "typeName", entityColumn = "fieldTypeName", entity = AutofillHint.class) + public List<AutofillHint> autofillHints; + + public FieldType getFieldType() { + return fieldType; + } + + public List<AutofillHint> getAutofillHints() { + return autofillHints; + } +} diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FilledAutofillField.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FilledAutofillField.java index ba474d2e..5a71c15a 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FilledAutofillField.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/model/FilledAutofillField.java @@ -23,9 +23,12 @@ import android.support.annotation.NonNull; import javax.annotation.Nullable; -@Entity(primaryKeys = {"datasetId", "hint"}, foreignKeys = @ForeignKey( - entity = AutofillDataset.class, parentColumns = "id", childColumns = "datasetId", - onDelete = ForeignKey.CASCADE)) +@Entity(primaryKeys = {"datasetId", "fieldTypeName"}, foreignKeys = { + @ForeignKey(entity = AutofillDataset.class, parentColumns = "id", + childColumns = "datasetId", onDelete = ForeignKey.CASCADE), + @ForeignKey(entity = FieldType.class, parentColumns = "typeName", + childColumns = "fieldTypeName", onDelete = ForeignKey.CASCADE) +}) public class FilledAutofillField { @NonNull @@ -45,13 +48,13 @@ public class FilledAutofillField { private final Boolean mToggleValue; @NonNull - @ColumnInfo(name = "hint") - private final String mHint; + @ColumnInfo(name = "fieldTypeName") + private final String mFieldTypeName; - public FilledAutofillField(@NonNull String datasetId, @NonNull String hint, + public FilledAutofillField(@NonNull String datasetId, @NonNull String fieldTypeName, @Nullable String textValue, @Nullable Long dateValue, @Nullable Boolean toggleValue) { mDatasetId = datasetId; - mHint = hint; + mFieldTypeName = fieldTypeName; mTextValue = textValue; mDateValue = dateValue; mToggleValue = toggleValue; @@ -107,8 +110,8 @@ public class FilledAutofillField { } @NonNull - public String getHint() { - return mHint; + public String getFieldTypeName() { + return mFieldTypeName; } public boolean isNull() { diff --git a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/SettingsActivity.java b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/SettingsActivity.java index 82222a80..a45a99ff 100644 --- a/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/SettingsActivity.java +++ b/input/autofill/AutofillFramework/afservice/src/main/java/com/example/android/autofill/service/settings/SettingsActivity.java @@ -39,15 +39,20 @@ import android.widget.TextView; import com.example.android.autofill.service.R; import com.example.android.autofill.service.data.AutofillDataBuilder; +import com.example.android.autofill.service.data.DataCallback; import com.example.android.autofill.service.data.FakeAutofillDataBuilder; +import com.example.android.autofill.service.data.source.DefaultFieldTypesSource; import com.example.android.autofill.service.data.source.PackageVerificationDataSource; +import com.example.android.autofill.service.data.source.local.DefaultFieldTypesLocalJsonSource; import com.example.android.autofill.service.data.source.local.LocalAutofillDataSource; import com.example.android.autofill.service.data.source.local.SharedPrefsPackageVerificationRepository; import com.example.android.autofill.service.data.source.local.dao.AutofillDao; import com.example.android.autofill.service.data.source.local.db.AutofillDatabase; import com.example.android.autofill.service.model.DatasetWithFilledAutofillFields; +import com.example.android.autofill.service.model.FieldTypeWithHints; import com.example.android.autofill.service.util.AppExecutors; import com.example.android.autofill.service.util.Util; +import com.google.gson.GsonBuilder; import java.util.List; @@ -71,11 +76,16 @@ public class SettingsActivity extends AppCompatActivity { setContentView(R.layout.multidataset_service_settings_activity); SharedPreferences localAfDataSourceSharedPrefs = getSharedPreferences(LocalAutofillDataSource.SHARED_PREF_KEY, Context.MODE_PRIVATE); - AutofillDao autofillDao = AutofillDatabase.getInstance(this).autofillDao(); + DefaultFieldTypesSource defaultFieldTypesSource = + DefaultFieldTypesLocalJsonSource.getInstance(getResources(), + new GsonBuilder().create()); + AutofillDao autofillDao = AutofillDatabase.getInstance( + this, defaultFieldTypesSource, new AppExecutors()).autofillDao(); mLocalAutofillDataSource = LocalAutofillDataSource.getInstance(localAfDataSourceSharedPrefs, autofillDao, new AppExecutors()); mAutofillManager = getSystemService(AutofillManager.class); - mPackageVerificationDataSource = SharedPrefsPackageVerificationRepository.getInstance(this); + mPackageVerificationDataSource = + SharedPrefsPackageVerificationRepository.getInstance(this); mPreferences = MyPreferences.getInstance(this); setupSettingsSwitch(R.id.settings_auth_responses_container, R.id.settings_auth_responses_label, @@ -194,27 +204,39 @@ public class SettingsActivity extends AppCompatActivity { .setView(numberOfDatasetsPicker) .setPositiveButton(R.string.settings_ok, (dialog, which) -> { int numOfDatasets = numberOfDatasetsPicker.getValue(); - boolean success = buildAndSaveMockedAutofillFieldCollections(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(); - } + mLocalAutofillDataSource.getFieldTypes(new DataCallback<List<FieldTypeWithHints>>() { + @Override + public void onLoaded(List<FieldTypeWithHints> fieldTypes) { + boolean saved = buildAndSaveMockedAutofillFieldCollections( + fieldTypes, numOfDatasets); + dialog.dismiss(); + if (saved) { + Snackbar.make(findViewById(R.id.settings_layout), + getResources().getQuantityString( + R.plurals.settings_add_data_success, + numOfDatasets, numOfDatasets), + Snackbar.LENGTH_SHORT).show(); + } + } + + @Override + public void onDataNotAvailable(String msg, Object... params) { + + } + }); }) .create(); } - public boolean buildAndSaveMockedAutofillFieldCollections(int numOfDatasets) { + public boolean buildAndSaveMockedAutofillFieldCollections(List<FieldTypeWithHints> fieldTypes, + int numOfDatasets) { if (numOfDatasets < 0 || numOfDatasets > 10) { logw("Number of Datasets (%d) out of range.", numOfDatasets); - return false; } for (int i = 0; i < numOfDatasets; i++) { int datasetNumber = mLocalAutofillDataSource.getDatasetNumber(); - AutofillDataBuilder autofillDataBuilder = new FakeAutofillDataBuilder(datasetNumber); + AutofillDataBuilder autofillDataBuilder = + new FakeAutofillDataBuilder(fieldTypes, datasetNumber); List<DatasetWithFilledAutofillFields> datasetsWithFilledAutofillFields = autofillDataBuilder.buildDatasetsByPartition(datasetNumber); // Save datasets to database. 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 new file mode 100644 index 00000000..637edead --- /dev/null +++ b/input/autofill/AutofillFramework/afservice/src/main/res/raw/default_field_types @@ -0,0 +1,1165 @@ +[ + { + "autofillHints": [ + "country" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "countryseed" + }, + "partition": 1, + "saveInfo": 2, + "typeName": "country" + } + }, + { + "autofillHints": [ + "transaction-amount" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "seed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "transaction-amount" + } + }, + { + "autofillHints": [ + "cc-family-name" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "familynameseed" + }, + "partition": 3, + "saveInfo": 4, + "typeName": "cc-family-name" + } + }, + { + "autofillHints": [ + "postal-code", + "postalCode" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "1000seed" + }, + "partition": 1, + "saveInfo": 2, + "typeName": "postalCode" + } + }, + { + "autofillHints": [ + "language" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [ + "Bulgarian", + "Croatian", + "Czech", + "Danish", + "Dutch", + "English", + "Estonian" + ] + }, + "partition": 0, + "saveInfo": 0, + "typeName": "language" + } + }, + { + "autofillHints": [ + "tel-national" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "tel-nationalseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "tel-national" + } + }, + { + "autofillHints": [ + "transaction-currency" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [ + "USD", + "CAD", + "KYD", + "CRC" + ] + }, + "partition": 0, + "saveInfo": 0, + "typeName": "transaction-currency" + } + }, + { + "autofillHints": [ + "billing" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "billingseed" + }, + "partition": 1, + "saveInfo": 0, + "typeName": "billing" + } + }, + { + "autofillHints": [ + "emailAddress", + "email" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "emailAddressseed" + }, + "partition": 2, + "saveInfo": 16, + "typeName": "emailAddress" + } + }, + { + "autofillHints": [ + "password", + "current-password" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "usernameseed" + }, + "partition": 0, + "saveInfo": 1, + "typeName": "password" + } + }, + { + "autofillHints": [ + "honorific-suffix" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [ + "san", + "kun", + "chan", + "sama" + ] + }, + "partition": 0, + "saveInfo": 0, + "typeName": "honorific-suffix" + } + }, + { + "autofillHints": [ + "shipping" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "shippingseed" + }, + "partition": 1, + "saveInfo": 0, + "typeName": "shipping" + } + }, + { + "autofillHints": [ + "pager" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "pagerseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "pager" + } + }, + { + "autofillHints": [ + "impp" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "imppseed" + }, + "partition": 2, + "saveInfo": 16, + "typeName": "impp" + } + }, + { + "autofillHints": [ + "bday-month" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "dateTemplate": "curr_time", + "strictExampleSet": [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12" + ], + "textTemplate": "bday-monthseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "bday-month" + } + }, + { + "autofillHints": [ + "tel-local-prefix" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "tel-local-prefixseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "tel-local-prefix" + } + }, + { + "autofillHints": [ + "tel" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "telseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "tel" + } + }, + { + "autofillHints": [ + "fax" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "faxseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "fax" + } + }, + { + "autofillHints": [ + "honorific-prefix" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [ + "Miss", + "Ms.", + "Mr.", + "Mx.", + "Sr.", + "Dr.", + "Lady", + "Lord" + ] + }, + "partition": 0, + "saveInfo": 0, + "typeName": "honorific-prefix" + } + }, + { + "autofillHints": [ + "bday-year" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "dateTemplate": "curr_time", + "strictExampleSet": [] + }, + "partition": 0, + "saveInfo": 0, + "typeName": "bday-year" + } + }, + { + "autofillHints": [ + "creditCardExpirationMonth", + "cc-exp-month" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3, + 4 + ], + "fakeData": { + "dateTemplate": "curr_time", + "strictExampleSet": [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12" + ] + }, + "partition": 3, + "saveInfo": 4, + "typeName": "creditCardExpirationMonth" + } + }, + { + "autofillHints": [ + "work" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "workseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "work" + } + }, + { + "autofillHints": [ + "cc-csc", + "creditCardSecurityCode" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "seedseedseed" + }, + "partition": 3, + "saveInfo": 4, + "typeName": "creditCardSecurityCode" + } + }, + { + "autofillHints": [ + "cc-type" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "cc-typeseed" + }, + "partition": 3, + "saveInfo": 4, + "typeName": "cc-type" + } + }, + { + "autofillHints": [ + "bday-day" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "dateTemplate": "curr_time", + "strictExampleSet": [], + "textTemplate": "seed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "bday-day" + } + }, + { + "autofillHints": [ + "address-line2" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "Bldg. seed" + }, + "partition": 1, + "saveInfo": 2, + "typeName": "address-line2" + } + }, + { + "autofillHints": [ + "address-line1" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "seed Fake Ln." + }, + "partition": 1, + "saveInfo": 2, + "typeName": "address-line1" + } + }, + { + "autofillHints": [ + "postalAddress" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "seed Fake Ln, Fake, FA, FAA 10001" + }, + "partition": 1, + "saveInfo": 2, + "typeName": "postalAddress" + } + }, + { + "autofillHints": [ + "address-line3" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "Suite seed" + }, + "partition": 1, + "saveInfo": 2, + "typeName": "address-line3" + } + }, + { + "autofillHints": [ + "phone" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "seed2345678910" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "phone" + } + }, + { + "autofillHints": [ + "tel_extension" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "tel_extensionseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "tel_extension" + } + }, + { + "autofillHints": [ + "creditCardNumber", + "cc-number" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "seed234567" + }, + "partition": 3, + "saveInfo": 4, + "typeName": "creditCardNumber" + } + }, + { + "autofillHints": [ + "name" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "nameseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "name" + } + }, + { + "autofillHints": [ + "additional-name" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "additional-nameseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "additional-name" + } + }, + { + "autofillHints": [ + "tel-local" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "tel-localseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "tel-local" + } + }, + { + "autofillHints": [ + "bday" + ], + "fieldType": { + "autofillTypes": [ + 4 + ], + "fakeData": { + "dateTemplate": "curr_time", + "strictExampleSet": [] + }, + "partition": 0, + "saveInfo": 0, + "typeName": "bday" + } + }, + { + "autofillHints": [ + "street-address" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "street-addressseed" + }, + "partition": 1, + "saveInfo": 2, + "typeName": "street-address" + } + }, + { + "autofillHints": [ + "cc-given-name" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "cc-given-nameseed" + }, + "partition": 3, + "saveInfo": 4, + "typeName": "cc-given-name" + } + }, + { + "autofillHints": [ + "creditCardExpirationDate", + "cc-exp" + ], + "fieldType": { + "autofillTypes": [ + 4 + ], + "fakeData": { + "dateTemplate": "curr_time", + "strictExampleSet": [] + }, + "partition": 3, + "saveInfo": 4, + "typeName": "creditCardExpirationDate" + } + }, + { + "autofillHints": [ + "creditCardExpirationYear", + "cc-exp-year" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3, + 4 + ], + "fakeData": { + "dateTemplate": "curr_time", + "strictExampleSet": [], + "textTemplate": "creditCardExpirationYearseed" + }, + "partition": 3, + "saveInfo": 4, + "typeName": "creditCardExpirationYear" + } + }, + { + "autofillHints": [ + "organization-title" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "organization-titleseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "organization-title" + } + }, + { + "autofillHints": [ + "sex" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [ + "Male", + "Female", + "Other" + ] + }, + "partition": 0, + "saveInfo": 0, + "typeName": "sex" + } + }, + { + "autofillHints": [ + "section-" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "section-seed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "section-" + } + }, + { + "autofillHints": [ + "country-name" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [ + "USA", + "Mexico", + "Canada" + ] + }, + "partition": 1, + "saveInfo": 2, + "typeName": "country-name" + } + }, + { + "autofillHints": [ + "photo" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "photoseed.jpg" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "photo" + } + }, + { + "autofillHints": [ + "tel-area-code" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "tel-area-codeseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "tel-area-code" + } + }, + { + "autofillHints": [ + "new-password" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "new-passwordseed" + }, + "partition": 0, + "saveInfo": 1, + "typeName": "new-password" + } + }, + { + "autofillHints": [ + "tel-local-suffix" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "tel-local-suffixseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "tel-local-suffix" + } + }, + { + "autofillHints": [ + "family-name" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "family-nameseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "family-name" + } + }, + { + "autofillHints": [ + "url" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "https://www.google.com/?count\u003dseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "url" + } + }, + { + "autofillHints": [ + "home" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "homeseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "home" + } + }, + { + "autofillHints": [ + "address-level4" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "address-level4seed" + }, + "partition": 1, + "saveInfo": 2, + "typeName": "address-level4" + } + }, + { + "autofillHints": [ + "address-level3" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "address-level3seed" + }, + "partition": 1, + "saveInfo": 2, + "typeName": "address-level3" + } + }, + { + "autofillHints": [ + "organization" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "organizationseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "organization" + } + }, + { + "autofillHints": [ + "cc-additional-name" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "cc-additional-nameseed" + }, + "partition": 3, + "saveInfo": 4, + "typeName": "cc-additional-name" + } + }, + { + "autofillHints": [ + "address-level2" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "address-level2seed" + }, + "partition": 1, + "saveInfo": 2, + "typeName": "address-level2" + } + }, + { + "autofillHints": [ + "given-name" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "given-nameseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "given-name" + } + }, + { + "autofillHints": [ + "address-level1" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "address-level1seed" + }, + "partition": 1, + "saveInfo": 2, + "typeName": "address-level1" + } + }, + { + "autofillHints": [ + "creditCardExpirationDay" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3, + 4 + ], + "fakeData": { + "dateTemplate": "curr_time", + "strictExampleSet": [], + "textTemplate": "creditCardExpirationDayseed" + }, + "partition": 3, + "saveInfo": 4, + "typeName": "creditCardExpirationDay" + } + }, + { + "autofillHints": [ + "cc-name" + ], + "fieldType": { + "autofillTypes": [ + 1 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "Firstnameseed Lastnameseed" + }, + "partition": 3, + "saveInfo": 4, + "typeName": "cc-name" + } + }, + { + "autofillHints": [ + "username" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "usernameseed" + }, + "partition": 0, + "saveInfo": 8, + "typeName": "username" + } + }, + { + "autofillHints": [ + "tel-country-code" + ], + "fieldType": { + "autofillTypes": [ + 1, + 3 + ], + "fakeData": { + "strictExampleSet": [], + "textTemplate": "tel-country-codeseed" + }, + "partition": 0, + "saveInfo": 0, + "typeName": "tel-country-code" + } + } +] |