From b72f012cb49a5930010fb0766776b40c2955ee3e Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Fri, 24 Feb 2017 12:53:27 -0800 Subject: [PATCH] Added customization to SaveInfo. Bug: 35727295 Test: CtsAutoFillServiceTestCases pass Test: m update-api Change-Id: I7eba36b6ab8181ae1cdbd10b0879927b9f9cf086 --- api/current.txt | 9 ++- api/system-current.txt | 9 ++- api/test-current.txt | 9 ++- .../service/autofill/FillResponse.java | 4 +- .../android/service/autofill/SaveInfo.java | 75 +++++++++++++------ .../res/layout/autofill_dataset_picker.xml | 2 +- core/res/res/layout/autofill_save.xml | 8 ++ core/res/res/values/strings.xml | 13 +++- core/res/res/values/symbols.xml | 5 ++ .../autofill/AutoFillManagerServiceImpl.java | 5 +- .../server/autofill/ui/AutoFillUI.java | 5 +- .../android/server/autofill/ui/SaveUi.java | 33 +++++++- 12 files changed, 130 insertions(+), 47 deletions(-) diff --git a/api/current.txt b/api/current.txt index b1d70c0ab7a7d..f53dace58b129 100644 --- a/api/current.txt +++ b/api/current.txt @@ -36391,16 +36391,17 @@ package android.service.autofill { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; - field public static final int SAVE_UI_TYPE_ADDRESS = 2; // 0x2 - field public static final int SAVE_UI_TYPE_CREDENTIALS = 1; // 0x1 - field public static final int SAVE_UI_TYPE_GENERIC = 0; // 0x0 - field public static final int SAVE_UI_TYPE_PAYMENT = 3; // 0x3 + field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2 + field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3 + field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0 + field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1 } public static final class SaveInfo.Builder { ctor public SaveInfo.Builder(int); method public android.service.autofill.SaveInfo.Builder addSavableIds(android.view.autofill.AutoFillId...); method public android.service.autofill.SaveInfo build(); + method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); } } diff --git a/api/system-current.txt b/api/system-current.txt index 924c79c9da180..44c9578d1bbdf 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -39311,16 +39311,17 @@ package android.service.autofill { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; - field public static final int SAVE_UI_TYPE_ADDRESS = 2; // 0x2 - field public static final int SAVE_UI_TYPE_CREDENTIALS = 1; // 0x1 - field public static final int SAVE_UI_TYPE_GENERIC = 0; // 0x0 - field public static final int SAVE_UI_TYPE_PAYMENT = 3; // 0x3 + field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2 + field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3 + field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0 + field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1 } public static final class SaveInfo.Builder { ctor public SaveInfo.Builder(int); method public android.service.autofill.SaveInfo.Builder addSavableIds(android.view.autofill.AutoFillId...); method public android.service.autofill.SaveInfo build(); + method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); } } diff --git a/api/test-current.txt b/api/test-current.txt index c8bd890e83b4e..bc200f336efca 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -36530,16 +36530,17 @@ package android.service.autofill { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; - field public static final int SAVE_UI_TYPE_ADDRESS = 2; // 0x2 - field public static final int SAVE_UI_TYPE_CREDENTIALS = 1; // 0x1 - field public static final int SAVE_UI_TYPE_GENERIC = 0; // 0x0 - field public static final int SAVE_UI_TYPE_PAYMENT = 3; // 0x3 + field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2 + field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; // 0x3 + field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0 + field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1 } public static final class SaveInfo.Builder { ctor public SaveInfo.Builder(int); method public android.service.autofill.SaveInfo.Builder addSavableIds(android.view.autofill.AutoFillId...); method public android.service.autofill.SaveInfo build(); + method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence); } } diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java index a241d1fa707cc..ba75c8bee0397 100644 --- a/core/java/android/service/autofill/FillResponse.java +++ b/core/java/android/service/autofill/FillResponse.java @@ -188,7 +188,7 @@ public final class FillResponse implements Parcelable { // Handle the the case where service didn't call setSavableIds() because it would // contain just the ids from the datasets. if (saveInfo == null && mDatasets != null) { - saveInfo = new SaveInfo.Builder(SaveInfo.SAVE_UI_TYPE_GENERIC).build(); + saveInfo = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC).build(); } if (saveInfo != null) { saveInfo.addSavableIds(mDatasets); @@ -324,7 +324,7 @@ public final class FillResponse implements Parcelable { throw new IllegalStateException("setSaveInfo() already called"); } if (mSaveInfoBuilder == null) { - mSaveInfoBuilder = new SaveInfo.Builder(SaveInfo.SAVE_UI_TYPE_GENERIC); + mSaveInfoBuilder = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC); } mSaveInfoBuilder.addSavableIds(ids); diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java index 148bd24f552c0..096f28b606871 100644 --- a/core/java/android/service/autofill/SaveInfo.java +++ b/core/java/android/service/autofill/SaveInfo.java @@ -52,43 +52,44 @@ public final class SaveInfo implements Parcelable { * Type used on when the service can save the contents of an activity, but cannot describe what * the content is for. */ - public static final int SAVE_UI_TYPE_GENERIC = 0; + public static final int SAVE_DATA_TYPE_GENERIC = 0; /** - * Type used when the {@link FillResponse} represents user credentials (such as username and - * password). + * Type used when the {@link FillResponse} represents user credentials that have a password. */ - public static final int SAVE_UI_TYPE_CREDENTIALS = 1; + public static final int SAVE_DATA_TYPE_PASSWORD = 1; + /** * Type used on when the {@link FillResponse} represents a physical address (such as street, * city, state, etc). */ - public static final int SAVE_UI_TYPE_ADDRESS = 2; + public static final int SAVE_DATA_TYPE_ADDRESS = 2; /** - * Type used when the {@link FillResponse} represents a payment (such as credit card number - * and expiration date). + * Type used when the {@link FillResponse} represents a credit card. */ - public static final int SAVE_UI_TYPE_PAYMENT = 3; + public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; - private final @SaveUiType int mType; + private final @SaveDataType int mType; private ArraySet mSavableIds; + private final CharSequence mDescription; /** @hide */ @IntDef({ - SAVE_UI_TYPE_GENERIC, - SAVE_UI_TYPE_CREDENTIALS, - SAVE_UI_TYPE_ADDRESS, - SAVE_UI_TYPE_PAYMENT + SAVE_DATA_TYPE_GENERIC, + SAVE_DATA_TYPE_PASSWORD, + SAVE_DATA_TYPE_ADDRESS, + SAVE_DATA_TYPE_CREDIT_CARD }) @Retention(RetentionPolicy.SOURCE) - public @interface SaveUiType { + public @interface SaveDataType { } private SaveInfo(Builder builder) { mType = builder.mType; mSavableIds = builder.mSavableIds; + mDescription = builder.mDescription; } /** @hide */ @@ -96,6 +97,16 @@ public final class SaveInfo implements Parcelable { return mSavableIds; } + /** @hide */ + public int getType() { + return mType; + } + + /** @hide */ + public CharSequence getDescription() { + return mDescription; + } + /** @hide */ public void addSavableIds(@Nullable ArrayList datasets) { if (datasets != null) { @@ -120,27 +131,28 @@ public final class SaveInfo implements Parcelable { */ public static final class Builder { - private final @SaveUiType int mType; + private final @SaveDataType int mType; private ArraySet mSavableIds; + private CharSequence mDescription; private boolean mDestroyed; /** * Creates a new builder. * * @param type the type of information the associated {@link FillResponse} represents. Must - * be {@link SaveInfo#SAVE_UI_TYPE_GENERIC}, {@link SaveInfo#SAVE_UI_TYPE_CREDENTIALS}, - * {@link SaveInfo#SAVE_UI_TYPE_ADDRESS}, or {@link SaveInfo#SAVE_UI_TYPE_PAYMENT}; - * otherwise it will assume {@link SaveInfo#SAVE_UI_TYPE_GENERIC}. + * be {@link SaveInfo#SAVE_DATA_TYPE_GENERIC}, {@link SaveInfo#SAVE_DATA_TYPE_PASSWORD}, + * {@link SaveInfo#SAVE_DATA_TYPE_ADDRESS}, or {@link SaveInfo#SAVE_DATA_TYPE_CREDIT_CARD}; + * otherwise it will assume {@link SaveInfo#SAVE_DATA_TYPE_GENERIC}. */ - public Builder(@SaveUiType int type) { + public Builder(@SaveDataType int type) { switch (type) { - case SAVE_UI_TYPE_CREDENTIALS: - case SAVE_UI_TYPE_ADDRESS: - case SAVE_UI_TYPE_PAYMENT: + case SAVE_DATA_TYPE_PASSWORD: + case SAVE_DATA_TYPE_ADDRESS: + case SAVE_DATA_TYPE_CREDIT_CARD: mType = type; break; default: - mType = SAVE_UI_TYPE_GENERIC; + mType = SAVE_DATA_TYPE_GENERIC; } } @@ -168,6 +180,20 @@ public final class SaveInfo implements Parcelable { return this; } + /** + * Sets an optional description to be shown in the UI when the user is asked to save. + * + *

Typically, it describes how the data will be stored by the service, so it can help + * users to decide whether they can trust the service to save their data. + * + * @param description a succint description. + * @return This Builder. + */ + public @NonNull Builder setDescription(@Nullable CharSequence description) { + mDescription = description; + return this; + } + /** * Builds a new {@link SaveInfo} instance. */ @@ -210,6 +236,7 @@ public final class SaveInfo implements Parcelable { public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(mType); parcel.writeTypedArraySet(mSavableIds, flags); + parcel.writeCharSequence(mDescription); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @@ -224,7 +251,7 @@ public final class SaveInfo implements Parcelable { for (int i = 0; i < savableIdsCount; i++) { builder.addSavableIds(savableIds.valueAt(i)); } - + builder.setDescription(parcel.readCharSequence()); return builder.build(); } diff --git a/core/res/res/layout/autofill_dataset_picker.xml b/core/res/res/layout/autofill_dataset_picker.xml index 40cce7b04d875..9b90de6003976 100644 --- a/core/res/res/layout/autofill_dataset_picker.xml +++ b/core/res/res/layout/autofill_dataset_picker.xml @@ -15,7 +15,7 @@ --> + + + Switch to clock mode for the time input. - + Save to %1$s? + + Save %1$s to %2$s? Save No thanks + + password + + address + + credit card + diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 49216d9b3951c..6995d9a9e7391 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2838,12 +2838,17 @@ + + + + + diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java index 7e9cbca3df95d..bfc6e836c3b0d 100644 --- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java @@ -743,8 +743,9 @@ final class AutoFillManagerServiceImpl { Slog.d(TAG, "finishSessionLocked(): found a change on " + id + ": " + state.mAutoFillValue); } - getUiForShowing().showSaveUi(mInfo.getServiceInfo() - .loadLabel(mContext.getPackageManager())); + getUiForShowing().showSaveUi( + mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()), + saveInfo); return; } } diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java index cc0baa3193079..949a80c7bfdc2 100644 --- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java +++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java @@ -24,6 +24,7 @@ import android.os.Handler; import android.os.IBinder; import android.service.autofill.Dataset; import android.service.autofill.FillResponse; +import android.service.autofill.SaveInfo; import android.text.TextUtils; import android.view.autofill.AutoFillId; import android.widget.Toast; @@ -172,13 +173,13 @@ public final class AutoFillUI { /** * Shows the UI asking the user to save for auto-fill. */ - public void showSaveUi(@NonNull CharSequence providerLabel) { + public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info) { mHandler.post(() -> { if (!hasCallback()) { return; } hideAllUiThread(); - mSaveUi = new SaveUi(mContext, providerLabel, + mSaveUi = new SaveUi(mContext, providerLabel, info, new SaveUi.OnSaveListener() { @Override public void onSave() { diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java index b7215d66dacc1..afe93c7d6e067 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.app.Dialog; import android.content.Context; import android.os.Handler; +import android.service.autofill.SaveInfo; import android.text.format.DateUtils; import android.view.Gravity; import android.view.Window; @@ -50,15 +51,41 @@ final class SaveUi { private boolean mDestroyed; - SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, + SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info, @NonNull OnSaveListener listener) { mListener = listener; final LayoutInflater inflater = LayoutInflater.from(context); final View view = inflater.inflate(R.layout.autofill_save, null); - final TextView title = (TextView) view.findViewById(R.id.autofill_save_title); - title.setText(context.getString(R.string.autofill_save_title, providerLabel)); + final TextView titleView = (TextView) view.findViewById(R.id.autofill_save_title); + final String type; + + switch(info.getType()) { + case SaveInfo.SAVE_DATA_TYPE_PASSWORD: + type = context.getString(R.string.autofill_save_type_password); + break; + case SaveInfo.SAVE_DATA_TYPE_ADDRESS: + type = context.getString(R.string.autofill_save_type_address); + break; + case SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD: + type = context.getString(R.string.autofill_save_type_credit_card); + break; + default: + type = null; + } + + final String title = (type == null) + ? context.getString(R.string.autofill_save_title, providerLabel) + : context.getString(R.string.autofill_save_title_with_type, type, providerLabel); + + titleView.setText(title); + final CharSequence subTitle = info.getDescription(); + if (subTitle != null) { + final TextView subTitleView = (TextView) view.findViewById(R.id.autofill_save_subtitle); + subTitleView.setText(subTitle); + subTitleView.setVisibility(View.VISIBLE); + } final View noButton = view.findViewById(R.id.autofill_save_no); noButton.setOnClickListener((v) -> mListener.onCancel());