Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f7fd183 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topics 'bug_62802026_take_2', 'bug_62802026' into oc-dev

* changes:
  Don't add FillEventHistory events to the wrong session.
  Fixed how FillEventHistory is reset and clarified javadoc.
parents 0f98ddaa d013bcea
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -208,12 +208,22 @@ public abstract class AutofillService extends Service {
    }

    /**
     * Returns the {@link FillEventHistory.Event events} since the last {@link FillResponse} was
     * returned.
     * Gets the events that happened after the last
     * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
     * call.
     *
     * <p>The history is not persisted over reboots.
     * <p>This method is typically used to keep track of previous user actions to optimize further
     * requests. For example, the service might return email addresses in alphabetical order by
     * default, but change that order based on the address the user picked on previous requests.
     *
     * @return The history or {@code null} if there are not events.
     * <p>The history is not persisted over reboots, and it's cleared every time the service
     * replies to a {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} by calling
     * {@link FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)}
     * (if the service doesn't call any of these methods, the history will clear out after some
     * pre-defined time). Hence, the service should call {@link #getFillEventHistory()} before
     * finishing the {@link FillCallback}.
     *
     * @return The history or {@code null} if there are no events.
     */
    @Nullable public final FillEventHistory getFillEventHistory() {
        AutofillManager afm = getSystemService(AutofillManager.class);
+31 −5
Original line number Diff line number Diff line
@@ -33,7 +33,20 @@ import java.util.ArrayList;
import java.util.List;

/**
 * Describes what happened after the latest call to {@link FillCallback#onSuccess(FillResponse)}.
 * Describes what happened after the last
 * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
 * call.
 *
 * <p>This history is typically used to keep track of previous user actions to optimize further
 * requests. For example, the service might return email addresses in alphabetical order by
 * default, but change that order based on the address the user picked on previous requests.
 *
 * <p>The history is not persisted over reboots, and it's cleared every time the service
 * replies to a
 * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
 * by calling {@link FillCallback#onSuccess(FillResponse)} or
 * {@link FillCallback#onFailure(CharSequence)} (if the service doesn't call any of these methods,
 * the history will clear out after some pre-defined time).
 */
public final class FillEventHistory implements Parcelable {
    /**
@@ -41,6 +54,11 @@ public final class FillEventHistory implements Parcelable {
     */
    private final int mServiceUid;

    /**
     * Not in parcel. The ID of the autofill session that created the {@link FillResponse}.
     */
    private final int mSessionId;

    @Nullable private final Bundle mClientState;
    @Nullable List<Event> mEvents;

@@ -55,10 +73,17 @@ public final class FillEventHistory implements Parcelable {
        return mServiceUid;
    }

    /** @hide */
    public int getSessionId() {
        return mSessionId;
    }

    /**
     * Returns the client state of the {@link FillResponse}.
     * Returns the client state set in the previous {@link FillResponse}.
     *
     * @return The client state set by the last {@link FillResponse}
     * <p><b>NOTE: </b>the state is associated with the app that was autofilled in the previous
     * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
     * , which is not necessary the same app being autofilled now.
     */
    @Nullable public Bundle getClientState() {
        return mClientState;
@@ -87,9 +112,10 @@ public final class FillEventHistory implements Parcelable {
    /**
     * @hide
     */
    public FillEventHistory(int serviceUid, @Nullable Bundle clientState) {
    public FillEventHistory(int serviceUid, int sessionId, @Nullable Bundle clientState) {
        mClientState = clientState;
        mServiceUid = serviceUid;
        mSessionId = sessionId;
    }

    @Override
@@ -190,7 +216,7 @@ public final class FillEventHistory implements Parcelable {
            new Parcelable.Creator<FillEventHistory>() {
                @Override
                public FillEventHistory createFromParcel(Parcel parcel) {
                    FillEventHistory selection = new FillEventHistory(0, parcel.readBundle());
                    FillEventHistory selection = new FillEventHistory(0, 0, parcel.readBundle());

                    int numEvents = parcel.readInt();
                    for (int i = 0; i < numEvents; i++) {
+43 −11
Original line number Diff line number Diff line
@@ -489,48 +489,80 @@ final class AutofillManagerServiceImpl {
     * Initializes the last fill selection after an autofill service returned a new
     * {@link FillResponse}.
     */
    void setLastResponse(int serviceUid, @NonNull FillResponse response) {
    void setLastResponse(int serviceUid, int sessionId, @NonNull FillResponse response) {
        synchronized (mLock) {
            mEventHistory = new FillEventHistory(serviceUid, response.getClientState());
            mEventHistory = new FillEventHistory(serviceUid, sessionId, response.getClientState());
        }
    }

    /**
     * Resets the last fill selection.
     */
    void resetLastResponse() {
        synchronized (mLock) {
            mEventHistory = null;
        }
    }

    private boolean isValidEventLocked(String method, int sessionId) {
        if (mEventHistory == null) {
            Slog.w(TAG, method + ": not logging event because history is null");
            return false;
        }
        if (sessionId != mEventHistory.getSessionId()) {
            if (sDebug) {
                Slog.d(TAG, method + ": not logging event for session " + sessionId
                        + " because tracked session is " + mEventHistory.getSessionId());
            }
            return false;
        }
        return true;
    }

    /**
     * Updates the last fill selection when an authentication was selected.
     */
    void setAuthenticationSelected() {
    void setAuthenticationSelected(int sessionId) {
        synchronized (mLock) {
            if (isValidEventLocked("setAuthenticationSelected()", sessionId)) {
                mEventHistory.addEvent(new Event(Event.TYPE_AUTHENTICATION_SELECTED, null));
            }
        }
    }

    /**
     * Updates the last fill selection when an dataset authentication was selected.
     */
    void setDatasetAuthenticationSelected(@Nullable String selectedDataset) {
    void setDatasetAuthenticationSelected(@Nullable String selectedDataset, int sessionId) {
        synchronized (mLock) {
            if (isValidEventLocked("setDatasetAuthenticationSelected()", sessionId)) {
                mEventHistory.addEvent(
                        new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset));
            }
        }
    }

    /**
     * Updates the last fill selection when an save Ui is shown.
     */
    void setSaveShown() {
    void setSaveShown(int sessionId) {
        synchronized (mLock) {
            if (isValidEventLocked("setSaveShown()", sessionId)) {
                mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null));
            }
        }
    }

    /**
     * Updates the last fill response when a dataset was selected.
     */
    void setDatasetSelected(@Nullable String selectedDataset) {
    void setDatasetSelected(@Nullable String selectedDataset, int sessionId) {
        synchronized (mLock) {
            if (isValidEventLocked("setDatasetSelected()", sessionId)) {
                mEventHistory.addEvent(new Event(Event.TYPE_DATASET_SELECTED, selectedDataset));
            }
        }
    }

    /**
     * Gets the fill event history.
+1 −0
Original line number Diff line number Diff line
@@ -427,6 +427,7 @@ final class RemoteFillService implements DeathRecipient {
                    mCompleted = true;
                }

                Slog.w(LOG_TAG, getClass().getSimpleName() + " timed out");
                final RemoteFillService remoteService = mWeakService.get();
                if (remoteService != null) {
                    fail(remoteService);
+7 −5
Original line number Diff line number Diff line
@@ -407,13 +407,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            if ((requestFlags & FLAG_MANUAL_REQUEST) != 0) {
                getUiForShowing().showError(R.string.autofill_error_cannot_autofill, this);
            }
            mService.resetLastResponse();
            // Nothing to be done, but need to notify client.
            notifyUnavailableToClient();
            removeSelf();
            return;
        }

        mService.setLastResponse(serviceUid, response);
        mService.setLastResponse(serviceUid, id, response);

        if ((response.getDatasets() == null || response.getDatasets().isEmpty())
                        && response.getAuthentication() == null) {
@@ -444,6 +445,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                        + id + " destroyed");
                return;
            }
            mService.resetLastResponse();
        }
        LogMaker log = (new LogMaker(MetricsEvent.AUTOFILL_REQUEST))
                .setType(MetricsEvent.TYPE_FAILURE)
@@ -542,7 +544,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                    getFillContextByRequestIdLocked(requestId).getStructure(), extras);
        }

        mService.setAuthenticationSelected();
        mService.setAuthenticationSelected(id);

        final int authenticationId = AutofillManager.makeAuthenticationId(requestId, datasetIndex);
        mHandlerCaller.getHandler().post(() -> startAuthentication(authenticationId,
@@ -831,7 +833,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            }
            if (atLeastOneChanged) {
                if (sDebug) Slog.d(TAG, "at least one field changed - showing save UI");
                mService.setSaveShown();
                mService.setSaveShown(id);
                getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName,
                        this);

@@ -1362,14 +1364,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            }
            // Autofill it directly...
            if (dataset.getAuthentication() == null) {
                mService.setDatasetSelected(dataset.getId());
                mService.setDatasetSelected(dataset.getId(), id);

                autoFillApp(dataset);
                return;
            }

            // ...or handle authentication.
            mService.setDatasetAuthenticationSelected(dataset.getId());
            mService.setDatasetAuthenticationSelected(dataset.getId(), id);
            setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false);
            final Intent fillInIntent = createAuthFillInIntent(
                    getFillContextByRequestIdLocked(requestId).getStructure(), mClientState);