Skip to content

Commit 7f35707

Browse files
aha-googAndroid (Google) Code Review
authored andcommitted
Merge "AF Inline: Notify the registered AutofillCallback, also fix filtering." into rvc-dev
2 parents 9dace76 + 974c311 commit 7f35707

5 files changed

Lines changed: 112 additions & 28 deletions

File tree

core/java/android/view/autofill/AutofillManager.java

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2590,8 +2590,26 @@ void notifyReenableAutofill() {
25902590

25912591
private void notifyNoFillUi(int sessionId, AutofillId id, int sessionFinishedState) {
25922592
if (sVerbose) {
2593-
Log.v(TAG, "notifyNoFillUi(): sessionId=" + sessionId + ", autofillId=" + id
2594-
+ ", sessionFinishedState=" + sessionFinishedState);
2593+
Log.v(TAG, "notifyNoFillUi(): sessionFinishedState=" + sessionFinishedState);
2594+
}
2595+
final View anchor = findView(id);
2596+
if (anchor == null) {
2597+
return;
2598+
}
2599+
2600+
notifyCallback(sessionId, id, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
2601+
2602+
if (sessionFinishedState != STATE_UNKNOWN) {
2603+
// Callback call was "hijacked" to also update the session state.
2604+
setSessionFinished(sessionFinishedState, /* autofillableIds= */ null);
2605+
}
2606+
}
2607+
2608+
private void notifyCallback(
2609+
int sessionId, AutofillId id, @AutofillCallback.AutofillEventType int event) {
2610+
if (sVerbose) {
2611+
Log.v(TAG, "notifyCallback(): sessionId=" + sessionId + ", autofillId=" + id
2612+
+ ", event=" + event);
25952613
}
25962614
final View anchor = findView(id);
25972615
if (anchor == null) {
@@ -2607,17 +2625,12 @@ private void notifyNoFillUi(int sessionId, AutofillId id, int sessionFinishedSta
26072625

26082626
if (callback != null) {
26092627
if (id.isVirtualInt()) {
2610-
callback.onAutofillEvent(anchor, id.getVirtualChildIntId(),
2611-
AutofillCallback.EVENT_INPUT_UNAVAILABLE);
2628+
callback.onAutofillEvent(
2629+
anchor, id.getVirtualChildIntId(), event);
26122630
} else {
2613-
callback.onAutofillEvent(anchor, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
2631+
callback.onAutofillEvent(anchor, event);
26142632
}
26152633
}
2616-
2617-
if (sessionFinishedState != STATE_UNKNOWN) {
2618-
// Callback call was "hijacked" to also update the session state.
2619-
setSessionFinished(sessionFinishedState, /* autofillableIds= */ null);
2620-
}
26212634
}
26222635

26232636
/**
@@ -3367,6 +3380,26 @@ public void notifyNoFillUi(int sessionId, AutofillId id, int sessionFinishedStat
33673380
}
33683381
}
33693382

3383+
@Override
3384+
public void notifyFillUiShown(int sessionId, AutofillId id) {
3385+
final AutofillManager afm = mAfm.get();
3386+
if (afm != null) {
3387+
afm.post(
3388+
() -> afm.notifyCallback(
3389+
sessionId, id, AutofillCallback.EVENT_INPUT_SHOWN));
3390+
}
3391+
}
3392+
3393+
@Override
3394+
public void notifyFillUiHidden(int sessionId, AutofillId id) {
3395+
final AutofillManager afm = mAfm.get();
3396+
if (afm != null) {
3397+
afm.post(
3398+
() -> afm.notifyCallback(
3399+
sessionId, id, AutofillCallback.EVENT_INPUT_HIDDEN));
3400+
}
3401+
}
3402+
33703403
@Override
33713404
public void notifyDisableAutofill(long disableDuration, ComponentName componentName)
33723405
throws RemoteException {

core/java/android/view/autofill/IAutoFillManagerClient.aidl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@ oneway interface IAutoFillManagerClient {
7878
*/
7979
void notifyNoFillUi(int sessionId, in AutofillId id, int sessionFinishedState);
8080

81+
/**
82+
* Notifies that the fill UI was shown by the system (e.g. as inline chips in the keyboard).
83+
*/
84+
void notifyFillUiShown(int sessionId, in AutofillId id);
85+
86+
/**
87+
* Notifies that the fill UI previously shown by the system has been hidden by the system.
88+
*
89+
* @see #notifyFillUiShown
90+
*/
91+
void notifyFillUiHidden(int sessionId, in AutofillId id);
92+
8193
/**
8294
* Dispatches unhandled keyevent from autofill ui. Autofill ui handles DPAD and ENTER events,
8395
* other unhandled keyevents are dispatched to app's window to filter autofill result.

services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,14 @@ boolean hideInlineSuggestionsUiLocked(@NonNull AutofillId autofillId) {
117117
}
118118

119119
/**
120-
* Permanently delete the current inline fill UI. Notify the IME to hide the suggestions as
121-
* well.
120+
* Disables prefix/regex based filtering. Other filtering rules (see {@link
121+
* android.service.autofill.Dataset}) still apply.
122122
*/
123123
@GuardedBy("mLock")
124-
boolean deleteInlineFillUiLocked(@NonNull AutofillId autofillId) {
125-
mInlineFillUi = null;
126-
return hideInlineSuggestionsUiLocked(autofillId);
124+
void disableFilterMatching(@NonNull AutofillId autofillId) {
125+
if (mInlineFillUi != null && mInlineFillUi.getAutofillId().equals(autofillId)) {
126+
mInlineFillUi.disableFilterMatching();
127+
}
127128
}
128129

129130
/**

services/autofill/java/com/android/server/autofill/Session.java

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2698,6 +2698,11 @@ private void updateViewStateAndUiOnValueChangedLocked(AutofillId id, AutofillVal
26982698
// TODO(b/156099633): remove this once framework gets out of business of resending
26992699
// inline suggestions when IME visibility changes.
27002700
mInlineSessionController.hideInlineSuggestionsUiLocked(viewState.id);
2701+
try {
2702+
mClient.notifyFillUiHidden(this.id, viewState.id);
2703+
} catch (RemoteException e) {
2704+
Slog.e(TAG, "Error requesting to hide fill UI", e);
2705+
}
27012706
viewState.resetState(ViewState.STATE_CHANGED);
27022707
return;
27032708
} else if ((viewState.id.equals(this.mCurrentViewId))
@@ -2713,20 +2718,20 @@ private void updateViewStateAndUiOnValueChangedLocked(AutofillId id, AutofillVal
27132718
} else if (viewState.id.equals(this.mCurrentViewId)
27142719
&& (viewState.getState() & ViewState.STATE_INLINE_SHOWN) != 0) {
27152720
if ((viewState.getState() & ViewState.STATE_INLINE_DISABLED) != 0) {
2716-
final FillResponse response = viewState.getResponse();
2717-
if (response != null) {
2718-
response.getDatasets().clear();
2719-
}
2720-
mInlineSessionController.deleteInlineFillUiLocked(viewState.id);
2721-
} else {
2722-
mInlineSessionController.filterInlineFillUiLocked(mCurrentViewId, filterText);
2721+
mInlineSessionController.disableFilterMatching(viewState.id);
27232722
}
2723+
mInlineSessionController.filterInlineFillUiLocked(mCurrentViewId, filterText);
27242724
} else if (viewState.id.equals(this.mCurrentViewId)
27252725
&& (viewState.getState() & ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL) != 0) {
27262726
if (!TextUtils.isEmpty(filterText)) {
27272727
// TODO: we should be able to replace this with controller#filterInlineFillUiLocked
27282728
// to accomplish filtering for augmented autofill.
27292729
mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
2730+
try {
2731+
mClient.notifyFillUiHidden(this.id, mCurrentViewId);
2732+
} catch (RemoteException e) {
2733+
Slog.e(TAG, "Error sending fill UI hidden notification", e);
2734+
}
27302735
}
27312736
}
27322737

@@ -2812,6 +2817,11 @@ public void onFillReady(@NonNull FillResponse response, @NonNull AutofillId fill
28122817
if (requestShowInlineSuggestionsLocked(response, filterText)) {
28132818
final ViewState currentView = mViewStates.get(mCurrentViewId);
28142819
currentView.setState(ViewState.STATE_INLINE_SHOWN);
2820+
try {
2821+
mClient.notifyFillUiShown(this.id, mCurrentViewId);
2822+
} catch (RemoteException e) {
2823+
Slog.e(TAG, "Error sending fill UI shown notification", e);
2824+
}
28152825
//TODO(b/137800469): Fix it to log showed only when IME asks for inflation,
28162826
// rather than here where framework sends back the response.
28172827
mService.logDatasetShown(id, mClientState);
@@ -2882,6 +2892,11 @@ private boolean requestShowInlineSuggestionsLocked(@NonNull FillResponse respons
28822892
synchronized (mLock) {
28832893
mInlineSessionController.hideInlineSuggestionsUiLocked(
28842894
focusedId);
2895+
try {
2896+
mClient.notifyFillUiHidden(this.id, focusedId);
2897+
} catch (RemoteException e) {
2898+
Slog.e(TAG, "Error sending fill UI hidden notification", e);
2899+
}
28852900
}
28862901
}, remoteRenderService);
28872902
return mInlineSessionController.setInlineFillUiLocked(inlineFillUi);
@@ -3393,6 +3408,11 @@ void autoFill(int requestId, int datasetIndex, Dataset dataset, boolean generate
33933408
}
33943409
if (mCurrentViewId != null) {
33953410
mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
3411+
try {
3412+
mClient.notifyFillUiHidden(this.id, mCurrentViewId);
3413+
} catch (RemoteException e) {
3414+
Slog.e(TAG, "Error sending fill UI hidden notification", e);
3415+
}
33963416
}
33973417
autoFillApp(dataset);
33983418
return;

services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ public final class InlineFillUi {
8383
@Nullable
8484
private String mFilterText;
8585

86+
/**
87+
* Whether prefix/regex based filtering is disabled.
88+
*/
89+
private boolean mFilterMatchingDisabled;
90+
8691
/**
8792
* Returns an empty inline autofill UI.
8893
*/
@@ -199,7 +204,7 @@ public InlineSuggestionsResponse getInlineSuggestionsResponse() {
199204
continue;
200205
}
201206
if (!inlinePresentation.isPinned() // don't filter pinned suggestions
202-
&& !includeDataset(dataset, fieldIndex, mFilterText)) {
207+
&& !includeDataset(dataset, fieldIndex)) {
203208
continue;
204209
}
205210
inlineSuggestions.add(copy(i, mInlineSuggestions.get(i)));
@@ -235,14 +240,13 @@ private InlineSuggestion copy(int index, @NonNull InlineSuggestion inlineSuggest
235240
}
236241

237242
// TODO: Extract the shared filtering logic here and in FillUi to a common method.
238-
private static boolean includeDataset(Dataset dataset, int fieldIndex,
239-
@Nullable String filterText) {
243+
private boolean includeDataset(Dataset dataset, int fieldIndex) {
240244
// Show everything when the user input is empty.
241-
if (TextUtils.isEmpty(filterText)) {
245+
if (TextUtils.isEmpty(mFilterText)) {
242246
return true;
243247
}
244248

245-
final String constraintLowerCase = filterText.toString().toLowerCase();
249+
final String constraintLowerCase = mFilterText.toString().toLowerCase();
246250

247251
// Use the filter provided by the service, if available.
248252
final Dataset.DatasetFieldFilter filter = dataset.getFilter(fieldIndex);
@@ -252,7 +256,10 @@ private static boolean includeDataset(Dataset dataset, int fieldIndex,
252256
if (sVerbose) {
253257
Slog.v(TAG, "Explicitly disabling filter for dataset id" + dataset.getId());
254258
}
255-
return true;
259+
return false;
260+
}
261+
if (mFilterMatchingDisabled) {
262+
return false;
256263
}
257264
return filterPattern.matcher(constraintLowerCase).matches();
258265
}
@@ -261,10 +268,21 @@ private static boolean includeDataset(Dataset dataset, int fieldIndex,
261268
if (value == null || !value.isText()) {
262269
return dataset.getAuthentication() == null;
263270
}
271+
if (mFilterMatchingDisabled) {
272+
return false;
273+
}
264274
final String valueText = value.getTextValue().toString().toLowerCase();
265275
return valueText.toLowerCase().startsWith(constraintLowerCase);
266276
}
267277

278+
/**
279+
* Disables prefix/regex based filtering. Other filtering rules (see {@link
280+
* android.service.autofill.Dataset}) still apply.
281+
*/
282+
public void disableFilterMatching() {
283+
mFilterMatchingDisabled = true;
284+
}
285+
268286
/**
269287
* Callback from the inline suggestion Ui.
270288
*/

0 commit comments

Comments
 (0)