diff options
| -rw-r--r-- | api/current.txt | 1 | ||||
| -rw-r--r-- | api/system-current.txt | 1 | ||||
| -rw-r--r-- | api/test-current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/service/autofill/FillResponse.java | 6 | ||||
| -rw-r--r-- | core/java/android/service/autofill/SaveInfo.java | 56 | ||||
| -rw-r--r-- | services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java | 1 | ||||
| -rw-r--r-- | services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java | 13 | ||||
| -rw-r--r-- | services/autofill/java/com/android/server/autofill/ui/SaveUi.java | 17 |
8 files changed, 86 insertions, 10 deletions
diff --git a/api/current.txt b/api/current.txt index 5099c2b62a98..6e054fc5f240 100644 --- a/api/current.txt +++ b/api/current.txt @@ -36535,6 +36535,7 @@ package android.service.autofill { 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); + method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); } } diff --git a/api/system-current.txt b/api/system-current.txt index 41b52ec999d5..0cef28e0a80a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -39458,6 +39458,7 @@ package android.service.autofill { 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); + method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); } } diff --git a/api/test-current.txt b/api/test-current.txt index 5183e27a9e07..478a3ed42444 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -36674,6 +36674,7 @@ package android.service.autofill { 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); + method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender); } } diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java index ba75c8bee039..ef551ad29623 100644 --- a/core/java/android/service/autofill/FillResponse.java +++ b/core/java/android/service/autofill/FillResponse.java @@ -171,7 +171,7 @@ public final class FillResponse implements Parcelable { if (false) { // TODO(b/33197203, 35727295): this is how mSaveInfo will be set once we don't support - // FillResponse.setSavableIds() + // FillResponse.addSavableIds() mSaveInfo = builder.mSaveInfo; if (mSaveInfo != null) { mSaveInfo.addSavableIds(mDatasets); @@ -181,11 +181,11 @@ public final class FillResponse implements Parcelable { } } } else { - // Temporary workaround to support FillResponse.setSavableIds() + // Temporary workaround to support FillResponse.addSavableIds() SaveInfo saveInfo = builder.mSaveInfoBuilder != null ? builder.mSaveInfoBuilder.build() : builder.mSaveInfo; - // Handle the the case where service didn't call setSavableIds() because it would + // Handle the the case where service didn't call addSavableIds() because it would // contain just the ids from the datasets. if (saveInfo == null && mDatasets != null) { saveInfo = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC).build(); diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java index 096f28b60687..a8f9aeedb6b9 100644 --- a/core/java/android/service/autofill/SaveInfo.java +++ b/core/java/android/service/autofill/SaveInfo.java @@ -21,6 +21,7 @@ import static android.view.autofill.Helper.DEBUG; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.IntentSender; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -72,6 +73,8 @@ public final class SaveInfo implements Parcelable { public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; private final @SaveDataType int mType; + private CharSequence mNegativeActionTitle; + private IntentSender mNegativeActionListener; private ArraySet<AutoFillId> mSavableIds; private final CharSequence mDescription; @@ -88,11 +91,23 @@ public final class SaveInfo implements Parcelable { private SaveInfo(Builder builder) { mType = builder.mType; + mNegativeActionTitle = builder.mNegativeActionTitle; + mNegativeActionListener = builder.mNegativeActionListener; mSavableIds = builder.mSavableIds; mDescription = builder.mDescription; } /** @hide */ + public @Nullable CharSequence getNegativeActionTitle() { + return mNegativeActionTitle; + } + + /** @hide */ + public @Nullable IntentSender getNegativeActionListener() { + return mNegativeActionListener; + } + + /** @hide */ public @Nullable ArraySet<AutoFillId> getSavableIds() { return mSavableIds; } @@ -132,6 +147,8 @@ public final class SaveInfo implements Parcelable { public static final class Builder { private final @SaveDataType int mType; + private CharSequence mNegativeActionTitle; + private IntentSender mNegativeActionListener; private ArraySet<AutoFillId> mSavableIds; private CharSequence mDescription; private boolean mDestroyed; @@ -195,6 +212,42 @@ public final class SaveInfo implements Parcelable { } /** + * Sets the title and listener for the negative save action. + * + * <p>This allows a fill-provider to customize the text and be + * notified when the user selects the negative action in the save + * UI. Note that selecting the negative action regardless of its text + * and listener being customized would dismiss the save UI and if a + * custom listener intent is provided then this intent will be + * started.</p> + * + * <p>This customization could be useful for providing additional + * semantics to the negative action. For example, a fill-provider + * can use this mechanism to add a "Disable" function or a "More info" + * function, etc. Note that the save action is exclusively controlled + * by the platform to ensure user consent is collected to release + * data from the filled app to the fill-provider.</p> + * + * @param title The action title. + * @param listener The action listener. + * @return This builder. + * + * @throws IllegalArgumentException If the title and the listener + * are not both either null or non-null. + */ + public @NonNull Builder setNegativeAction(@Nullable CharSequence title, + @Nullable IntentSender listener) { + throwIfDestroyed(); + if (title == null ^ listener == null) { + throw new IllegalArgumentException("title and listener" + + " must be both non-null or null"); + } + mNegativeActionTitle = title; + mNegativeActionListener = listener; + return this; + } + + /** * Builds a new {@link SaveInfo} instance. */ public SaveInfo build() { @@ -235,6 +288,8 @@ public final class SaveInfo implements Parcelable { @Override public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(mType); + parcel.writeCharSequence(mNegativeActionTitle); + parcel.writeParcelable(mNegativeActionListener, flags); parcel.writeTypedArraySet(mSavableIds, flags); parcel.writeCharSequence(mDescription); } @@ -246,6 +301,7 @@ public final class SaveInfo implements Parcelable { // the system obeys the contract of the builder to avoid attacks // using specially crafted parcels. final Builder builder = new Builder(parcel.readInt()); + builder.setNegativeAction(parcel.readCharSequence(), parcel.readParcelable(null)); final ArraySet<AutoFillId> savableIds = parcel.readTypedArraySet(null); final int savableIdsCount = (savableIds != null) ? savableIds.size() : 0; for (int i = 0; i < savableIdsCount; i++) { diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java index ad4dac070d38..5e852f1738f1 100644 --- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java @@ -59,7 +59,6 @@ import android.service.autofill.IAutoFillService; import android.service.autofill.SaveInfo; import android.text.TextUtils; import android.util.ArrayMap; -import android.util.ArraySet; import android.util.LocalLog; import android.util.PrintWriterPrinter; import android.util.Slog; 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 949a80c7bfdc..0da36c8936c8 100644 --- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java +++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java @@ -26,6 +26,7 @@ import android.service.autofill.Dataset; import android.service.autofill.FillResponse; import android.service.autofill.SaveInfo; import android.text.TextUtils; +import android.util.Slog; import android.view.autofill.AutoFillId; import android.widget.Toast; @@ -41,6 +42,8 @@ import java.io.PrintWriter; * managing saving of user edits. */ public final class AutoFillUI { + private static final String TAG = "AutoFillUI"; + private final Handler mHandler = UiThread.getHandler(); private final @NonNull Context mContext; @@ -191,9 +194,17 @@ public final class AutoFillUI { } @Override - public void onCancel() { + public void onCancel(IntentSender listener) { // TODO(b/33197203): add MetricsLogger call hideSaveUiUiThread(); + if (listener != null) { + try { + listener.sendIntent(mContext, 0, null, null, null); + } catch (IntentSender.SendIntentException e) { + Slog.e(TAG, "Error starting negative action listener: " + + listener, e); + } + } } }); }); 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 afe93c7d6e06..d443dc34f949 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -19,6 +19,7 @@ package com.android.server.autofill.ui; import android.annotation.NonNull; import android.app.Dialog; import android.content.Context; +import android.content.IntentSender; import android.os.Handler; import android.service.autofill.SaveInfo; import android.text.format.DateUtils; @@ -38,7 +39,7 @@ import com.android.server.UiThread; final class SaveUi { public interface OnSaveListener { void onSave(); - void onCancel(); + void onCancel(IntentSender listener); } private static final long LIFETIME_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS; @@ -87,14 +88,20 @@ final class SaveUi { subTitleView.setVisibility(View.VISIBLE); } - final View noButton = view.findViewById(R.id.autofill_save_no); - noButton.setOnClickListener((v) -> mListener.onCancel()); + final TextView noButton = view.findViewById(R.id.autofill_save_no); + if (info.getNegativeActionTitle() != null) { + noButton.setText(info.getNegativeActionTitle()); + noButton.setOnClickListener((v) -> mListener.onCancel( + info.getNegativeActionListener())); + } else { + noButton.setOnClickListener((v) -> mListener.onCancel(null)); + } final View yesButton = view.findViewById(R.id.autofill_save_yes); yesButton.setOnClickListener((v) -> mListener.onSave()); final View closeButton = view.findViewById(R.id.autofill_save_close); - closeButton.setOnClickListener((v) -> mListener.onCancel()); + closeButton.setOnClickListener((v) -> mListener.onCancel(null)); mDialog = new Dialog(context, R.style.Theme_Material_Panel); mDialog.setContentView(view); @@ -112,7 +119,7 @@ final class SaveUi { mDialog.show(); - mHandler.postDelayed(() -> mListener.onCancel(), LIFETIME_MILLIS); + mHandler.postDelayed(() -> mListener.onCancel(null), LIFETIME_MILLIS); } void destroy() { |