Merge "Allow better customization of Autofill dialogs."

This commit is contained in:
Tim Yu
2023-01-14 01:58:06 +00:00
committed by Android (Google) Code Review
6 changed files with 183 additions and 12 deletions

View File

@@ -39235,9 +39235,13 @@ package android.service.autofill {
method @NonNull public android.service.autofill.FillResponse.Builder setFlags(int);
method @NonNull public android.service.autofill.FillResponse.Builder setFooter(@NonNull android.widget.RemoteViews);
method @NonNull public android.service.autofill.FillResponse.Builder setHeader(@NonNull android.widget.RemoteViews);
method @NonNull public android.service.autofill.FillResponse.Builder setIconResourceId(@DrawableRes int);
method @NonNull public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...);
method @NonNull public android.service.autofill.FillResponse.Builder setPresentationCancelIds(@Nullable int[]);
method @NonNull public android.service.autofill.FillResponse.Builder setSaveInfo(@NonNull android.service.autofill.SaveInfo);
method @NonNull public android.service.autofill.FillResponse.Builder setServiceDisplayNameResourceId(@StringRes int);
method @NonNull public android.service.autofill.FillResponse.Builder setShowFillDialogIcon(boolean);
method @NonNull public android.service.autofill.FillResponse.Builder setShowSaveDialogIcon(boolean);
method @NonNull public android.service.autofill.FillResponse.Builder setUserData(@NonNull android.service.autofill.UserData);
}

View File

