Merge "Fill-provider can control the negative button label and listener"
This commit is contained in:
committed by
Android (Google) Code Review
commit
5048c1cbb1
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,10 +91,22 @@ 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;
|
||||
@@ -194,6 +211,42 @@ public final class SaveInfo implements Parcelable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user