Merge "AF Inline: Notify the registered AutofillCallback, also fix filtering." into rvc-dev
This commit is contained in:
@@ -2590,8 +2590,26 @@ public final class AutofillManager {
|
||||
|
||||
private void notifyNoFillUi(int sessionId, AutofillId id, int sessionFinishedState) {
|
||||
if (sVerbose) {
|
||||
Log.v(TAG, "notifyNoFillUi(): sessionId=" + sessionId + ", autofillId=" + id
|
||||
+ ", sessionFinishedState=" + sessionFinishedState);
|
||||
Log.v(TAG, "notifyNoFillUi(): sessionFinishedState=" + sessionFinishedState);
|
||||
}
|
||||
final View anchor = findView(id);
|
||||
if (anchor == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
notifyCallback(sessionId, id, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
|
||||
|
||||
if (sessionFinishedState != STATE_UNKNOWN) {
|
||||
// Callback call was "hijacked" to also update the session state.
|
||||
setSessionFinished(sessionFinishedState, /* autofillableIds= */ null);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyCallback(
|
||||
int sessionId, AutofillId id, @AutofillCallback.AutofillEventType int event) {
|
||||
if (sVerbose) {
|
||||
Log.v(TAG, "notifyCallback(): sessionId=" + sessionId + ", autofillId=" + id
|
||||
+ ", event=" + event);
|
||||
}
|
||||
final View anchor = findView(id);
|
||||
if (anchor == null) {
|
||||
@@ -2607,17 +2625,12 @@ public final class AutofillManager {
|
||||
|
||||
if (callback != null) {
|
||||
if (id.isVirtualInt()) {
|
||||
callback.onAutofillEvent(anchor, id.getVirtualChildIntId(),
|
||||
AutofillCallback.EVENT_INPUT_UNAVAILABLE);
|
||||
callback.onAutofillEvent(
|
||||
anchor, id.getVirtualChildIntId(), event);
|
||||
} else {
|
||||
callback.onAutofillEvent(anchor, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
|
||||
callback.onAutofillEvent(anchor, event);
|
||||
}
|
||||
}
|
||||
|
||||
if (sessionFinishedState != STATE_UNKNOWN) {
|
||||
// Callback call was "hijacked" to also update the session state.
|
||||
setSessionFinished(sessionFinishedState, /* autofillableIds= */ null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3367,6 +3380,26 @@ public final class AutofillManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyFillUiShown(int sessionId, AutofillId id) {
|
||||
final AutofillManager afm = mAfm.get();
|
||||
if (afm != null) {
|
||||
afm.post(
|
||||
() -> afm.notifyCallback(
|
||||
sessionId, id, AutofillCallback.EVENT_INPUT_SHOWN));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyFillUiHidden(int sessionId, AutofillId id) {
|
||||
final AutofillManager afm = mAfm.get();
|
||||
if (afm != null) {
|
||||
afm.post(
|
||||
() -> afm.notifyCallback(
|
||||
sessionId, id, AutofillCallback.EVENT_INPUT_HIDDEN));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDisableAutofill(long disableDuration, ComponentName componentName)
|
||||
throws RemoteException {
|
||||
|
||||
@@ -78,6 +78,18 @@ oneway interface IAutoFillManagerClient {
|
||||
*/
|
||||
void notifyNoFillUi(int sessionId, in AutofillId id, int sessionFinishedState);
|
||||
|
||||
/**
|
||||
* Notifies that the fill UI was shown by the system (e.g. as inline chips in the keyboard).
|
||||
*/
|
||||
void notifyFillUiShown(int sessionId, in AutofillId id);
|
||||
|
||||
/**
|
||||
* Notifies that the fill UI previously shown by the system has been hidden by the system.
|
||||
*
|
||||
* @see #notifyFillUiShown
|
||||
*/
|
||||
void notifyFillUiHidden(int sessionId, in AutofillId id);
|
||||
|
||||
/**
|
||||
* Dispatches unhandled keyevent from autofill ui. Autofill ui handles DPAD and ENTER events,
|
||||
* other unhandled keyevents are dispatched to app's window to filter autofill result.
|
||||
|
||||
@@ -117,13 +117,14 @@ final class AutofillInlineSessionController {
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently delete the current inline fill UI. Notify the IME to hide the suggestions as
|
||||
* well.
|
||||
* Disables prefix/regex based filtering. Other filtering rules (see {@link
|
||||
* android.service.autofill.Dataset}) still apply.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
boolean deleteInlineFillUiLocked(@NonNull AutofillId autofillId) {
|
||||
mInlineFillUi = null;
|
||||
return hideInlineSuggestionsUiLocked(autofillId);
|
||||
void disableFilterMatching(@NonNull AutofillId autofillId) {
|
||||
if (mInlineFillUi != null && mInlineFillUi.getAutofillId().equals(autofillId)) {
|
||||
mInlineFillUi.disableFilterMatching();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2698,6 +2698,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
// TODO(b/156099633): remove this once framework gets out of business of resending
|
||||
// inline suggestions when IME visibility changes.
|
||||
mInlineSessionController.hideInlineSuggestionsUiLocked(viewState.id);
|
||||
try {
|
||||
mClient.notifyFillUiHidden(this.id, viewState.id);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Error requesting to hide fill UI", e);
|
||||
}
|
||||
viewState.resetState(ViewState.STATE_CHANGED);
|
||||
return;
|
||||
} else if ((viewState.id.equals(this.mCurrentViewId))
|
||||
@@ -2713,20 +2718,20 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
} else if (viewState.id.equals(this.mCurrentViewId)
|
||||
&& (viewState.getState() & ViewState.STATE_INLINE_SHOWN) != 0) {
|
||||
if ((viewState.getState() & ViewState.STATE_INLINE_DISABLED) != 0) {
|
||||
final FillResponse response = viewState.getResponse();
|
||||
if (response != null) {
|
||||
response.getDatasets().clear();
|
||||
}
|
||||
mInlineSessionController.deleteInlineFillUiLocked(viewState.id);
|
||||
} else {
|
||||
mInlineSessionController.filterInlineFillUiLocked(mCurrentViewId, filterText);
|
||||
mInlineSessionController.disableFilterMatching(viewState.id);
|
||||
}
|
||||
mInlineSessionController.filterInlineFillUiLocked(mCurrentViewId, filterText);
|
||||
} else if (viewState.id.equals(this.mCurrentViewId)
|
||||
&& (viewState.getState() & ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL) != 0) {
|
||||
if (!TextUtils.isEmpty(filterText)) {
|
||||
// TODO: we should be able to replace this with controller#filterInlineFillUiLocked
|
||||
// to accomplish filtering for augmented autofill.
|
||||
mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
|
||||
try {
|
||||
mClient.notifyFillUiHidden(this.id, mCurrentViewId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Error sending fill UI hidden notification", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2812,6 +2817,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
if (requestShowInlineSuggestionsLocked(response, filterText)) {
|
||||
final ViewState currentView = mViewStates.get(mCurrentViewId);
|
||||
currentView.setState(ViewState.STATE_INLINE_SHOWN);
|
||||
try {
|
||||
mClient.notifyFillUiShown(this.id, mCurrentViewId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Error sending fill UI shown notification", e);
|
||||
}
|
||||
//TODO(b/137800469): Fix it to log showed only when IME asks for inflation,
|
||||
// rather than here where framework sends back the response.
|
||||
mService.logDatasetShown(id, mClientState);
|
||||
@@ -2882,6 +2892,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
synchronized (mLock) {
|
||||
mInlineSessionController.hideInlineSuggestionsUiLocked(
|
||||
focusedId);
|
||||
try {
|
||||
mClient.notifyFillUiHidden(this.id, focusedId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Error sending fill UI hidden notification", e);
|
||||
}
|
||||
}
|
||||
}, remoteRenderService);
|
||||
return mInlineSessionController.setInlineFillUiLocked(inlineFillUi);
|
||||
@@ -3393,6 +3408,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
}
|
||||
if (mCurrentViewId != null) {
|
||||
mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
|
||||
try {
|
||||
mClient.notifyFillUiHidden(this.id, mCurrentViewId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Error sending fill UI hidden notification", e);
|
||||
}
|
||||
}
|
||||
autoFillApp(dataset);
|
||||
return;
|
||||
|
||||
@@ -83,6 +83,11 @@ public final class InlineFillUi {
|
||||
@Nullable
|
||||
private String mFilterText;
|
||||
|
||||
/**
|
||||
* Whether prefix/regex based filtering is disabled.
|
||||
*/
|
||||
private boolean mFilterMatchingDisabled;
|
||||
|
||||
/**
|
||||
* Returns an empty inline autofill UI.
|
||||
*/
|
||||
@@ -199,7 +204,7 @@ public final class InlineFillUi {
|
||||
continue;
|
||||
}
|
||||
if (!inlinePresentation.isPinned() // don't filter pinned suggestions
|
||||
&& !includeDataset(dataset, fieldIndex, mFilterText)) {
|
||||
&& !includeDataset(dataset, fieldIndex)) {
|
||||
continue;
|
||||
}
|
||||
inlineSuggestions.add(copy(i, mInlineSuggestions.get(i)));
|
||||
@@ -235,14 +240,13 @@ public final class InlineFillUi {
|
||||
}
|
||||
|
||||
// TODO: Extract the shared filtering logic here and in FillUi to a common method.
|
||||
private static boolean includeDataset(Dataset dataset, int fieldIndex,
|
||||
@Nullable String filterText) {
|
||||
private boolean includeDataset(Dataset dataset, int fieldIndex) {
|
||||
// Show everything when the user input is empty.
|
||||
if (TextUtils.isEmpty(filterText)) {
|
||||
if (TextUtils.isEmpty(mFilterText)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final String constraintLowerCase = filterText.toString().toLowerCase();
|
||||
final String constraintLowerCase = mFilterText.toString().toLowerCase();
|
||||
|
||||
// Use the filter provided by the service, if available.
|
||||
final Dataset.DatasetFieldFilter filter = dataset.getFilter(fieldIndex);
|
||||
@@ -252,7 +256,10 @@ public final class InlineFillUi {
|
||||
if (sVerbose) {
|
||||
Slog.v(TAG, "Explicitly disabling filter for dataset id" + dataset.getId());
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
if (mFilterMatchingDisabled) {
|
||||
return false;
|
||||
}
|
||||
return filterPattern.matcher(constraintLowerCase).matches();
|
||||
}
|
||||
@@ -261,10 +268,21 @@ public final class InlineFillUi {
|
||||
if (value == null || !value.isText()) {
|
||||
return dataset.getAuthentication() == null;
|
||||
}
|
||||
if (mFilterMatchingDisabled) {
|
||||
return false;
|
||||
}
|
||||
final String valueText = value.getTextValue().toString().toLowerCase();
|
||||
return valueText.toLowerCase().startsWith(constraintLowerCase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables prefix/regex based filtering. Other filtering rules (see {@link
|
||||
* android.service.autofill.Dataset}) still apply.
|
||||
*/
|
||||
public void disableFilterMatching() {
|
||||
mFilterMatchingDisabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback from the inline suggestion Ui.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user