Merge "Add pendingIntent to FillRequest to enable retriggering"

This commit is contained in:
TreeHugger Robot
2022-01-29 07:00:55 +00:00
committed by Android (Google) Code Review
6 changed files with 209 additions and 9 deletions

View File

@@ -37882,6 +37882,7 @@ package android.service.autofill {
method public abstract void onFillRequest(@NonNull android.service.autofill.FillRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback);
method public abstract void onSaveRequest(@NonNull android.service.autofill.SaveRequest, @NonNull android.service.autofill.SaveCallback);
method public void onSavedDatasetsInfoRequest(@NonNull android.service.autofill.SavedDatasetsInfoCallback);
field public static final String EXTRA_FILL_RESPONSE = "android.service.autofill.extra.FILL_RESPONSE";
field public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
field public static final String SERVICE_META_DATA = "android.autofill";
}
@@ -38037,6 +38038,7 @@ package android.service.autofill {
public final class FillRequest implements android.os.Parcelable {
method public int describeContents();
method @Nullable public android.os.Bundle getClientState();
method @Nullable public android.content.IntentSender getDelayedFillIntentSender();
method @NonNull public java.util.List<android.service.autofill.FillContext> getFillContexts();
method public int getFlags();
method public int getId();
@@ -38051,6 +38053,7 @@ package android.service.autofill {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.FillResponse> CREATOR;
field public static final int FLAG_DELAY_FILL = 4; // 0x4
field public static final int FLAG_DISABLE_ACTIVITY_ONLY = 2; // 0x2
field public static final int FLAG_TRACK_CONTEXT_COMMITED = 1; // 0x1
}

View File

@@ -577,6 +577,14 @@ public abstract class AutofillService extends Service {
*/
public static final String SERVICE_META_DATA = "android.autofill";
/**
* Name of the {@link FillResponse} extra used to return a delayed fill response.
*
* <p>Please see {@link FillRequest#getDelayedFillIntentSender()} on how to send a delayed
* fill response to framework.</p>
*/
public static final String EXTRA_FILL_RESPONSE = "android.service.autofill.extra.FILL_RESPONSE";
/**
* Name of the {@link IResultReceiver} extra used to return the primary result of a request.
*

View File

@@ -19,6 +19,7 @@ package android.service.autofill;
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;
@@ -160,6 +161,19 @@ public final class FillRequest implements Parcelable {
*/
private final @Nullable InlineSuggestionsRequest mInlineSuggestionsRequest;
/**
* Gets the {@link IntentSender} to send a delayed fill response.
*
* <p>The autofill service must first indicate that it wants to return a delayed
* {@link FillResponse} by setting {@link FillResponse#FLAG_DELAY_FILL} in a successful
* fill response. Then it can use this IntentSender to send an Intent with extra
* {@link AutofillService#EXTRA_FILL_RESPONSE} with the delayed response.</p>
*
* <p>Note that this may be null if a delayed fill response is not supported for
* this fill request.</p>
*/
private final @Nullable IntentSender mDelayedFillIntentSender;
private void onConstructed() {
Preconditions.checkCollectionElementsNotNull(mFillContexts, "contexts");
}
@@ -252,6 +266,16 @@ public final class FillRequest implements Parcelable {
*
* <p>The Autofill Service must set supportsInlineSuggestions in its XML to enable support
* for inline suggestions.</p>
* @param delayedFillIntentSender
* Gets the {@link IntentSender} to send a delayed fill response.
*
* <p>The autofill service must first indicate that it wants to return a delayed
* {@link FillResponse} by setting {@link FillResponse#FLAG_DELAY_FILL} in a successful
* fill response. Then it can use this IntentSender to send an Intent with extra
* {@link AutofillService#EXTRA_FILL_RESPONSE} with the delayed response.</p>
*
* <p>Note that this may be null if a delayed fill response is not supported for
* this fill request.</p>
* @hide
*/
@DataClass.Generated.Member
@@ -260,7 +284,8 @@ public final class FillRequest implements Parcelable {
@NonNull List<FillContext> fillContexts,
@Nullable Bundle clientState,
@RequestFlags int flags,
@Nullable InlineSuggestionsRequest inlineSuggestionsRequest) {
@Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
@Nullable IntentSender delayedFillIntentSender) {
this.mId = id;
this.mFillContexts = fillContexts;
com.android.internal.util.AnnotationValidations.validate(
@@ -276,6 +301,7 @@ public final class FillRequest implements Parcelable {
| FLAG_VIEW_NOT_FOCUSED
| FLAG_ACTIVITY_START);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
this.mDelayedFillIntentSender = delayedFillIntentSender;
onConstructed();
}
@@ -348,6 +374,22 @@ public final class FillRequest implements Parcelable {
return mInlineSuggestionsRequest;
}
/**
* Gets the {@link IntentSender} to send a delayed fill response.
*
* <p>The autofill service must first indicate that it wants to return a delayed
* {@link FillResponse} by setting {@link FillResponse#FLAG_DELAY_FILL} in a successful
* fill response. Then it can use this IntentSender to send an Intent with extra
* {@link AutofillService#EXTRA_FILL_RESPONSE} with the delayed response.</p>
*
* <p>Note that this may be null if a delayed fill response is not supported for
* this fill request.</p>
*/
@DataClass.Generated.Member
public @Nullable IntentSender getDelayedFillIntentSender() {
return mDelayedFillIntentSender;
}
@Override
@DataClass.Generated.Member
public String toString() {
@@ -359,7 +401,8 @@ public final class FillRequest implements Parcelable {
"fillContexts = " + mFillContexts + ", " +
"clientState = " + mClientState + ", " +
"flags = " + requestFlagsToString(mFlags) + ", " +
"inlineSuggestionsRequest = " + mInlineSuggestionsRequest +
"inlineSuggestionsRequest = " + mInlineSuggestionsRequest + ", " +
"delayedFillIntentSender = " + mDelayedFillIntentSender +
" }";
}
@@ -372,12 +415,14 @@ public final class FillRequest implements Parcelable {
byte flg = 0;
if (mClientState != null) flg |= 0x4;
if (mInlineSuggestionsRequest != null) flg |= 0x10;
if (mDelayedFillIntentSender != null) flg |= 0x20;
dest.writeByte(flg);
dest.writeInt(mId);
dest.writeParcelableList(mFillContexts, flags);
if (mClientState != null) dest.writeBundle(mClientState);
dest.writeInt(mFlags);
if (mInlineSuggestionsRequest != null) dest.writeTypedObject(mInlineSuggestionsRequest, flags);
if (mDelayedFillIntentSender != null) dest.writeTypedObject(mDelayedFillIntentSender, flags);
}
@Override
@@ -398,6 +443,7 @@ public final class FillRequest implements Parcelable {
Bundle clientState = (flg & 0x4) == 0 ? null : in.readBundle();
int flags = in.readInt();
InlineSuggestionsRequest inlineSuggestionsRequest = (flg & 0x10) == 0 ? null : (InlineSuggestionsRequest) in.readTypedObject(InlineSuggestionsRequest.CREATOR);
IntentSender delayedFillIntentSender = (flg & 0x20) == 0 ? null : (IntentSender) in.readTypedObject(IntentSender.CREATOR);
this.mId = id;
this.mFillContexts = fillContexts;
@@ -414,6 +460,7 @@ public final class FillRequest implements Parcelable {
| FLAG_VIEW_NOT_FOCUSED
| FLAG_ACTIVITY_START);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
this.mDelayedFillIntentSender = delayedFillIntentSender;
onConstructed();
}
@@ -433,10 +480,10 @@ public final class FillRequest implements Parcelable {
};
@DataClass.Generated(
time = 1643052544776L,
time = 1643386870464L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_ACTIVITY_START\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_ACTIVITY_START\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
@Deprecated
private void __metadata() {}

View File

@@ -65,10 +65,22 @@ public final class FillResponse implements Parcelable {
*/
public static final int FLAG_DISABLE_ACTIVITY_ONLY = 0x2;
/**
* Flag used to request to wait for a delayed fill from the remote Autofill service if it's
* passed to {@link Builder#setFlags(int)}.
*
* <p>Some datasets (i.e. OTP) take time to produce. This flags allows remote service to send
* a {@link FillResponse} to the latest {@link FillRequest} via
* {@link FillRequest#getDelayedFillIntentSender()} even if the original {@link FillCallback}
* has timed out.
*/
public static final int FLAG_DELAY_FILL = 0x4;
/** @hide */
@IntDef(flag = true, prefix = { "FLAG_" }, value = {
FLAG_TRACK_CONTEXT_COMMITED,
FLAG_DISABLE_ACTIVITY_ONLY
FLAG_DISABLE_ACTIVITY_ONLY,
FLAG_DELAY_FILL
})
@Retention(RetentionPolicy.SOURCE)
@interface FillResponseFlags {}
@@ -657,7 +669,7 @@ public final class FillResponse implements Parcelable {
public Builder setFlags(@FillResponseFlags int flags) {
throwIfDestroyed();
mFlags = Preconditions.checkFlagsArgument(flags,
FLAG_TRACK_CONTEXT_COMMITED | FLAG_DISABLE_ACTIVITY_ONLY);
FLAG_TRACK_CONTEXT_COMMITED | FLAG_DISABLE_ACTIVITY_ONLY | FLAG_DELAY_FILL);
return this;
}

View File

@@ -719,6 +719,7 @@
<protected-broadcast android:name="android.safetycenter.action.REFRESH_SAFETY_SOURCES" />
<protected-broadcast android:name="android.app.action.DEVICE_POLICY_RESOURCE_UPDATED" />
<protected-broadcast android:name="android.intent.action.SHOW_FOREGROUND_SERVICE_MANAGER" />
<protected-broadcast android:name="android.service.autofill.action.DELAYED_FILL" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->

View File

@@ -17,6 +17,7 @@
package com.android.server.autofill;
import static android.service.autofill.AutofillFieldClassificationService.EXTRA_SCORES;
import static android.service.autofill.AutofillService.EXTRA_FILL_RESPONSE;
import static android.service.autofill.FillRequest.FLAG_ACTIVITY_START;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
@@ -47,13 +48,16 @@ import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityTaskManager;
import android.app.IAssistDataReceiver;
import android.app.PendingIntent;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.AutofillOverlay;
import android.app.assist.AssistStructure.ViewNode;
import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.graphics.Bitmap;
@@ -148,6 +152,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
AutoFillUI.AutoFillUiCallback, ValueFinder {
private static final String TAG = "AutofillSession";
private static final String ACTION_DELAYED_FILL =
"android.service.autofill.action.DELAYED_FILL";
private static final String EXTRA_REQUEST_ID = "android.service.autofill.extra.REQUEST_ID";
final Object mLock;
@@ -155,6 +161,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
private final AutofillManagerServiceImpl mService;
private final Handler mHandler;
private final AutoFillUI mUi;
@NonNull private final Context mContext;
private final MetricsLogger mMetricsLogger = new MetricsLogger();
@@ -269,6 +276,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
*/
private boolean mHasCallback;
@GuardedBy("mLock")
private boolean mDelayedFillBroadcastReceiverRegistered;
@GuardedBy("mLock")
private PendingIntent mDelayedFillPendingIntent;
/**
* Extras sent by service on {@code onFillRequest()} calls; the most recent non-null extra is
* saved and used on subsequent {@code onFillRequest()} and {@code onSaveRequest()} calls.
@@ -356,6 +369,32 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
private final AccessibilityManager mAccessibilityManager;
// TODO(b/216576510): Share one BroadcastReceiver between all Sessions instead of creating a
// new one per Session.
private final BroadcastReceiver mDelayedFillBroadcastReceiver =
new BroadcastReceiver() {
// ErrorProne says mAssistReceiver#processDelayedFillLocked needs to be guarded by
// 'Session.this.mLock', which is the same as mLock.
@SuppressWarnings("GuardedBy")
@Override
public void onReceive(final Context context, final Intent intent) {
if (!intent.getAction().equals(ACTION_DELAYED_FILL)) {
Slog.wtf(TAG, "Unexpected action is received.");
return;
}
if (!intent.hasExtra(EXTRA_REQUEST_ID)) {
Slog.e(TAG, "Delay fill action is missing request id extra.");
return;
}
Slog.v(TAG, "mDelayedFillBroadcastReceiver delayed fill action received");
synchronized (mLock) {
int requestId = intent.getIntExtra(EXTRA_REQUEST_ID, 0);
FillResponse response = intent.getParcelableExtra(EXTRA_FILL_RESPONSE);
mAssistReceiver.processDelayedFillLocked(requestId, response);
}
}
};
void onSwitchInputMethodLocked() {
// One caveat is that for the case where the focus is on a field for which regular autofill
// returns null, and augmented autofill is triggered, and then the user switches the input
@@ -447,6 +486,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
private InlineSuggestionsRequest mPendingInlineSuggestionsRequest;
@GuardedBy("mLock")
private FillRequest mPendingFillRequest;
@GuardedBy("mLock")
private FillRequest mLastFillRequest;
@Nullable Consumer<InlineSuggestionsRequest> newAutofillRequestLocked(ViewState viewState,
boolean isInlineRequest) {
@@ -473,6 +514,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mPendingInlineSuggestionsRequest = inlineRequest;
}
@GuardedBy("mLock")
void maybeRequestFillFromServiceLocked() {
if (mPendingFillRequest == null) {
return;
@@ -490,9 +532,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
mPendingFillRequest.getFillContexts(),
mPendingFillRequest.getClientState(),
mPendingFillRequest.getFlags(), mPendingInlineSuggestionsRequest);
mPendingFillRequest.getFlags(),
mPendingInlineSuggestionsRequest,
mPendingFillRequest.getDelayedFillIntentSender());
}
}
mLastFillRequest = mPendingFillRequest;
mRemoteFillService.onFillRequest(mPendingFillRequest);
mPendingInlineSuggestionsRequest = null;
@@ -594,8 +639,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final ArrayList<FillContext> contexts =
mergePreviousSessionLocked(/* forSave= */ false);
mDelayedFillPendingIntent = createPendingIntent(requestId);
request = new FillRequest(requestId, contexts, mClientState, flags,
/*inlineSuggestionsRequest=*/null);
/*inlineSuggestionsRequest=*/ null,
/*delayedFillIntentSender=*/ mDelayedFillPendingIntent == null
? null
: mDelayedFillPendingIntent.getIntentSender());
mPendingFillRequest = request;
maybeRequestFillFromServiceLocked();
@@ -610,7 +659,70 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
public void onHandleAssistScreenshot(Bitmap screenshot) {
// Do nothing
}
};
@GuardedBy("mLock")
void processDelayedFillLocked(int requestId, FillResponse response) {
if (mLastFillRequest != null && requestId == mLastFillRequest.getId()) {
Slog.v(TAG, "processDelayedFillLocked: "
+ "calling onFillRequestSuccess with new response");
onFillRequestSuccess(requestId, response,
mService.getServicePackageName(), mLastFillRequest.getFlags());
}
}
}
/** Creates {@link PendingIntent} for autofill service to send a delayed fill. */
private PendingIntent createPendingIntent(int requestId) {
Slog.d(TAG, "createPendingIntent for request " + requestId);
PendingIntent pendingIntent;
final long identity = Binder.clearCallingIdentity();
try {
Intent intent = new Intent(ACTION_DELAYED_FILL).setPackage("android")
.putExtra(EXTRA_REQUEST_ID, requestId);
pendingIntent = PendingIntent.getBroadcast(
mContext, this.id, intent,
PendingIntent.FLAG_MUTABLE
| PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_CANCEL_CURRENT);
} finally {
Binder.restoreCallingIdentity(identity);
}
return pendingIntent;
}
@GuardedBy("mLock")
private void clearPendingIntentLocked() {
Slog.d(TAG, "clearPendingIntentLocked");
if (mDelayedFillPendingIntent == null) {
return;
}
final long identity = Binder.clearCallingIdentity();
try {
mDelayedFillPendingIntent.cancel();
mDelayedFillPendingIntent = null;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@GuardedBy("mLock")
private void registerDelayedFillBroadcastLocked() {
if (!mDelayedFillBroadcastReceiverRegistered) {
Slog.v(TAG, "registerDelayedFillBroadcastLocked()");
IntentFilter intentFilter = new IntentFilter(ACTION_DELAYED_FILL);
mContext.registerReceiver(mDelayedFillBroadcastReceiver, intentFilter);
mDelayedFillBroadcastReceiverRegistered = true;
}
}
@GuardedBy("mLock")
private void unregisterDelayedFillBroadcastLocked() {
if (mDelayedFillBroadcastReceiverRegistered) {
Slog.v(TAG, "unregisterDelayedFillBroadcastLocked()");
mContext.unregisterReceiver(mDelayedFillBroadcastReceiver);
mDelayedFillBroadcastReceiverRegistered = false;
}
}
/**
* Returns the ids of all entries in {@link #mViewStates} in the same order.
@@ -964,6 +1076,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mHasCallback = hasCallback;
mUiLatencyHistory = uiLatencyHistory;
mWtfHistory = wtfHistory;
mContext = context;
mComponentName = componentName;
mCompatMode = compatMode;
mSessionState = STATE_ACTIVE;
@@ -1096,6 +1209,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
processNullResponseLocked(requestId, requestFlags);
return;
}
final int flags = response.getFlags();
if ((flags & FillResponse.FLAG_DELAY_FILL) != 0) {
Slog.v(TAG, "Service requested to wait for delayed fill response.");
registerDelayedFillBroadcastLocked();
}
}
mService.setLastResponse(id, response);
@@ -1206,6 +1325,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@Nullable CharSequence message) {
boolean showMessage = !TextUtils.isEmpty(message);
synchronized (mLock) {
unregisterDelayedFillBroadcastLocked();
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onFillRequestFailureOrTimeout(req=" + requestId
+ ") rejected - session: " + id + " destroyed");
@@ -3530,6 +3650,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@GuardedBy("mLock")
private void processNullResponseLocked(int requestId, int flags) {
unregisterDelayedFillBroadcastLocked();
if ((flags & FLAG_MANUAL_REQUEST) != 0) {
getUiForShowing().showError(R.string.autofill_error_cannot_autofill, this);
}
@@ -3744,6 +3865,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// only if handling the current response requires it.
mUi.hideAll(this);
if ((newResponse.getFlags() & FillResponse.FLAG_DELAY_FILL) == 0) {
Slog.d(TAG, "Service did not request to wait for delayed fill response.");
unregisterDelayedFillBroadcastLocked();
}
final int requestId = newResponse.getRequestId();
if (sVerbose) {
Slog.v(TAG, "processResponseLocked(): mCurrentViewId=" + mCurrentViewId
@@ -4296,6 +4422,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return null;
}
clearPendingIntentLocked();
unregisterDelayedFillBroadcastLocked();
unlinkClientVultureLocked();
mUi.destroyAll(mPendingSaveUi, this, true);
mUi.clearCallback(this);