From 88872971a7da6b828a32140a2cf2a5cc3b7222b2 Mon Sep 17 00:00:00 2001 From: Feng Cao Date: Tue, 3 Mar 2020 19:03:05 -0800 Subject: [PATCH] Create InlineAction class to wrap the IntentSender and the presentation * Before this change, we were putting the action intent in the Slice, but we realize that's not the best place as slice is only meant for data representation, and intent does not fall into that * This patch includes the code to actually fire the pending intent when action suggestion is clicked. However, it'll only work if the fill service have the SYSTEM_ALERT_WINDOW permission for the intent to be fired when it is in the background. We will move it to be fired from the client foreground app in a separate patch Test: manual verification Test: atest android.autofillservice.cts.inline Bug: 150499490 Change-Id: I411a7ee05e783f7de94a54064c44a6126afe0b12 --- api/current.txt | 11 +- api/system-current.txt | 2 +- api/test-current.txt | 2 +- .../service/autofill/FillResponse.java | 19 +- .../service/autofill/InlineAction.aidl | 19 ++ .../service/autofill/InlineAction.java | 205 ++++++++++++++++++ .../augmented/AugmentedAutofillService.java | 4 +- .../autofill/augmented/FillResponse.java | 31 ++- .../autofill/augmented/IFillCallback.aidl | 4 +- .../RemoteAugmentedAutofillService.java | 8 +- .../com/android/server/autofill/Session.java | 4 +- .../autofill/ui/InlineSuggestionFactory.java | 51 +++-- 12 files changed, 296 insertions(+), 64 deletions(-) create mode 100644 core/java/android/service/autofill/InlineAction.aidl create mode 100644 core/java/android/service/autofill/InlineAction.java diff --git a/api/current.txt b/api/current.txt index 6052d93d1f608..bf1ebd0abc933 100644 --- a/api/current.txt +++ b/api/current.txt @@ -43108,7 +43108,7 @@ package android.service.autofill { public static final class FillResponse.Builder { ctor public FillResponse.Builder(); method @NonNull public android.service.autofill.FillResponse.Builder addDataset(@Nullable android.service.autofill.Dataset); - method @NonNull public android.service.autofill.FillResponse.Builder addInlineAction(@NonNull android.service.autofill.InlinePresentation); + method @NonNull public android.service.autofill.FillResponse.Builder addInlineAction(@NonNull android.service.autofill.InlineAction); method @NonNull public android.service.autofill.FillResponse build(); method @NonNull public android.service.autofill.FillResponse.Builder disableAutofill(long); method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews); @@ -43138,6 +43138,15 @@ package android.service.autofill { method public android.service.autofill.ImageTransformation build(); } + public final class InlineAction implements android.os.Parcelable { + ctor public InlineAction(@NonNull android.service.autofill.InlinePresentation, @NonNull android.content.IntentSender); + method public int describeContents(); + method @NonNull public android.content.IntentSender getAction(); + method @NonNull public android.service.autofill.InlinePresentation getInlinePresentation(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + public final class InlinePresentation implements android.os.Parcelable { ctor public InlinePresentation(@NonNull android.app.slice.Slice, @NonNull android.view.inline.InlinePresentationSpec, boolean); method public int describeContents(); diff --git a/api/system-current.txt b/api/system-current.txt index e8c0d0511425b..605fbca825fc6 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -9868,7 +9868,7 @@ package android.service.autofill.augmented { method @NonNull public android.service.autofill.augmented.FillResponse build(); method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@NonNull android.os.Bundle); method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@NonNull android.service.autofill.augmented.FillWindow); - method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@NonNull java.util.List); + method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@NonNull java.util.List); method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@NonNull java.util.List); } diff --git a/api/test-current.txt b/api/test-current.txt index a38ad8f9b1f32..21e41d2d1da65 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -3229,7 +3229,7 @@ package android.service.autofill.augmented { method @NonNull public android.service.autofill.augmented.FillResponse build(); method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@NonNull android.os.Bundle); method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@NonNull android.service.autofill.augmented.FillWindow); - method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@NonNull java.util.List); + method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@NonNull java.util.List); method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@NonNull java.util.List); } diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java index e8e1223a29d06..06b5fa07a554d 100644 --- a/core/java/android/service/autofill/FillResponse.java +++ b/core/java/android/service/autofill/FillResponse.java @@ -89,7 +89,7 @@ public final class FillResponse implements Parcelable { private final @Nullable int[] mCancelIds; private final boolean mSupportsInlineSuggestions; // TODO(b/149240554): revert back to use ParceledListSlice after the bug is resolved. - private final @Nullable ArrayList mInlineActions; + private final @Nullable ArrayList mInlineActions; private FillResponse(@NonNull Builder builder) { mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null; @@ -213,7 +213,7 @@ public final class FillResponse implements Parcelable { } /** @hide */ - public @Nullable List getInlineActions() { + public @Nullable List getInlineActions() { return mInlineActions; } @@ -239,7 +239,7 @@ public final class FillResponse implements Parcelable { private UserData mUserData; private int[] mCancelIds; private boolean mSupportsInlineSuggestions; - private ArrayList mInlineActions; + private ArrayList mInlineActions; /** * Triggers a custom UI before before autofilling the screen with any data set in this @@ -656,15 +656,12 @@ public final class FillResponse implements Parcelable { } /** - * Adds a new {@link InlinePresentation} to this response representing an action UI. - * - *

For example, the UI can be associated with an intent which can open an activity for - * the user to manage the Autofill provider settings. + * Adds a new {@link InlineAction} to this response representing an action UI. * * @return This builder. */ @NonNull - public Builder addInlineAction(@NonNull InlinePresentation inlineAction) { + public Builder addInlineAction(@NonNull InlineAction inlineAction) { throwIfDestroyed(); throwIfAuthenticationCalled(); if (mInlineActions == null) { @@ -881,10 +878,10 @@ public final class FillResponse implements Parcelable { final int[] cancelIds = parcel.createIntArray(); builder.setPresentationCancelIds(cancelIds); - final List inlineActions = parcel.createTypedArrayList( - InlinePresentation.CREATOR); + final List inlineActions = parcel.createTypedArrayList( + InlineAction.CREATOR); if (inlineActions != null) { - for (InlinePresentation inlineAction : inlineActions) { + for (InlineAction inlineAction : inlineActions) { builder.addInlineAction(inlineAction); } } diff --git a/core/java/android/service/autofill/InlineAction.aidl b/core/java/android/service/autofill/InlineAction.aidl new file mode 100644 index 0000000000000..7f8511825d731 --- /dev/null +++ b/core/java/android/service/autofill/InlineAction.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.autofill; + +parcelable InlineAction; diff --git a/core/java/android/service/autofill/InlineAction.java b/core/java/android/service/autofill/InlineAction.java new file mode 100644 index 0000000000000..17c4b33ba96bd --- /dev/null +++ b/core/java/android/service/autofill/InlineAction.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.autofill; + +import android.annotation.NonNull; +import android.content.IntentSender; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +/** + * Represents an inline action as part of the autofill/augmented autofill response. + * + *

It includes both the action intent and the UI presentation. For example, the UI can be + * associated with an intent which can open an activity for the user to manage the Autofill provider + * settings. + */ +@DataClass( + genToString = true, + genHiddenConstDefs = true, + genEqualsHashCode = true) +public final class InlineAction implements Parcelable { + + /** + * Representation of the inline action. + */ + private final @NonNull InlinePresentation mInlinePresentation; + + /** + * The associated intent which will be triggered when the action is selected. It will only be + * called by the OS. + */ + private final @NonNull IntentSender mAction; + + + + // Code below generated by codegen v1.0.15. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/autofill/InlineAction.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new InlineAction. + * + * @param inlinePresentation + * Representation of the inline action. + * @param action + * The associated intent which will be triggered when the action is selected. It will only be + * invoked by the OS. + */ + @DataClass.Generated.Member + public InlineAction( + @NonNull InlinePresentation inlinePresentation, + @NonNull IntentSender action) { + this.mInlinePresentation = inlinePresentation; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mInlinePresentation); + this.mAction = action; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAction); + + // onConstructed(); // You can define this method to get a callback + } + + /** + * Representation of the inline action. + */ + @DataClass.Generated.Member + public @NonNull InlinePresentation getInlinePresentation() { + return mInlinePresentation; + } + + /** + * The associated intent which will be triggered when the action is selected. It will only be + * invoked by the OS. + */ + @DataClass.Generated.Member + public @NonNull IntentSender getAction() { + return mAction; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "InlineAction { " + + "inlinePresentation = " + mInlinePresentation + ", " + + "action = " + mAction + + " }"; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@android.annotation.Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(InlineAction other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + InlineAction that = (InlineAction) o; + //noinspection PointlessBooleanExpression + return true + && java.util.Objects.equals(mInlinePresentation, that.mInlinePresentation) + && java.util.Objects.equals(mAction, that.mAction); + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + java.util.Objects.hashCode(mInlinePresentation); + _hash = 31 * _hash + java.util.Objects.hashCode(mAction); + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeTypedObject(mInlinePresentation, flags); + dest.writeTypedObject(mAction, flags); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ InlineAction(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + InlinePresentation inlinePresentation = (InlinePresentation) in.readTypedObject(InlinePresentation.CREATOR); + IntentSender action = (IntentSender) in.readTypedObject(IntentSender.CREATOR); + + this.mInlinePresentation = inlinePresentation; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mInlinePresentation); + this.mAction = action; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAction); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public InlineAction[] newArray(int size) { + return new InlineAction[size]; + } + + @Override + public InlineAction createFromParcel(@NonNull android.os.Parcel in) { + return new InlineAction(in); + } + }; + + @DataClass.Generated( + time = 1583798182424L, + codegenVersion = "1.0.15", + sourceFile = "frameworks/base/core/java/android/service/autofill/InlineAction.java", + inputSignatures = "private final @android.annotation.NonNull android.service.autofill.InlinePresentation mInlinePresentation\nprivate final @android.annotation.NonNull android.content.IntentSender mAction\nclass InlineAction extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java index fe792b1efd9f1..ed27dd5688232 100644 --- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java +++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java @@ -40,7 +40,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.service.autofill.Dataset; import android.service.autofill.FillEventHistory; -import android.service.autofill.InlinePresentation; +import android.service.autofill.InlineAction; import android.service.autofill.augmented.PresentationParams.SystemPopupPresentationParams; import android.util.Log; import android.util.Pair; @@ -559,7 +559,7 @@ public abstract class AugmentedAutofillService extends Service { } void reportResult(@Nullable List inlineSuggestionsData, - @Nullable List inlineActions) { + @Nullable List inlineActions) { try { mCallback.onSuccess(inlineSuggestionsData, inlineActions); } catch (RemoteException e) { diff --git a/core/java/android/service/autofill/augmented/FillResponse.java b/core/java/android/service/autofill/augmented/FillResponse.java index 37d75aa5d5027..f564b3ba616ac 100644 --- a/core/java/android/service/autofill/augmented/FillResponse.java +++ b/core/java/android/service/autofill/augmented/FillResponse.java @@ -21,7 +21,7 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.Bundle; import android.service.autofill.Dataset; -import android.service.autofill.InlinePresentation; +import android.service.autofill.InlineAction; import com.android.internal.util.DataClass; @@ -53,11 +53,10 @@ public final class FillResponse { private @Nullable List mInlineSuggestions; /** - * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no - * inline actions are provided. + * Defaults to null if no inline actions are provided. */ @DataClass.PluralOf("inlineAction") - private @Nullable List mInlineActions; + private @Nullable List mInlineActions; /** * The client state that {@link AugmentedAutofillService} implementation can put anything in to @@ -74,7 +73,7 @@ public final class FillResponse { return null; } - private static List defaultInlineActions() { + private static List defaultInlineActions() { return null; } @@ -86,7 +85,7 @@ public final class FillResponse { /** @hide */ abstract static class BaseBuilder { abstract FillResponse.Builder addInlineSuggestion(@NonNull Dataset value); - abstract FillResponse.Builder addInlineAction(@NonNull InlinePresentation value); + abstract FillResponse.Builder addInlineAction(@NonNull InlineAction value); } @@ -108,7 +107,7 @@ public final class FillResponse { /* package-private */ FillResponse( @Nullable FillWindow fillWindow, @Nullable List inlineSuggestions, - @Nullable List inlineActions, + @Nullable List inlineActions, @Nullable Bundle clientState) { this.mFillWindow = fillWindow; this.mInlineSuggestions = inlineSuggestions; @@ -140,13 +139,12 @@ public final class FillResponse { } /** - * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no - * inline actions are provided. + * Defaults to null if no inline actions are provided. * * @hide */ @DataClass.Generated.Member - public @Nullable List getInlineActions() { + public @Nullable List getInlineActions() { return mInlineActions; } @@ -171,7 +169,7 @@ public final class FillResponse { private @Nullable FillWindow mFillWindow; private @Nullable List mInlineSuggestions; - private @Nullable List mInlineActions; + private @Nullable List mInlineActions; private @Nullable Bundle mClientState; private long mBuilderFieldsSet = 0L; @@ -212,11 +210,10 @@ public final class FillResponse { } /** - * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no - * inline actions are provided. + * Defaults to null if no inline actions are provided. */ @DataClass.Generated.Member - public @NonNull Builder setInlineActions(@NonNull List value) { + public @NonNull Builder setInlineActions(@NonNull List value) { checkNotUsed(); mBuilderFieldsSet |= 0x4; mInlineActions = value; @@ -226,7 +223,7 @@ public final class FillResponse { /** @see #setInlineActions */ @DataClass.Generated.Member @Override - @NonNull FillResponse.Builder addInlineAction(@NonNull InlinePresentation value) { + @NonNull FillResponse.Builder addInlineAction(@NonNull InlineAction value) { if (mInlineActions == null) setInlineActions(new ArrayList<>()); mInlineActions.add(value); return this; @@ -279,10 +276,10 @@ public final class FillResponse { } @DataClass.Generated( - time = 1583780042587L, + time = 1583793032373L, codegenVersion = "1.0.15", sourceFile = "frameworks/base/core/java/android/service/autofill/augmented/FillResponse.java", - inputSignatures = "private @android.annotation.Nullable android.service.autofill.augmented.FillWindow mFillWindow\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineSuggestion\") @android.annotation.Nullable java.util.List mInlineSuggestions\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineAction\") @android.annotation.Nullable java.util.List mInlineActions\nprivate @android.annotation.Nullable android.os.Bundle mClientState\nprivate static android.service.autofill.augmented.FillWindow defaultFillWindow()\nprivate static java.util.List defaultInlineSuggestions()\nprivate static java.util.List defaultInlineActions()\nprivate static android.os.Bundle defaultClientState()\nclass FillResponse extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genHiddenGetters=true)\nabstract android.service.autofill.augmented.FillResponse.Builder addInlineSuggestion(android.service.autofill.Dataset)\nabstract android.service.autofill.augmented.FillResponse.Builder addInlineAction(android.service.autofill.InlinePresentation)\nclass BaseBuilder extends java.lang.Object implements []") + inputSignatures = "private @android.annotation.Nullable android.service.autofill.augmented.FillWindow mFillWindow\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineSuggestion\") @android.annotation.Nullable java.util.List mInlineSuggestions\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineAction\") @android.annotation.Nullable java.util.List mInlineActions\nprivate @android.annotation.Nullable android.os.Bundle mClientState\nprivate static android.service.autofill.augmented.FillWindow defaultFillWindow()\nprivate static java.util.List defaultInlineSuggestions()\nprivate static java.util.List defaultInlineActions()\nprivate static android.os.Bundle defaultClientState()\nclass FillResponse extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genHiddenGetters=true)\nabstract android.service.autofill.augmented.FillResponse.Builder addInlineSuggestion(android.service.autofill.Dataset)\nabstract android.service.autofill.augmented.FillResponse.Builder addInlineAction(android.service.autofill.InlineAction)\nclass BaseBuilder extends java.lang.Object implements []") @Deprecated private void __metadata() {} diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl index bf0adcd54ab16..545dab2840677 100644 --- a/core/java/android/service/autofill/augmented/IFillCallback.aidl +++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl @@ -20,7 +20,7 @@ import android.os.Bundle; import android.os.ICancellationSignal; import android.service.autofill.Dataset; -import android.service.autofill.InlinePresentation; +import android.service.autofill.InlineAction; import java.util.List; @@ -32,7 +32,7 @@ import java.util.List; interface IFillCallback { void onCancellable(in ICancellationSignal cancellation); void onSuccess(in @nullable List inlineSuggestionsData, - in @nullable List inlineActions); + in @nullable List inlineActions); boolean isCompleted(); void cancel(); } diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java index 2420e69b5d908..e73f9ce4f7c09 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java @@ -37,7 +37,7 @@ import android.os.ICancellationSignal; import android.os.RemoteException; import android.os.SystemClock; import android.service.autofill.Dataset; -import android.service.autofill.InlinePresentation; +import android.service.autofill.InlineAction; import android.service.autofill.augmented.AugmentedAutofillService; import android.service.autofill.augmented.IAugmentedAutofillService; import android.service.autofill.augmented.IFillCallback; @@ -167,7 +167,7 @@ final class RemoteAugmentedAutofillService new IFillCallback.Stub() { @Override public void onSuccess(@Nullable List inlineSuggestionsData, - @Nullable List inlineActions) { + @Nullable List inlineActions) { mCallbacks.resetLastResponse(); maybeRequestShowInlineSuggestions(sessionId, inlineSuggestionsRequest, inlineSuggestionsData, @@ -237,7 +237,7 @@ final class RemoteAugmentedAutofillService private void maybeRequestShowInlineSuggestions(int sessionId, @Nullable InlineSuggestionsRequest request, @Nullable List inlineSuggestionsData, - @Nullable List inlineActions, @NonNull AutofillId focusedId, + @Nullable List inlineActions, @NonNull AutofillId focusedId, @Nullable Function inlineSuggestionsCallback, @NonNull IAutoFillManagerClient client, @NonNull Runnable onErrorCallback, @Nullable RemoteInlineSuggestionRenderService remoteRenderService) { @@ -250,7 +250,7 @@ final class RemoteAugmentedAutofillService final InlineSuggestionsResponse inlineSuggestionsResponse = InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse( - request, inlineSuggestionsData, inlineActions, focusedId, mContext, + request, inlineSuggestionsData, inlineActions, focusedId, dataset -> { mCallbacks.logAugmentedAutofillSelected(sessionId, dataset.getId()); diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index f14a7e906c5da..56194788358df 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -137,7 +137,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private final Handler mHandler; private final Object mLock; private final AutoFillUI mUi; - private final Context mContext; private final MetricsLogger mMetricsLogger = new MetricsLogger(); @@ -695,7 +694,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mLock = lock; mUi = ui; mHandler = handler; - mContext = context; mRemoteFillService = serviceComponentName == null ? null : new RemoteFillService(context, serviceComponentName, userId, this, bindInstantServiceAllowed); @@ -2680,7 +2678,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState InlineSuggestionsResponse inlineSuggestionsResponse = InlineSuggestionFactory.createInlineSuggestionsResponse( inlineSuggestionsRequest.get(), - response, filterText, response.getInlineActions(), mCurrentViewId, mContext, + response, filterText, response.getInlineActions(), mCurrentViewId, this, () -> { synchronized (mLock) { requestHideFillUi(mCurrentViewId); diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java index 4cf4463feaadd..82e5003d3961e 100644 --- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java +++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java @@ -21,12 +21,13 @@ import static com.android.server.autofill.Helper.sVerbose; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.Context; +import android.content.IntentSender; import android.os.IBinder; import android.os.RemoteException; import android.service.autofill.Dataset; import android.service.autofill.FillResponse; import android.service.autofill.IInlineSuggestionUiCallback; +import android.service.autofill.InlineAction; import android.service.autofill.InlinePresentation; import android.text.TextUtils; import android.util.Slog; @@ -39,7 +40,6 @@ import android.view.inputmethod.InlineSuggestion; import android.view.inputmethod.InlineSuggestionInfo; import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InlineSuggestionsResponse; -import android.widget.Toast; import com.android.internal.view.inline.IInlineContentCallback; import com.android.internal.view.inline.IInlineContentProvider; @@ -73,8 +73,8 @@ public final class InlineSuggestionFactory { @Nullable public static InlineSuggestionsResponse createInlineSuggestionsResponse( @NonNull InlineSuggestionsRequest request, @NonNull FillResponse response, - @Nullable String filterText, @Nullable List inlineActions, - @NonNull AutofillId autofillId, @NonNull Context context, + @Nullable String filterText, @Nullable List inlineActions, + @NonNull AutofillId autofillId, @NonNull AutoFillUI.AutoFillUiCallback client, @NonNull Runnable onErrorCallback, @Nullable RemoteInlineSuggestionRenderService remoteRenderService) { if (sDebug) Slog.d(TAG, "createInlineSuggestionsResponse called"); @@ -97,7 +97,7 @@ public final class InlineSuggestionFactory { response.getAuthentication() == null ? null : response.getInlinePresentation(); return createInlineSuggestionsResponseInternal(/* isAugmented= */ false, request, response.getDatasets(), filterText, inlineAuthentication, inlineActions, autofillId, - context, onErrorCallback, onClickFactory, remoteRenderService); + onErrorCallback, onClickFactory, remoteRenderService); } /** @@ -107,15 +107,14 @@ public final class InlineSuggestionFactory { @Nullable public static InlineSuggestionsResponse createAugmentedInlineSuggestionsResponse( @NonNull InlineSuggestionsRequest request, @NonNull List datasets, - @Nullable List inlineActions, - @NonNull AutofillId autofillId, @NonNull Context context, + @Nullable List inlineActions, @NonNull AutofillId autofillId, @NonNull InlineSuggestionUiCallback inlineSuggestionUiCallback, @NonNull Runnable onErrorCallback, @Nullable RemoteInlineSuggestionRenderService remoteRenderService) { if (sDebug) Slog.d(TAG, "createAugmentedInlineSuggestionsResponse called"); return createInlineSuggestionsResponseInternal(/* isAugmented= */ true, request, datasets, /* filterText= */ null, /* inlineAuthentication= */ null, - inlineActions, autofillId, context, onErrorCallback, + inlineActions, autofillId, onErrorCallback, (dataset, datasetIndex) -> inlineSuggestionUiCallback.autofill(dataset), remoteRenderService); } @@ -125,9 +124,8 @@ public final class InlineSuggestionFactory { boolean isAugmented, @NonNull InlineSuggestionsRequest request, @Nullable List datasets, @Nullable String filterText, @Nullable InlinePresentation inlineAuthentication, - @Nullable List inlineActions, @NonNull AutofillId autofillId, - @NonNull Context context, @NonNull Runnable onErrorCallback, - @NonNull BiConsumer onClickFactory, + @Nullable List inlineActions, @NonNull AutofillId autofillId, + @NonNull Runnable onErrorCallback, @NonNull BiConsumer onClickFactory, @Nullable RemoteInlineSuggestionRenderService remoteRenderService) { final ArrayList inlineSuggestions = new ArrayList<>(); @@ -171,12 +169,13 @@ public final class InlineSuggestionFactory { } // We should only add inline actions if there is at least one suggestion. if (!inlineSuggestions.isEmpty() && inlineActions != null) { - for (InlinePresentation inlinePresentation : inlineActions) { - final InlineSuggestion inlineAction = createInlineAction(isAugmented, context, - mergedInlinePresentation(request, 0, inlinePresentation), + for (InlineAction inlineAction : inlineActions) { + final InlineSuggestion inlineActionSuggestion = createInlineAction(isAugmented, + mergedInlinePresentation(request, 0, inlineAction.getInlinePresentation()), + inlineAction.getAction(), remoteRenderService, onErrorCallback, request.getHostInputToken(), request.getHostDisplayId()); - inlineSuggestions.add(inlineAction); + inlineSuggestions.add(inlineActionSuggestion); } } return new InlineSuggestionsResponse(inlineSuggestions); @@ -215,22 +214,30 @@ public final class InlineSuggestionFactory { private static InlineSuggestion createInlineAction(boolean isAugmented, - @NonNull Context context, - @NonNull InlinePresentation inlinePresentation, + @NonNull InlinePresentation presentation, + @NonNull IntentSender action, @Nullable RemoteInlineSuggestionRenderService remoteRenderService, @NonNull Runnable onErrorCallback, @Nullable IBinder hostInputToken, int displayId) { final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo( - inlinePresentation.getInlinePresentationSpec(), + presentation.getInlinePresentationSpec(), isAugmented ? InlineSuggestionInfo.SOURCE_PLATFORM : InlineSuggestionInfo.SOURCE_AUTOFILL, - inlinePresentation.getAutofillHints(), - InlineSuggestionInfo.TYPE_ACTION, inlinePresentation.isPinned()); + presentation.getAutofillHints(), InlineSuggestionInfo.TYPE_ACTION, + presentation.isPinned()); final Runnable onClickAction = () -> { - Toast.makeText(context, "icon clicked", Toast.LENGTH_SHORT).show(); + try { + // TODO(b/150499490): route the intent to the client app to have it fired there, + // so that it will appear as a part of the same task as the client app (similar + // to the authentication flow). + action.sendIntent(null, 0, null, null, null); + } catch (IntentSender.SendIntentException e) { + onErrorCallback.run(); + Slog.w(TAG, "Error sending inline action intent"); + } }; return new InlineSuggestion(inlineSuggestionInfo, - createInlineContentProvider(inlinePresentation, onClickAction, onErrorCallback, + createInlineContentProvider(presentation, onClickAction, onErrorCallback, remoteRenderService, hostInputToken, displayId)); }