@@ -20,9 +20,11 @@ import static android.service.autofill.AutofillServiceHelper.assertValid;
import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
import static android.view.autofill.Helper.sDebug;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.app.Activity;
@@ -107,6 +109,10 @@ public final class FillResponse implements Parcelable {
private final @Nullable UserData mUserData;
private final @Nullable int[] mCancelIds;
private final boolean mSupportsInlineSuggestions;
private final @DrawableRes int mIconResourceId;
private final @StringRes int mServiceDisplayNameResourceId;
private final boolean mShowFillDialogIcon;
private final boolean mShowSaveDialogIcon;
private FillResponse(@NonNull Builder builder) {
mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null;
@@ -130,6 +136,10 @@ public final class FillResponse implements Parcelable {
mUserData = builder.mUserData;
mCancelIds = builder.mCancelIds;
mSupportsInlineSuggestions = builder.mSupportsInlineSuggestions;
mIconResourceId = builder.mIconResourceId;
mServiceDisplayNameResourceId = builder.mServiceDisplayNameResourceId;
mShowFillDialogIcon = builder.mShowFillDialogIcon;
mShowSaveDialogIcon = builder.mShowSaveDialogIcon;
}
/** @hide */
@@ -217,6 +227,26 @@ public final class FillResponse implements Parcelable {
return mUserData;
}
/** @hide */
public @DrawableRes int getIconResourceId() {
return mIconResourceId;
}
/** @hide */
public @StringRes int getServiceDisplayNameResourceId() {
return mServiceDisplayNameResourceId;
}
/** @hide */
public boolean getShowFillDialogIcon() {
return mShowFillDialogIcon;
}
/** @hide */
public boolean getShowSaveDialogIcon() {
return mShowSaveDialogIcon;
}
/** @hide */
@TestApi
public int getFlags() {
@@ -278,6 +308,10 @@ public final class FillResponse implements Parcelable {
private UserData mUserData;
private int[] mCancelIds;
private boolean mSupportsInlineSuggestions;
private int mIconResourceId;
private int mServiceDisplayNameResourceId;
private boolean mShowFillDialogIcon = true;
private boolean mShowSaveDialogIcon = true;
/**
* Triggers a custom UI before autofilling the screen with any data set in this
@@ -728,6 +762,70 @@ public final class FillResponse implements Parcelable {
return this;
}
/**
* Overwrites Save/Fill dialog header icon with a specific one specified by resource id.
* The image is pulled from the package, so id should be defined in the manifest.
*
* @param id {@link android.graphics.drawable.Drawable} resource id of the icon to be used.
* A value of 0 indicates to use the default header icon.
*
* @return this builder
*/
@NonNull
public Builder setIconResourceId(@DrawableRes int id) {
throwIfDestroyed();
mIconResourceId = id;
return this;
}
/**
* Overrides the service name in the Save Dialog header with a specific string defined
* in the service provider's manifest.xml
*
* @param id Resoure Id of the custom string defined in the provider's manifest. If set
* to 0, the default name will be used.
*
* @return this builder
*/
@NonNull
public Builder setServiceDisplayNameResourceId(@StringRes int id) {
throwIfDestroyed();
mServiceDisplayNameResourceId = id;
return this;
}
/**
* Whether or not to show the Autofill provider icon inside of the Fill Dialog
*
* @param show True to show, false to hide. Defaults to true.
*
* @return this builder
*/
@NonNull
public Builder setShowFillDialogIcon(boolean show) {
throwIfDestroyed();
mShowFillDialogIcon = show;
return this;
}
/**
* Whether or not to show the Autofill provider icon inside of the Save Dialog
*
* @param show True to show, false to hide. Defaults to true.
*
* @return this builder
*/
@NonNull
public Builder setShowSaveDialogIcon(boolean show) {
throwIfDestroyed();
mShowSaveDialogIcon = show;
return this;
}
/**
* Sets a header to be shown as the first element in the list of datasets.
*
@@ -1024,6 +1122,10 @@ public final class FillResponse implements Parcelable {
parcel.writeParcelableArray(mIgnoredIds, flags);
parcel.writeLong(mDisableDuration);
parcel.writeParcelableArray(mFieldClassificationIds, flags);
parcel.writeInt(mIconResourceId);
parcel.writeInt(mServiceDisplayNameResourceId);
parcel.writeBoolean(mShowFillDialogIcon);
parcel.writeBoolean(mShowSaveDialogIcon);
parcel.writeInt(mFlags);
parcel.writeIntArray(mCancelIds);
parcel.writeInt(mRequestId);
@@ -1089,6 +1191,11 @@ public final class FillResponse implements Parcelable {
if (fieldClassifactionIds != null) {
builder.setFieldClassificationIds(fieldClassifactionIds);
}
builder.setIconResourceId(parcel.readInt());
builder.setServiceDisplayNameResourceId(parcel.readInt());
builder.setShowFillDialogIcon(parcel.readBoolean());
builder.setShowSaveDialogIcon(parcel.readBoolean());
builder.setFlags(parcel.readInt());
final int[] cancelIds = parcel.createIntArray();
builder.setPresentationCancelIds(cancelIds);

View File

@@ -2651,8 +2651,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final CharSequence serviceLabel;
final Drawable serviceIcon;
synchronized (mLock) {
serviceLabel = mService.getServiceLabelLocked();
serviceIcon = mService.getServiceIconLocked();
serviceIcon = getServiceIcon(response);
serviceLabel = getServiceLabel(response);
}
if (serviceLabel == null || serviceIcon == null) {
wtf(null, "showSaveLocked(): no service label or icon");
@@ -2662,7 +2662,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
getUiForShowing().showSaveUi(serviceLabel, serviceIcon,
mService.getServicePackageName(), saveInfo, this,
mComponentName, this, mPendingSaveUi, isUpdate, mCompatMode);
mComponentName, this, mPendingSaveUi, isUpdate, mCompatMode,
response.getShowSaveDialogIcon());
if (client != null) {
try {
client.setSaveUiState(id, true);
@@ -3600,9 +3601,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (sDebug) Log.w(TAG, "Last fill dialog triggered ids are changed.");
return false;
}
}
final Drawable serviceIcon = getServiceIcon();
Drawable serviceIcon = null;
synchronized (mLock) {
serviceIcon = getServiceIcon(response);
}
getUiForShowing().showFillDialog(filledId, response, filterText,
mService.getServicePackageName(), mComponentName, serviceIcon, this,
@@ -3610,13 +3615,64 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return true;
}
/**
* Get the custom icon that was passed through FillResponse. If the custom icon wasn't able
* to be fetched, use the default provider icon instead
*
* @return Drawable of the provider icon, if it was able to be fetched. Null otherwise
*/
@SuppressWarnings("GuardedBy") // ErrorProne says we need to use mService.mLock, but it's
// actually the same object as mLock.
// TODO: Expose mService.mLock or redesign instead.
private Drawable getServiceIcon() {
synchronized (mLock) {
return mService.getServiceIconLocked();
@GuardedBy("mLock")
private Drawable getServiceIcon(FillResponse response) {
Drawable serviceIcon = null;
// Try to get the custom Icon, if one was passed through FillResponse
int iconResourceId = response.getIconResourceId();
if (iconResourceId != 0) {
serviceIcon = mService.getMaster().getContext().getPackageManager()
.getDrawable(
mService.getServicePackageName(),
iconResourceId,
null);
}
// Custom icon wasn't fetched, use the default package icon instead
if (serviceIcon == null) {
serviceIcon = mService.getServiceIconLocked();
}
return serviceIcon;
}
/**
* Get the custom label that was passed through FillResponse. If the custom label
* wasn't able to be fetched, use the default provider icon instead
*
* @return Drawable of the provider icon, if it was able to be fetched. Null otherwise
*/
@SuppressWarnings("GuardedBy") // ErrorProne says we need to use mService.mLock, but it's
// actually the same object as mLock.
// TODO: Expose mService.mLock or redesign instead.
@GuardedBy("mLock")
private CharSequence getServiceLabel(FillResponse response) {
CharSequence serviceLabel = null;
// Try to get the custom Service name, if one was passed through FillResponse
int customServiceNameId = response.getServiceDisplayNameResourceId();
if (customServiceNameId != 0) {
serviceLabel = mService.getMaster().getContext().getPackageManager()
.getText(
mService.getServicePackageName(),
customServiceNameId,
null);
}
// Custom label wasn't fetched, use the default package name instead
if (serviceLabel == null) {
serviceLabel = mService.getServiceLabelLocked();
}
return serviceLabel;
}
/**

View File

@@ -315,7 +315,7 @@ public final class AutoFillUI {
@Nullable String servicePackageName, @NonNull SaveInfo info,
@NonNull ValueFinder valueFinder, @NonNull ComponentName componentName,
@NonNull AutoFillUiCallback callback, @NonNull PendingUi pendingSaveUi,
boolean isUpdate, boolean compatMode) {
boolean isUpdate, boolean compatMode, boolean showServiceIcon) {
if (sVerbose) {
Slog.v(TAG, "showSaveUi(update=" + isUpdate + ") for " + componentName.toShortString()
+ ": " + info);
@@ -379,7 +379,7 @@ public final class AutoFillUI {
public void startIntentSender(IntentSender intentSender, Intent intent) {
callback.startIntentSender(intentSender, intent);
}
}, mUiModeMgr.isNightMode(), isUpdate, compatMode);
}, mUiModeMgr.isNightMode(), isUpdate, compatMode, showServiceIcon);
});
}

View File

@@ -117,7 +117,9 @@ final class DialogFillUi {
final LayoutInflater inflater = LayoutInflater.from(mContext);
final View decor = inflater.inflate(R.layout.autofill_fill_dialog, null);
setServiceIcon(decor, serviceIcon);
if (response.getShowFillDialogIcon()) {
setServiceIcon(decor, serviceIcon);
}
setHeader(decor, response);
mVisibleDatasetsMaxCount = getVisibleDatasetsMaxCount();

View File

@@ -177,7 +177,7 @@ final class SaveUi {
@Nullable String servicePackageName, @NonNull ComponentName componentName,
@NonNull SaveInfo info, @NonNull ValueFinder valueFinder,
@NonNull OverlayControl overlayControl, @NonNull OnSaveListener listener,
boolean nightMode, boolean isUpdate, boolean compatMode) {
boolean nightMode, boolean isUpdate, boolean compatMode, boolean showServiceIcon) {
if (sVerbose) Slog.v(TAG, "nightMode: " + nightMode);
mThemeId = nightMode ? THEME_ID_DARK : THEME_ID_LIGHT;
mPendingUi = pendingUi;
@@ -288,7 +288,9 @@ final class SaveUi {
}
titleView.setText(mTitle);
setServiceIcon(context, view, serviceIcon);
if (showServiceIcon) {
setServiceIcon(context, view, serviceIcon);
}
final boolean hasCustomDescription =
applyCustomDescription(context, view, valueFinder, info);