diff --git a/core/api/current.txt b/core/api/current.txt index 84274cb507674..8dc28bd1220ac 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -39234,9 +39234,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); } diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java index 78f91edfedcd9..385b0aa8b867a 100644 --- a/core/java/android/service/autofill/FillResponse.java +++ b/core/java/android/service/autofill/FillResponse.java @@ -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); diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 81fbd78e2b62b..939047fdb622c 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -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; } /** 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 5f0f9a3f1577d..7db6e6f43f4be 100644 --- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java +++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java @@ -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); }); } diff --git a/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java b/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java index c2c630e01bee7..72a38eb14e21b 100644 --- a/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java @@ -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(); 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 8c2c964e2d2ca..7db27acf1afa8 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -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);