Merge "Refactored ViewState." into oc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
817e838b16
@@ -63,6 +63,7 @@ import com.android.internal.os.HandlerCaller;
|
|||||||
import com.android.server.autofill.ui.AutoFillUI;
|
import com.android.server.autofill.ui.AutoFillUI;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
@@ -101,23 +102,25 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private final Map<AutofillId, ViewState> mViewStates = new ArrayMap<>();
|
private final Map<AutofillId, ViewState> mViewStates = new ArrayMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Id of the View currently being displayed.
|
||||||
|
*/
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
@Nullable
|
@Nullable private AutofillId mCurrentViewId;
|
||||||
private ViewState mCurrentViewState;
|
|
||||||
|
|
||||||
private final IAutoFillManagerClient mClient;
|
private final IAutoFillManagerClient mClient;
|
||||||
|
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
RemoteFillService mRemoteFillService;
|
RemoteFillService mRemoteFillService;
|
||||||
|
|
||||||
// TODO(b/33197203): Get a response per view instead of per activity.
|
// TODO(b/33197203 , b/35707731): Use List once it supports partitioning
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private FillResponse mCurrentResponse;
|
private FillResponse mCurrentResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to remember which {@link Dataset} filled the session.
|
* Used to remember which {@link Dataset} filled the session.
|
||||||
*/
|
*/
|
||||||
// TODO(b/33197203): might need more than one once we support partitions
|
// TODO(b/33197203 , b/35707731): might need more than one once it supports partitioning
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private Dataset mAutoFilledDataset;
|
private Dataset mAutoFilledDataset;
|
||||||
|
|
||||||
@@ -189,7 +192,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
processResponseLocked(response);
|
processResponseLocked(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogMaker log = (new LogMaker(MetricsEvent.AUTOFILL_REQUEST))
|
final LogMaker log = (new LogMaker(MetricsEvent.AUTOFILL_REQUEST))
|
||||||
.setType(MetricsEvent.TYPE_SUCCESS)
|
.setType(MetricsEvent.TYPE_SUCCESS)
|
||||||
.setPackageName(mPackageName)
|
.setPackageName(mPackageName)
|
||||||
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
|
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
|
||||||
@@ -292,8 +295,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
public void requestShowFillUi(AutofillId id, int width, int height,
|
public void requestShowFillUi(AutofillId id, int width, int height,
|
||||||
IAutofillWindowPresenter presenter) {
|
IAutofillWindowPresenter presenter) {
|
||||||
try {
|
try {
|
||||||
|
final ViewState currentView = mViewStates.get(mCurrentViewId);
|
||||||
mClient.requestShowFillUi(mWindowToken, id, width, height,
|
mClient.requestShowFillUi(mWindowToken, id, width, height,
|
||||||
mCurrentViewState.mVirtualBounds, presenter);
|
currentView.getVirtualBounds(), presenter);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.e(TAG, "Error requesting to show fill UI", e);
|
Slog.e(TAG, "Error requesting to show fill UI", e);
|
||||||
}
|
}
|
||||||
@@ -376,13 +380,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(b/33197203 , b/35707731): refactor excessive calls to getCurrentValue()
|
||||||
boolean allRequiredAreNotEmpty = true;
|
boolean allRequiredAreNotEmpty = true;
|
||||||
boolean atLeastOneChanged = false;
|
boolean atLeastOneChanged = false;
|
||||||
for (int i = 0; i < requiredIds.length; i++) {
|
for (int i = 0; i < requiredIds.length; i++) {
|
||||||
final AutofillId id = requiredIds[i];
|
final AutofillId id = requiredIds[i];
|
||||||
final ViewState state = mViewStates.get(id);
|
final ViewState state = mViewStates.get(id);
|
||||||
if (state == null || state.mAutofillValue == null
|
if (state == null || state.getCurrentValue() == null
|
||||||
|| state.mAutofillValue.isEmpty()) {
|
|| state.getCurrentValue().isEmpty()) {
|
||||||
final ViewNode node = findViewNodeByIdLocked(id);
|
final ViewNode node = findViewNodeByIdLocked(id);
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
Slog.w(TAG, "Service passed invalid id on SavableInfo: " + id);
|
Slog.w(TAG, "Service passed invalid id on SavableInfo: " + id);
|
||||||
@@ -398,20 +403,20 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (state.mValueUpdated) {
|
if (state.isChanged()) {
|
||||||
final AutofillValue filledValue = findValue(mAutoFilledDataset, id);
|
final AutofillValue filledValue = findValue(mAutoFilledDataset, id);
|
||||||
if (!state.mAutofillValue.equals(filledValue)) {
|
if (!state.getCurrentValue().equals(filledValue)) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "finishSessionLocked(): found a change on " + id + ": "
|
Slog.d(TAG, "finishSessionLocked(): found a change on " + id + ": "
|
||||||
+ filledValue + " => " + state.mAutofillValue);
|
+ filledValue + " => " + state.getCurrentValue());
|
||||||
}
|
}
|
||||||
atLeastOneChanged = true;
|
atLeastOneChanged = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (state.mAutofillValue == null || state.mAutofillValue.isEmpty()) {
|
if (state.getCurrentValue() == null || state.getCurrentValue().isEmpty()) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "finishSessionLocked(): empty value for " + id + ": "
|
Slog.d(TAG, "finishSessionLocked(): empty value for " + id + ": "
|
||||||
+ state.mAutofillValue);
|
+ state.getCurrentValue());
|
||||||
}
|
}
|
||||||
allRequiredAreNotEmpty = false;
|
allRequiredAreNotEmpty = false;
|
||||||
break;
|
break;
|
||||||
@@ -425,13 +430,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
for (int i = 0; i < saveInfo.getOptionalIds().length; i++) {
|
for (int i = 0; i < saveInfo.getOptionalIds().length; i++) {
|
||||||
final AutofillId id = saveInfo.getOptionalIds()[i];
|
final AutofillId id = saveInfo.getOptionalIds()[i];
|
||||||
final ViewState state = mViewStates.get(id);
|
final ViewState state = mViewStates.get(id);
|
||||||
if (state != null && state.mAutofillValue != null && state.mValueUpdated) {
|
if (state != null && state.getCurrentValue() != null && state.isChanged()) {
|
||||||
final AutofillValue filledValue = findValue(mAutoFilledDataset, id);
|
final AutofillValue filledValue = findValue(mAutoFilledDataset, id);
|
||||||
if (!state.mAutofillValue.equals(filledValue)) {
|
if (!state.getCurrentValue().equals(filledValue)) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "finishSessionLocked(): found a change on optional "
|
Slog.d(TAG, "finishSessionLocked(): found a change on optional "
|
||||||
+ id + ": " + filledValue + " => "
|
+ id + ": " + filledValue + " => "
|
||||||
+ state.mAutofillValue);
|
+ state.getCurrentValue());
|
||||||
}
|
}
|
||||||
atLeastOneChanged = true;
|
atLeastOneChanged = true;
|
||||||
break;
|
break;
|
||||||
@@ -464,7 +469,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
final Bundle extras = this.mCurrentResponse.getExtras();
|
final Bundle extras = this.mCurrentResponse.getExtras();
|
||||||
|
|
||||||
for (Entry<AutofillId, ViewState> entry : mViewStates.entrySet()) {
|
for (Entry<AutofillId, ViewState> entry : mViewStates.entrySet()) {
|
||||||
final AutofillValue value = entry.getValue().mAutofillValue;
|
final AutofillValue value = entry.getValue().getCurrentValue();
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
if (VERBOSE) {
|
if (VERBOSE) {
|
||||||
Slog.v(TAG, "callSaveLocked(): skipping " + entry.getKey());
|
Slog.v(TAG, "callSaveLocked(): skipping " + entry.getKey());
|
||||||
@@ -498,39 +503,43 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
void updateLocked(AutofillId id, Rect virtualBounds, AutofillValue value, int flags) {
|
void updateLocked(AutofillId id, Rect virtualBounds, AutofillValue value, int flags) {
|
||||||
if (mAutoFilledDataset != null && (flags & FLAG_VALUE_CHANGED) == 0) {
|
if (mAutoFilledDataset != null && (flags & FLAG_VALUE_CHANGED) == 0) {
|
||||||
// TODO(b/33197203): ignoring because we don't support partitions yet
|
// TODO(b/33197203): ignoring because we don't support partitions yet
|
||||||
Slog.d(TAG, "updateLocked(): ignoring " + flags + " after app was autofilled");
|
Slog.d(TAG, "updateLocked(): ignoring " + id + " after app was autofilled");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewState viewState = mViewStates.get(id);
|
ViewState viewState = mViewStates.get(id);
|
||||||
if (viewState == null) {
|
if (viewState == null) {
|
||||||
viewState = new ViewState(this, id, this);
|
viewState = new ViewState(this, id, this, ViewState.STATE_INITIAL);
|
||||||
mViewStates.put(id, viewState);
|
mViewStates.put(id, viewState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & FLAG_START_SESSION) != 0) {
|
if ((flags & FLAG_START_SESSION) != 0) {
|
||||||
// View is triggering autofill.
|
// View is triggering autofill.
|
||||||
mCurrentViewState = viewState;
|
mCurrentViewId = viewState.id;
|
||||||
viewState.update(value, virtualBounds);
|
viewState.update(value, virtualBounds);
|
||||||
|
viewState.setState(ViewState.STATE_STARTED_SESSION);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & FLAG_VALUE_CHANGED) != 0) {
|
if ((flags & FLAG_VALUE_CHANGED) != 0) {
|
||||||
if (value != null && !value.equals(viewState.mAutofillValue)) {
|
if (value != null && !value.equals(viewState.getCurrentValue())) {
|
||||||
viewState.mValueUpdated = true;
|
|
||||||
|
// TODO(b/33197203 , b/35707731): currently resets STATE_AUTOFILLED; should check
|
||||||
|
// first (doesn't make a difference now, but it will when it supports partitions)
|
||||||
|
viewState.setState(ViewState.STATE_CHANGED);
|
||||||
|
|
||||||
// Must check if this update was caused by autofilling the view, in which
|
// Must check if this update was caused by autofilling the view, in which
|
||||||
// case we just update the value, but not the UI.
|
// case we just update the value, but not the UI.
|
||||||
if (mAutoFilledDataset != null) {
|
if (mAutoFilledDataset != null) {
|
||||||
final AutofillValue filledValue = findValue(mAutoFilledDataset, id);
|
final AutofillValue filledValue = findValue(mAutoFilledDataset, id);
|
||||||
if (value.equals(filledValue)) {
|
if (value.equals(filledValue)) {
|
||||||
viewState.mAutofillValue = value;
|
viewState.setCurrentValue(value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change value
|
// Change value
|
||||||
viewState.mAutofillValue = value;
|
viewState.setCurrentValue(value);
|
||||||
|
|
||||||
// Update the chooser UI
|
// Update the chooser UI
|
||||||
if (value.isText()) {
|
if (value.isText()) {
|
||||||
@@ -545,15 +554,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
|
|
||||||
if ((flags & FLAG_VIEW_ENTERED) != 0) {
|
if ((flags & FLAG_VIEW_ENTERED) != 0) {
|
||||||
// Remove the UI if the ViewState has changed.
|
// Remove the UI if the ViewState has changed.
|
||||||
if (mCurrentViewState != viewState) {
|
if (mCurrentViewId != viewState.id) {
|
||||||
mUi.hideFillUi(mCurrentViewState != null ? mCurrentViewState.mId : null);
|
mUi.hideFillUi(mCurrentViewId != null ? mCurrentViewId : null);
|
||||||
mCurrentViewState = viewState;
|
mCurrentViewId = viewState.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the ViewState is ready to be displayed, onReady() will be called.
|
// If the ViewState is ready to be displayed, onReady() will be called.
|
||||||
viewState.update(value, virtualBounds);
|
viewState.update(value, virtualBounds);
|
||||||
|
|
||||||
// TODO(b/33197203): Remove when there is a response per activity.
|
|
||||||
if (mCurrentResponse != null) {
|
if (mCurrentResponse != null) {
|
||||||
viewState.setResponse(mCurrentResponse);
|
viewState.setResponse(mCurrentResponse);
|
||||||
}
|
}
|
||||||
@@ -562,9 +570,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & FLAG_VIEW_EXITED) != 0) {
|
if ((flags & FLAG_VIEW_EXITED) != 0) {
|
||||||
if (mCurrentViewState == viewState) {
|
if (mCurrentViewId == viewState.id) {
|
||||||
mUi.hideFillUi(viewState.mId);
|
mUi.hideFillUi(viewState.id);
|
||||||
mCurrentViewState = null;
|
mCurrentViewId = null;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -584,17 +592,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void notifyUnavailableToClient() {
|
private void notifyUnavailableToClient() {
|
||||||
if (mCurrentViewState == null) {
|
if (mCurrentViewId == null) {
|
||||||
// TODO(b/33197203): temporary sanity check; should never happen
|
// TODO(b/33197203): temporary sanity check; should never happen
|
||||||
Slog.w(TAG, "notifyUnavailable(): mCurrentViewState is null");
|
Slog.w(TAG, "notifyUnavailable(): mCurrentViewId is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!mHasCallback) return;
|
if (!mHasCallback) return;
|
||||||
try {
|
try {
|
||||||
mClient.notifyNoFillUi(mWindowToken, mCurrentViewState.mId);
|
mClient.notifyNoFillUi(mWindowToken, mCurrentViewId);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.e(TAG, "Error notifying client no fill UI: windowToken=" + mWindowToken
|
Slog.e(TAG, "Error notifying client no fill UI: windowToken=" + mWindowToken
|
||||||
+ " id=" + mCurrentViewState.mId, e);
|
+ " id=" + mCurrentViewId, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,21 +612,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
+ "):" + response);
|
+ "):" + response);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCurrentViewState == null) {
|
if (mCurrentViewId == null) {
|
||||||
// TODO(b/33197203): temporary sanity check; should never happen
|
// TODO(b/33197203): temporary sanity check; should never happen
|
||||||
Slog.w(TAG, "processResponseLocked(): mCurrentViewState is null");
|
Slog.w(TAG, "processResponseLocked(): mCurrentViewId is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mCurrentResponse = response;
|
mCurrentResponse = response;
|
||||||
|
|
||||||
if (mCurrentResponse.getAuthentication() != null) {
|
setViewStatesLocked(response, ViewState.STATE_FILLABLE);
|
||||||
// Handle authentication.
|
|
||||||
final Intent fillInIntent = createAuthFillInIntent(mStructure,
|
|
||||||
mCurrentResponse.getExtras());
|
|
||||||
mCurrentViewState.setResponse(mCurrentResponse, fillInIntent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((mFlags & FLAG_MANUAL_REQUEST) != 0 && response.getDatasets() != null
|
if ((mFlags & FLAG_MANUAL_REQUEST) != 0 && response.getDatasets() != null
|
||||||
&& response.getDatasets().size() == 1) {
|
&& response.getDatasets().size() == 1) {
|
||||||
@@ -627,7 +629,50 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mCurrentViewState.setResponse(mCurrentResponse);
|
// Updates the UI, if necessary.
|
||||||
|
final ViewState currentView = mViewStates.get(mCurrentViewId);
|
||||||
|
currentView.maybeCallOnFillReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the state of all views in the given response.
|
||||||
|
*/
|
||||||
|
private void setViewStatesLocked(FillResponse response, int state) {
|
||||||
|
final ArrayList<Dataset> datasets = response.getDatasets();
|
||||||
|
if (datasets != null) {
|
||||||
|
for (int i = 0; i < datasets.size(); i++) {
|
||||||
|
final Dataset dataset = datasets.get(i);
|
||||||
|
if (dataset == null) {
|
||||||
|
Slog.w(TAG, "Ignoring null dataset on " + datasets);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
setViewStatesLocked(response, dataset, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the state of all views in the given dataset and response.
|
||||||
|
*/
|
||||||
|
private void setViewStatesLocked(@Nullable FillResponse response, @NonNull Dataset dataset,
|
||||||
|
int state) {
|
||||||
|
final ArrayList<AutofillId> ids = dataset.getFieldIds();
|
||||||
|
for (int j = 0; j < ids.size(); j++) {
|
||||||
|
final AutofillId id = ids.get(j);
|
||||||
|
ViewState viewState = mViewStates.get(id);
|
||||||
|
if (viewState != null) {
|
||||||
|
viewState.setState(state);
|
||||||
|
} else {
|
||||||
|
viewState = new ViewState(this, id, this, state);
|
||||||
|
if (DEBUG) { // TODO(b/33197203): change to VERBOSE once stable
|
||||||
|
Slog.d(TAG, "Adding autofillable view with id " + id + " and state " + state);
|
||||||
|
}
|
||||||
|
mViewStates.put(id, viewState);
|
||||||
|
}
|
||||||
|
if (response != null) {
|
||||||
|
viewState.setResponse(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void autoFill(Dataset dataset) {
|
void autoFill(Dataset dataset) {
|
||||||
@@ -650,6 +695,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
return mService.getServiceName();
|
return mService.getServiceName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FillResponse getCurrentResponse() {
|
||||||
|
return mCurrentResponse;
|
||||||
|
}
|
||||||
|
|
||||||
private Intent createAuthFillInIntent(AssistStructure structure, Bundle extras) {
|
private Intent createAuthFillInIntent(AssistStructure structure, Bundle extras) {
|
||||||
final Intent fillInIntent = new Intent();
|
final Intent fillInIntent = new Intent();
|
||||||
fillInIntent.putExtra(AutofillManager.EXTRA_ASSIST_STRUCTURE, structure);
|
fillInIntent.putExtra(AutofillManager.EXTRA_ASSIST_STRUCTURE, structure);
|
||||||
@@ -672,8 +721,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
pw.print(prefix); pw.print("mFlags: "); pw.println(mFlags);
|
pw.print(prefix); pw.print("mFlags: "); pw.println(mFlags);
|
||||||
pw.print(prefix); pw.print("mCurrentResponse: "); pw.println(mCurrentResponse);
|
pw.print(prefix); pw.print("mCurrentResponse: "); pw.println(mCurrentResponse);
|
||||||
pw.print(prefix); pw.print("mAutoFilledDataset: "); pw.println(mAutoFilledDataset);
|
pw.print(prefix); pw.print("mAutoFilledDataset: "); pw.println(mAutoFilledDataset);
|
||||||
pw.print(prefix); pw.print("mCurrentViewStates: "); pw.println(mCurrentViewState);
|
pw.print(prefix); pw.print("mCurrentViewId: "); pw.println(mCurrentViewId);
|
||||||
pw.print(prefix); pw.print("mViewStates: "); pw.println(mViewStates.size());
|
pw.print(prefix); pw.print("mViewStates size: "); pw.println(mViewStates.size());
|
||||||
final String prefix2 = prefix + " ";
|
final String prefix2 = prefix + " ";
|
||||||
for (Map.Entry<AutofillId, ViewState> entry : mViewStates.entrySet()) {
|
for (Map.Entry<AutofillId, ViewState> entry : mViewStates.entrySet()) {
|
||||||
pw.print(prefix); pw.print("State for id "); pw.println(entry.getKey());
|
pw.print(prefix); pw.print("State for id "); pw.println(entry.getKey());
|
||||||
@@ -700,6 +749,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
|||||||
Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
|
Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
|
||||||
}
|
}
|
||||||
mClient.autofill(mWindowToken, dataset.getFieldIds(), dataset.getFieldValues());
|
mClient.autofill(mWindowToken, dataset.getFieldIds(), dataset.getFieldValues());
|
||||||
|
setViewStatesLocked(null, dataset, ViewState.STATE_AUTOFILLED);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.w(TAG, "Error autofilling activity: " + e);
|
Slog.w(TAG, "Error autofilling activity: " + e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
package com.android.server.autofill;
|
package com.android.server.autofill;
|
||||||
|
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.service.autofill.FillResponse;
|
import android.service.autofill.FillResponse;
|
||||||
|
import android.util.DebugUtils;
|
||||||
import android.view.autofill.AutofillId;
|
import android.view.autofill.AutofillId;
|
||||||
import android.view.autofill.AutofillValue;
|
import android.view.autofill.AutofillValue;
|
||||||
|
|
||||||
@@ -40,55 +40,92 @@ final class ViewState {
|
|||||||
@Nullable AutofillValue value);
|
@Nullable AutofillValue value);
|
||||||
}
|
}
|
||||||
|
|
||||||
final AutofillId mId;
|
// NOTE: state constants must be public because of flagstoString().
|
||||||
|
public static final int STATE_UNKNOWN = 0x00;
|
||||||
|
/** Initial state. */
|
||||||
|
public static final int STATE_INITIAL = 0x01;
|
||||||
|
/** View id is present in a dataset returned by the service. */
|
||||||
|
public static final int STATE_FILLABLE = 0x02;
|
||||||
|
/** View was autofilled after user selected a dataset. */
|
||||||
|
public static final int STATE_AUTOFILLED = 0x04;
|
||||||
|
/** View value was changed, but not by the service. */
|
||||||
|
public static final int STATE_CHANGED = 0x08;
|
||||||
|
/** Set only in the View that started a session . */
|
||||||
|
public static final int STATE_STARTED_SESSION = 0x10;
|
||||||
|
|
||||||
|
public final AutofillId id;
|
||||||
private final Listener mListener;
|
private final Listener mListener;
|
||||||
// TODO(b/33197203): would not need a reference to response and session if it was an inner
|
|
||||||
// class of Session...
|
|
||||||
private final Session mSession;
|
private final Session mSession;
|
||||||
private FillResponse mResponse;
|
private FillResponse mResponse;
|
||||||
private Intent mAuthIntent;
|
|
||||||
|
|
||||||
// TODO(b/33197203): encapsulate access so it's not called by UI
|
private AutofillValue mCurrentValue;
|
||||||
AutofillValue mAutofillValue;
|
private Rect mVirtualBounds;
|
||||||
|
|
||||||
// TODO(b/33197203): encapsulate access so it's not called by UI
|
private int mState;
|
||||||
// Bounds if a virtual view, null otherwise
|
|
||||||
Rect mVirtualBounds;
|
|
||||||
|
|
||||||
boolean mValueUpdated;
|
ViewState(Session session, AutofillId id, Listener listener, int state) {
|
||||||
|
|
||||||
ViewState(Session session, AutofillId id, Listener listener) {
|
|
||||||
mSession = session;
|
mSession = session;
|
||||||
mId = id;
|
this.id = id;
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
|
mState = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Response should only be set once.
|
* Gets the boundaries of the virtual view, or {@code null} if the the view is not virtual.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
|
Rect getVirtualBounds() {
|
||||||
|
return mVirtualBounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current value of the view.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
AutofillValue getCurrentValue() {
|
||||||
|
return mCurrentValue;
|
||||||
|
}
|
||||||
|
|
||||||
void setResponse(FillResponse response) {
|
void setResponse(FillResponse response) {
|
||||||
mResponse = response;
|
mResponse = response;
|
||||||
maybeCallOnFillReady();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
FillResponse getResponse() {
|
||||||
* Used when a {@link FillResponse} requires authentication to be unlocked.
|
return mResponse;
|
||||||
*/
|
|
||||||
void setResponse(FillResponse response, Intent authIntent) {
|
|
||||||
mAuthIntent = authIntent;
|
|
||||||
setResponse(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CharSequence getServiceName() {
|
CharSequence getServiceName() {
|
||||||
return mSession.getServiceName();
|
return mSession.getServiceName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isChanged() {
|
||||||
|
return (mState & STATE_CHANGED) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getState() {
|
||||||
|
return mState;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getStateAsString() {
|
||||||
|
return DebugUtils.flagsToString(ViewState.class, "STATE_", mState);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCurrentValue(AutofillValue value) {
|
||||||
|
mCurrentValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setState(int state) {
|
||||||
|
// TODO(b/33197203 , b/35707731): currently it's always setting one state, but once it
|
||||||
|
// supports partitioning it will need to 'or' some of them..
|
||||||
|
mState = state;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(b/33197203): need to refactor / rename / document this method to make it clear that
|
// TODO(b/33197203): need to refactor / rename / document this method to make it clear that
|
||||||
// it can change the value and update the UI; similarly, should replace code that
|
// it can change the value and update the UI; similarly, should replace code that
|
||||||
// directly sets mAutoFilLValue to use encapsulation.
|
// directly sets mAutoFilLValue to use encapsulation.
|
||||||
void update(@Nullable AutofillValue autofillValue, @Nullable Rect virtualBounds) {
|
void update(@Nullable AutofillValue autofillValue, @Nullable Rect virtualBounds) {
|
||||||
if (autofillValue != null) {
|
if (autofillValue != null) {
|
||||||
mAutofillValue = autofillValue;
|
mCurrentValue = autofillValue;
|
||||||
}
|
}
|
||||||
if (virtualBounds != null) {
|
if (virtualBounds != null) {
|
||||||
mVirtualBounds = virtualBounds;
|
mVirtualBounds = virtualBounds;
|
||||||
@@ -103,23 +140,31 @@ final class ViewState {
|
|||||||
* fill UI is ready to be displayed (i.e. when response and bounds are set).
|
* fill UI is ready to be displayed (i.e. when response and bounds are set).
|
||||||
*/
|
*/
|
||||||
void maybeCallOnFillReady() {
|
void maybeCallOnFillReady() {
|
||||||
if (mResponse != null && (mResponse.getAuthentication() != null
|
// First try the current response associated with this View.
|
||||||
|| mResponse.getDatasets() != null)) {
|
if (mResponse != null) {
|
||||||
mListener.onFillReady(mResponse, mId, mAutofillValue);
|
if (mResponse.getDatasets() != null) {
|
||||||
|
mListener.onFillReady(mResponse, this.id, mCurrentValue);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Then checks if the session has a response waiting authentication; if so, uses it instead.
|
||||||
|
final FillResponse currentResponse = mSession.getCurrentResponse();
|
||||||
|
if (currentResponse.getAuthentication() != null) {
|
||||||
|
mListener.onFillReady(currentResponse, this.id, mCurrentValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ViewState: [id=" + mId + ", value=" + mAutofillValue + ", bounds=" + mVirtualBounds
|
return "ViewState: [id=" + id + ", currentValue=" + mCurrentValue
|
||||||
+ ", updated = " + mValueUpdated + "]";
|
+ ", bounds=" + mVirtualBounds + ", state=" + getStateAsString() +"]";
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump(String prefix, PrintWriter pw) {
|
void dump(String prefix, PrintWriter pw) {
|
||||||
pw.print(prefix); pw.print("id:" ); pw.println(mId);
|
pw.print(prefix); pw.print("id:" ); pw.println(this.id);
|
||||||
pw.print(prefix); pw.print("value:" ); pw.println(mAutofillValue);
|
pw.print(prefix); pw.print("state:" ); pw.println(getStateAsString());
|
||||||
pw.print(prefix); pw.print("updated:" ); pw.println(mValueUpdated);
|
pw.print(prefix); pw.print("has response:" ); pw.println(mResponse != null);
|
||||||
|
pw.print(prefix); pw.print("currentValue:" ); pw.println(mCurrentValue);
|
||||||
pw.print(prefix); pw.print("virtualBounds:" ); pw.println(mVirtualBounds);
|
pw.print(prefix); pw.print("virtualBounds:" ); pw.println(mVirtualBounds);
|
||||||
pw.print(prefix); pw.print("authIntent:" ); pw.println(mAuthIntent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user