From b1fb9aa9cade1069524c9010c10ef76ac29a01a7 Mon Sep 17 00:00:00 2001 From: TYM Tsai Date: Wed, 19 May 2021 07:36:02 +0000 Subject: [PATCH] [DO NOT MERGE] Remove Client suggestions implementations Bug: 188618287 Test: atest CtsAutoFillServiceTestCases Change-Id: Iee3e5abc8f0ef067c8f9af936577ebd4274d6e72 (cherry picked from commit 6b2c01da6ec15ff2fcd9bbc3d7ed19209d8cb851) --- .../autofill/ClientSuggestionsSession.java | 293 ------------------ .../com/android/server/autofill/Session.java | 188 +++-------- 2 files changed, 36 insertions(+), 445 deletions(-) delete mode 100644 services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java diff --git a/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java b/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java deleted file mode 100644 index 715697d82cadb..0000000000000 --- a/services/autofill/java/com/android/server/autofill/ClientSuggestionsSession.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.server.autofill; - -import static android.service.autofill.FillRequest.INVALID_REQUEST_ID; - -import static com.android.server.autofill.Helper.sVerbose; - -import android.annotation.Nullable; -import android.annotation.UserIdInt; -import android.app.AppGlobals; -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.ICancellationSignal; -import android.os.RemoteException; -import android.service.autofill.Dataset; -import android.service.autofill.FillResponse; -import android.service.autofill.IFillCallback; -import android.service.autofill.SaveInfo; -import android.text.TextUtils; -import android.text.format.DateUtils; -import android.util.Slog; -import android.view.autofill.AutofillId; -import android.view.autofill.IAutoFillManagerClient; -import android.view.inputmethod.InlineSuggestionsRequest; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.infra.AndroidFuture; - -import java.util.List; -import java.util.concurrent.CancellationException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Maintains a client suggestions session with the - * {@link android.view.autofill.AutofillRequestCallback} through the {@link IAutoFillManagerClient}. - * - */ -final class ClientSuggestionsSession { - - private static final String TAG = "ClientSuggestionsSession"; - private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 15 * DateUtils.SECOND_IN_MILLIS; - - private final int mSessionId; - private final IAutoFillManagerClient mClient; - private final Handler mHandler; - private final ComponentName mComponentName; - - private final RemoteFillService.FillServiceCallbacks mCallbacks; - - private final Object mLock = new Object(); - @GuardedBy("mLock") - private AndroidFuture mPendingFillRequest; - @GuardedBy("mLock") - private int mPendingFillRequestId = INVALID_REQUEST_ID; - - ClientSuggestionsSession(int sessionId, IAutoFillManagerClient client, Handler handler, - ComponentName componentName, RemoteFillService.FillServiceCallbacks callbacks) { - mSessionId = sessionId; - mClient = client; - mHandler = handler; - mComponentName = componentName; - mCallbacks = callbacks; - } - - void onFillRequest(int requestId, InlineSuggestionsRequest inlineRequest, int flags) { - final AtomicReference cancellationSink = new AtomicReference<>(); - final AtomicReference> futureRef = new AtomicReference<>(); - final AndroidFuture fillRequest = new AndroidFuture<>(); - - mHandler.post(() -> { - if (sVerbose) { - Slog.v(TAG, "calling onFillRequest() for id=" + requestId); - } - - try { - mClient.requestFillFromClient(requestId, inlineRequest, - new FillCallbackImpl(fillRequest, futureRef, cancellationSink)); - } catch (RemoteException e) { - fillRequest.completeExceptionally(e); - } - }); - - fillRequest.orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS); - futureRef.set(fillRequest); - - synchronized (mLock) { - mPendingFillRequest = fillRequest; - mPendingFillRequestId = requestId; - } - - fillRequest.whenComplete((res, err) -> mHandler.post(() -> { - synchronized (mLock) { - mPendingFillRequest = null; - mPendingFillRequestId = INVALID_REQUEST_ID; - } - if (err == null) { - processAutofillId(res); - mCallbacks.onFillRequestSuccess(requestId, res, - mComponentName.getPackageName(), flags); - } else { - Slog.e(TAG, "Error calling on client fill request", err); - if (err instanceof TimeoutException) { - dispatchCancellationSignal(cancellationSink.get()); - mCallbacks.onFillRequestTimeout(requestId); - } else if (err instanceof CancellationException) { - dispatchCancellationSignal(cancellationSink.get()); - } else { - mCallbacks.onFillRequestFailure(requestId, err.getMessage()); - } - } - })); - } - - /** - * Gets the application info for the component. - */ - @Nullable - static ApplicationInfo getAppInfo(ComponentName comp, @UserIdInt int userId) { - try { - ApplicationInfo si = AppGlobals.getPackageManager().getApplicationInfo( - comp.getPackageName(), - PackageManager.GET_META_DATA, - userId); - if (si != null) { - return si; - } - } catch (RemoteException e) { - } - return null; - } - - /** - * Gets the user-visible name of the application. - */ - @Nullable - @GuardedBy("mLock") - static CharSequence getAppLabelLocked(Context context, ApplicationInfo appInfo) { - return appInfo == null ? null : appInfo.loadSafeLabel( - context.getPackageManager(), 0 /* do not ellipsize */, - TextUtils.SAFE_STRING_FLAG_FIRST_LINE | TextUtils.SAFE_STRING_FLAG_TRIM); - } - - /** - * Gets the user-visible icon of the application. - */ - @Nullable - @GuardedBy("mLock") - static Drawable getAppIconLocked(Context context, ApplicationInfo appInfo) { - return appInfo == null ? null : appInfo.loadIcon(context.getPackageManager()); - } - - int cancelCurrentRequest() { - synchronized (mLock) { - return mPendingFillRequest != null && mPendingFillRequest.cancel(false) - ? mPendingFillRequestId - : INVALID_REQUEST_ID; - } - } - - /** - * The {@link AutofillId} which the client gets from its view is not contain the session id, - * but Autofill framework is using the {@link AutofillId} with a session id. So before using - * those ids in the Autofill framework, applies the current session id. - * - * @param res which response need to apply for a session id - */ - private void processAutofillId(FillResponse res) { - if (res == null) { - return; - } - - final List datasets = res.getDatasets(); - if (datasets != null && !datasets.isEmpty()) { - for (int i = 0; i < datasets.size(); i++) { - final Dataset dataset = datasets.get(i); - if (dataset != null) { - applySessionId(dataset.getFieldIds()); - } - } - } - - final SaveInfo saveInfo = res.getSaveInfo(); - if (saveInfo != null) { - applySessionId(saveInfo.getOptionalIds()); - applySessionId(saveInfo.getRequiredIds()); - applySessionId(saveInfo.getSanitizerValues()); - applySessionId(saveInfo.getTriggerId()); - } - } - - private void applySessionId(List ids) { - if (ids == null || ids.isEmpty()) { - return; - } - - for (int i = 0; i < ids.size(); i++) { - applySessionId(ids.get(i)); - } - } - - private void applySessionId(AutofillId[][] ids) { - if (ids == null) { - return; - } - for (int i = 0; i < ids.length; i++) { - applySessionId(ids[i]); - } - } - - private void applySessionId(AutofillId[] ids) { - if (ids == null) { - return; - } - for (int i = 0; i < ids.length; i++) { - applySessionId(ids[i]); - } - } - - private void applySessionId(AutofillId id) { - if (id == null) { - return; - } - id.setSessionId(mSessionId); - } - - private void dispatchCancellationSignal(@Nullable ICancellationSignal signal) { - if (signal == null) { - return; - } - try { - signal.cancel(); - } catch (RemoteException e) { - Slog.e(TAG, "Error requesting a cancellation", e); - } - } - - private class FillCallbackImpl extends IFillCallback.Stub { - final AndroidFuture mFillRequest; - final AtomicReference> mFutureRef; - final AtomicReference mCancellationSink; - - FillCallbackImpl(AndroidFuture fillRequest, - AtomicReference> futureRef, - AtomicReference cancellationSink) { - mFillRequest = fillRequest; - mFutureRef = futureRef; - mCancellationSink = cancellationSink; - } - - @Override - public void onCancellable(ICancellationSignal cancellation) { - AndroidFuture future = mFutureRef.get(); - if (future != null && future.isCancelled()) { - dispatchCancellationSignal(cancellation); - } else { - mCancellationSink.set(cancellation); - } - } - - @Override - public void onSuccess(FillResponse response) { - mFillRequest.complete(response); - } - - @Override - public void onFailure(int requestId, CharSequence message) { - String errorMessage = message == null ? "" : String.valueOf(message); - mFillRequest.completeExceptionally( - new RuntimeException(errorMessage)); - } - } -} diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 042631d05186e..320047fec66b8 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -26,7 +26,6 @@ import static android.view.autofill.AutofillManager.ACTION_START_SESSION; import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED; import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED; import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED; -import static android.view.autofill.AutofillManager.FLAG_ENABLED_CLIENT_SUGGESTIONS; import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM; import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString; @@ -54,7 +53,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentSender; -import android.content.pm.ApplicationInfo; import android.graphics.Bitmap; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -348,9 +346,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState */ private final AssistDataReceiverImpl mAssistReceiver = new AssistDataReceiverImpl(); - @Nullable - private ClientSuggestionsSession mClientSuggestionsSession; - 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 @@ -421,10 +416,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState /** Whether the current {@link FillResponse} is expired. */ @GuardedBy("mLock") private boolean mExpiredResponse; - - /** Whether the client is using {@link android.view.autofill.AutofillRequestCallback}. */ - @GuardedBy("mLock") - private boolean mClientSuggestionsEnabled; } /** @@ -450,19 +441,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } mPendingInlineSuggestionsRequest = inlineSuggestionsRequest; - maybeRequestFillFromServiceLocked(); + maybeRequestFillLocked(); viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST); } } : null; } - void newAutofillRequestLocked(@Nullable InlineSuggestionsRequest inlineRequest) { - mPendingFillRequest = null; - mWaitForInlineRequest = inlineRequest != null; - mPendingInlineSuggestionsRequest = inlineRequest; - } - - void maybeRequestFillFromServiceLocked() { + void maybeRequestFillLocked() { if (mPendingFillRequest == null) { return; } @@ -472,12 +457,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } - if (mPendingInlineSuggestionsRequest.isServiceSupported()) { - mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(), - mPendingFillRequest.getFillContexts(), - mPendingFillRequest.getClientState(), - mPendingFillRequest.getFlags(), mPendingInlineSuggestionsRequest); - } + mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(), + mPendingFillRequest.getFillContexts(), mPendingFillRequest.getClientState(), + mPendingFillRequest.getFlags(), mPendingInlineSuggestionsRequest); } mRemoteFillService.onFillRequest(mPendingFillRequest); @@ -584,7 +566,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState /*inlineSuggestionsRequest=*/null); mPendingFillRequest = request; - maybeRequestFillFromServiceLocked(); + maybeRequestFillLocked(); } if (mActivityToken != null) { @@ -746,39 +728,30 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } /** - * Cancels the last request sent to the {@link #mRemoteFillService} or the - * {@link #mClientSuggestionsSession}. + * Cancels the last request sent to the {@link #mRemoteFillService}. */ @GuardedBy("mLock") private void cancelCurrentRequestLocked() { - if (mRemoteFillService == null && mClientSuggestionsSession == null) { - wtf(null, "cancelCurrentRequestLocked() called without a remote service or a " - + "client suggestions session. mForAugmentedAutofillOnly: %s", - mSessionFlags.mAugmentedAutofillOnly); + if (mRemoteFillService == null) { + wtf(null, "cancelCurrentRequestLocked() called without a remote service. " + + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly); return; } + final int canceledRequest = mRemoteFillService.cancelCurrentRequest(); - if (mRemoteFillService != null) { - final int canceledRequest = mRemoteFillService.cancelCurrentRequest(); + // Remove the FillContext as there will never be a response for the service + if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) { + final int numContexts = mContexts.size(); - // Remove the FillContext as there will never be a response for the service - if (canceledRequest != INVALID_REQUEST_ID && mContexts != null) { - final int numContexts = mContexts.size(); - - // It is most likely the last context, hence search backwards - for (int i = numContexts - 1; i >= 0; i--) { - if (mContexts.get(i).getRequestId() == canceledRequest) { - if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest); - mContexts.remove(i); - break; - } + // It is most likely the last context, hence search backwards + for (int i = numContexts - 1; i >= 0; i--) { + if (mContexts.get(i).getRequestId() == canceledRequest) { + if (sDebug) Slog.d(TAG, "cancelCurrentRequest(): id = " + canceledRequest); + mContexts.remove(i); + break; } } } - - if (mClientSuggestionsSession != null) { - mClientSuggestionsSession.cancelCurrentRequest(); - } } private boolean isViewFocusedLocked(int flags) { @@ -843,30 +816,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // structure is taken. This causes only one fill request per burst of focus changes. cancelCurrentRequestLocked(); - // Only ask IME to create inline suggestions request when - // 1. Autofill provider supports it or client enabled client suggestions. - // 2. The render service is available. - // 3. The view is focused. (The view may not be focused if the autofill is triggered - // manually.) + // Only ask IME to create inline suggestions request if Autofill provider supports it and + // the render service is available except the autofill is triggered manually and the view + // is also not focused. final RemoteInlineSuggestionRenderService remoteRenderService = mService.getRemoteInlineSuggestionRenderServiceLocked(); - if ((mSessionFlags.mInlineSupportedByService || mSessionFlags.mClientSuggestionsEnabled) + if (mSessionFlags.mInlineSupportedByService && remoteRenderService != null && isViewFocusedLocked(flags)) { - Consumer inlineSuggestionsRequestConsumer; - if (mSessionFlags.mClientSuggestionsEnabled) { - final int finalRequestId = requestId; - inlineSuggestionsRequestConsumer = (inlineSuggestionsRequest) -> { - // Using client suggestions - synchronized (mLock) { - onClientFillRequestLocked(finalRequestId, inlineSuggestionsRequest); - } - viewState.resetState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST); - }; - } else { - inlineSuggestionsRequestConsumer = mAssistReceiver.newAutofillRequestLocked( - viewState, /* isInlineRequest= */ true); - } + Consumer inlineSuggestionsRequestConsumer = + mAssistReceiver.newAutofillRequestLocked(viewState, + /* isInlineRequest= */ true); if (inlineSuggestionsRequestConsumer != null) { final AutofillId focusedId = mCurrentViewId; final int requestIdCopy = requestId; @@ -882,24 +842,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState ); viewState.setState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST); } - } else if (mSessionFlags.mClientSuggestionsEnabled) { - // Request client suggestions for the dropdown mode - onClientFillRequestLocked(requestId, null); } else { mAssistReceiver.newAutofillRequestLocked(viewState, /* isInlineRequest= */ false); } - if (mSessionFlags.mClientSuggestionsEnabled) { - // Using client suggestions, unnecessary request AssistStructure - return; - } - // Now request the assist structure data. - requestAssistStructureLocked(requestId, flags); - } - - @GuardedBy("mLock") - private void requestAssistStructureLocked(int requestId, int flags) { try { final Bundle receiverExtras = new Bundle(); receiverExtras.putInt(EXTRA_REQUEST_ID, requestId); @@ -948,13 +895,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mComponentName = componentName; mCompatMode = compatMode; mSessionState = STATE_ACTIVE; - synchronized (mLock) { mSessionFlags = new SessionFlags(); mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly; mSessionFlags.mInlineSupportedByService = mService.isInlineSuggestionsEnabledLocked(); - mSessionFlags.mClientSuggestionsEnabled = - (mFlags & FLAG_ENABLED_CLIENT_SUGGESTIONS) != 0; setClientLocked(client); } @@ -1066,13 +1010,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (requestLog != null) { requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1); } - processNullResponseOrFallbackLocked(requestId, requestFlags); + processNullResponseLocked(requestId, requestFlags); return; } fieldClassificationIds = response.getFieldClassificationIds(); - if (!mSessionFlags.mClientSuggestionsEnabled && fieldClassificationIds != null - && !mService.isFieldClassificationEnabledLocked()) { + if (fieldClassificationIds != null && !mService.isFieldClassificationEnabledLocked()) { Slog.w(TAG, "Ignoring " + response + " because field detection is disabled"); processNullResponseLocked(requestId, requestFlags); return; @@ -1151,26 +1094,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } - @GuardedBy("mLock") - private void processNullResponseOrFallbackLocked(int requestId, int flags) { - if (!mSessionFlags.mClientSuggestionsEnabled) { - processNullResponseLocked(requestId, flags); - return; - } - - // fallback to the default platform password manager - mSessionFlags.mClientSuggestionsEnabled = false; - - final InlineSuggestionsRequest inlineRequest = - (mLastInlineSuggestionsRequest != null - && mLastInlineSuggestionsRequest.first == requestId) - ? mLastInlineSuggestionsRequest.second : null; - mAssistReceiver.newAutofillRequestLocked(inlineRequest); - requestAssistStructureLocked(requestId, - flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS); - return; - } - // FillServiceCallbacks @Override public void onFillRequestFailure(int requestId, @Nullable CharSequence message) { @@ -3109,22 +3032,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState filterText = value.getTextValue().toString(); } - final CharSequence targetLabel; - final Drawable targetIcon; + final CharSequence serviceLabel; + final Drawable serviceIcon; synchronized (mLock) { - if (mSessionFlags.mClientSuggestionsEnabled) { - final ApplicationInfo appInfo = ClientSuggestionsSession.getAppInfo(mComponentName, - mService.getUserId()); - targetLabel = ClientSuggestionsSession.getAppLabelLocked( - mService.getMaster().getContext(), appInfo); - targetIcon = ClientSuggestionsSession.getAppIconLocked( - mService.getMaster().getContext(), appInfo); - } else { - targetLabel = mService.getServiceLabelLocked(); - targetIcon = mService.getServiceIconLocked(); - } + serviceLabel = mService.getServiceLabelLocked(); + serviceIcon = mService.getServiceIconLocked(); } - if (targetLabel == null || targetIcon == null) { + if (serviceLabel == null || serviceIcon == null) { wtf(null, "onFillReady(): no service label or icon"); return; } @@ -3144,7 +3058,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState getUiForShowing().showFillUi(filledId, response, filterText, mService.getServicePackageName(), mComponentName, - targetLabel, targetIcon, this, id, mCompatMode); + serviceLabel, serviceIcon, this, id, mCompatMode); mService.logDatasetShown(id, mClientState); @@ -3191,17 +3105,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return false; } - final InlineSuggestionsRequest request = inlineSuggestionsRequest.get(); - if (mSessionFlags.mClientSuggestionsEnabled && !request.isClientSupported() - || !mSessionFlags.mClientSuggestionsEnabled && !request.isServiceSupported()) { - if (sDebug) { - Slog.d(TAG, "Inline suggestions not supported for " - + (mSessionFlags.mClientSuggestionsEnabled ? "client" : "service") - + ". Falling back to dropdown."); - } - return false; - } - final RemoteInlineSuggestionRenderService remoteRenderService = mService.getRemoteInlineSuggestionRenderServiceLocked(); if (remoteRenderService == null) { @@ -3210,7 +3113,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } final InlineFillUi.InlineFillUiInfo inlineFillUiInfo = - new InlineFillUi.InlineFillUiInfo(request, focusedId, + new InlineFillUi.InlineFillUiInfo(inlineSuggestionsRequest.get(), focusedId, filterText, remoteRenderService, userId, id); InlineFillUi inlineFillUi = InlineFillUi.forAutofill(inlineFillUiInfo, response, new InlineFillUi.InlineSuggestionUiCallback() { @@ -3812,25 +3715,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } - @GuardedBy("mLock") - private void onClientFillRequestLocked(int requestId, - InlineSuggestionsRequest inlineSuggestionsRequest) { - if (mClientSuggestionsSession == null) { - mClientSuggestionsSession = new ClientSuggestionsSession(id, mClient, mHandler, - mComponentName, this); - } - - if (mContexts == null) { - mContexts = new ArrayList<>(1); - } - - if (inlineSuggestionsRequest != null && !inlineSuggestionsRequest.isClientSupported()) { - inlineSuggestionsRequest = null; - } - - mClientSuggestionsSession.onFillRequest(requestId, inlineSuggestionsRequest, mFlags); - } - /** * The result of checking whether to show the save dialog, when session can be saved. *