Loading services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java +2 −3 Original line number Diff line number Diff line Loading @@ -35,8 +35,8 @@ import java.util.function.Consumer; * Controls the interaction with the IME for the {@link AutofillInlineSuggestionsRequestSession}s. * * <p>The class maintains the inline suggestion session with the autofill service. There is at most * one active inline suggestion session at any given corresponding to one focused view. * New sessions are created only when {@link #onCreateInlineSuggestionsRequestLocked} is called.</p> * one active inline suggestion session at any given corresponding to one focused view. New * sessions are created only when {@link #onCreateInlineSuggestionsRequestLocked} is called.</p> * * <p>The class manages the interaction between the {@link com.android.server.autofill.Session} and * the inline suggestion session whenever inline suggestions can be provided. All calls to the Loading Loading @@ -83,7 +83,6 @@ final class AutofillInlineSessionController { @GuardedBy("mLock") void onCreateInlineSuggestionsRequestLocked(@NonNull AutofillId autofillId, @NonNull Consumer<InlineSuggestionsRequest> requestConsumer, @NonNull Bundle uiExtras) { // TODO(b/151123764): rename the method to better reflect what it does. if (mSession != null) { // Destroy the existing session. mSession.destroySessionLocked(); Loading services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +2 −2 Original line number Diff line number Diff line Loading @@ -1055,7 +1055,7 @@ final class AutofillManagerServiceImpl pw.println(compatPkgs); } pw.print(prefix); pw.print("Inline Suggestions Enabled: "); pw.println(isInlineSuggestionsEnabled()); pw.println(isInlineSuggestionsEnabledLocked()); pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune); mDisabledInfoCache.dump(mUserId, prefix, pw); Loading Loading @@ -1168,7 +1168,7 @@ final class AutofillManagerServiceImpl } @GuardedBy("mLock") boolean isInlineSuggestionsEnabled() { boolean isInlineSuggestionsEnabledLocked() { if (mInfo != null) { return mInfo.isInlineSuggestionsEnabled(); } Loading services/autofill/java/com/android/server/autofill/Helper.java +44 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,9 @@ import android.app.assist.AssistStructure.WindowNode; import android.content.ComponentName; import android.metrics.LogMaker; import android.service.autofill.Dataset; import android.service.autofill.InternalSanitizer; import android.service.autofill.SaveInfo; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; Loading @@ -38,6 +41,7 @@ import com.android.internal.util.ArrayUtils; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; public final class Helper { Loading Loading @@ -234,6 +238,46 @@ public final class Helper { } } @Nullable static ArrayMap<AutofillId, InternalSanitizer> createSanitizers(@Nullable SaveInfo saveInfo) { if (saveInfo == null) return null; final InternalSanitizer[] sanitizerKeys = saveInfo.getSanitizerKeys(); if (sanitizerKeys == null) return null; final int size = sanitizerKeys.length; final ArrayMap<AutofillId, InternalSanitizer> sanitizers = new ArrayMap<>(size); if (sDebug) Slog.d(TAG, "Service provided " + size + " sanitizers"); final AutofillId[][] sanitizerValues = saveInfo.getSanitizerValues(); for (int i = 0; i < size; i++) { final InternalSanitizer sanitizer = sanitizerKeys[i]; final AutofillId[] ids = sanitizerValues[i]; if (sDebug) { Slog.d(TAG, "sanitizer #" + i + " (" + sanitizer + ") for ids " + Arrays.toString(ids)); } for (AutofillId id : ids) { sanitizers.put(id, sanitizer); } } return sanitizers; } /** * Returns true if {@code s1} contains all characters of {@code s2}, in order. */ static boolean containsCharsInOrder(String s1, String s2) { int prevIndex = -1; for (char ch : s2.toCharArray()) { int index = TextUtils.indexOf(s1, ch, prevIndex + 1); if (index == -1) { return false; } prevIndex = index; } return true; } private interface ViewNodeFilter { boolean matches(ViewNode node); } Loading services/autofill/java/com/android/server/autofill/Session.java +29 −63 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.server.autofill.Helper.containsCharsInOrder; import static com.android.server.autofill.Helper.createSanitizers; import static com.android.server.autofill.Helper.getNumericValue; import static com.android.server.autofill.Helper.sDebug; import static com.android.server.autofill.Helper.sVerbose; Loading Loading @@ -545,6 +547,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return ids; } /** * Returns the String value of an {@link AutofillValue} by {@link AutofillId id} if it is of * type {@code AUTOFILL_TYPE_TEXT} or {@code AUTOFILL_TYPE_LIST}. */ @Override @Nullable public String findByAutofillId(@NonNull AutofillId id) { Loading Loading @@ -706,7 +712,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState * Autofill provider). */ private boolean isInlineSuggestionsEnabledByAutofillProviderLocked() { return mService.isInlineSuggestionsEnabled(); return mService.isInlineSuggestionsEnabledLocked(); } private boolean isViewFocusedLocked(int flags) { Loading Loading @@ -767,7 +773,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // triggers a new partition and we end up with many duplicate partitions. This is // enhanced as the focus change can be much faster than the taking of the assist structure. // Hence remove the currently queued request and replace it with the one queued after the // structure is taken. This causes only one fill request per bust of focus changes. // structure is taken. This causes only one fill request per burst of focus changes. cancelCurrentRequestLocked(); // Only ask IME to create inline suggestions request if Autofill provider supports it and Loading @@ -794,8 +800,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState viewState.setState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST); } } else { mAssistReceiver.newAutofillRequestLocked(viewState, /*isInlineRequest=*/ false); mAssistReceiver.newAutofillRequestLocked(viewState, /* isInlineRequest= */ false); } // Now request the assist structure data. Loading Loading @@ -1172,7 +1177,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return null; } // FillServiceCallbacks // VultureCallback @Override public void onServiceDied(@NonNull RemoteFillService service) { Slog.w(TAG, "removing session because service died"); forceRemoveSelfLocked(); } // AutoFillUiCallback @Override public void authenticate(int requestId, int datasetIndex, IntentSender intent, Bundle extras, boolean authenticateInline) { Loading Loading @@ -1202,13 +1214,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState this, authenticationId, intent, fillInIntent, authenticateInline)); } // VultureCallback @Override public void onServiceDied(@NonNull RemoteFillService service) { Slog.w(TAG, "removing session because service died"); forceRemoveSelfLocked(); } // AutoFillUiCallback @Override public void fill(int requestId, int datasetIndex, Dataset dataset) { Loading Loading @@ -1282,6 +1287,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } // AutoFillUiCallback @Override public void dispatchUnhandledKey(AutofillId id, KeyEvent keyEvent) { synchronized (mLock) { Loading Loading @@ -2280,31 +2286,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mService.logSaveShown(id, mClientState); } @Nullable private ArrayMap<AutofillId, InternalSanitizer> createSanitizers(@Nullable SaveInfo saveInfo) { if (saveInfo == null) return null; final InternalSanitizer[] sanitizerKeys = saveInfo.getSanitizerKeys(); if (sanitizerKeys == null) return null; final int size = sanitizerKeys.length ; final ArrayMap<AutofillId, InternalSanitizer> sanitizers = new ArrayMap<>(size); if (sDebug) Slog.d(TAG, "Service provided " + size + " sanitizers"); final AutofillId[][] sanitizerValues = saveInfo.getSanitizerValues(); for (int i = 0; i < size; i++) { final InternalSanitizer sanitizer = sanitizerKeys[i]; final AutofillId[] ids = sanitizerValues[i]; if (sDebug) { Slog.d(TAG, "sanitizer #" + i + " (" + sanitizer + ") for ids " + Arrays.toString(ids)); } for (AutofillId id : ids) { sanitizers.put(id, sanitizer); } } return sanitizers; } @Nullable private AutofillValue getSanitizedValue( @Nullable ArrayMap<AutofillId, InternalSanitizer> sanitizers, Loading Loading @@ -2369,12 +2350,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState */ @GuardedBy("mLock") @Nullable private CharSequence[] getAutofillOptionsFromContextsLocked(AutofillId id) { private CharSequence[] getAutofillOptionsFromContextsLocked(@NonNull AutofillId autofillId) { final int numContexts = mContexts.size(); for (int i = numContexts - 1; i >= 0; i--) { final FillContext context = mContexts.get(i); final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(), id); final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(), autofillId); if (node != null && node.getAutofillOptions() != null) { return node.getAutofillOptions(); } Loading Loading @@ -2480,7 +2461,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // TODO(b/113281366): rather than merge it here, it might be better to simply reuse the old // session instead of creating a new one. But we need to consider what would happen on corner // cases such as "Main Activity M -> activity A with username -> activity B with password" // If user follows the normal workflow, than session A would be merged with session B as // If user follows the normal workflow, then session A would be merged with session B as // expected. But if when on Activity A the user taps back or somehow launches another activity, // session A could be merged with the wrong session. /** Loading Loading @@ -2573,12 +2554,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } requestNewFillResponseLocked(viewState, ViewState.STATE_STARTED_PARTITION, flags); return true; } else { } if (sVerbose) { Slog.v(TAG, "Not starting new partition for view " + id + ": " + viewState.getStateAsString()); } } return false; } Loading Loading @@ -2938,21 +2919,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } /** * Returns true if {@code s1} contains all characters of {@code s2}, in order. */ private static boolean containsCharsInOrder(String s1, String s2) { int prevIndex = -1; for (char ch : s2.toCharArray()) { int index = TextUtils.indexOf(s1, ch, prevIndex + 1); if (index == -1) { return false; } prevIndex = index; } return true; } @Override public void onFillReady(@NonNull FillResponse response, @NonNull AutofillId filledId, @Nullable AutofillValue value) { Loading Loading @@ -3421,7 +3387,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mInlineSessionController.getInlineSuggestionsRequestLocked().orElse(null)); } if (mAugmentedAutofillDestroyer == null) { mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest(); mAugmentedAutofillDestroyer = remoteService::onDestroyAutofillWindowsRequest; } return mAugmentedAutofillDestroyer; } Loading Loading
services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java +2 −3 Original line number Diff line number Diff line Loading @@ -35,8 +35,8 @@ import java.util.function.Consumer; * Controls the interaction with the IME for the {@link AutofillInlineSuggestionsRequestSession}s. * * <p>The class maintains the inline suggestion session with the autofill service. There is at most * one active inline suggestion session at any given corresponding to one focused view. * New sessions are created only when {@link #onCreateInlineSuggestionsRequestLocked} is called.</p> * one active inline suggestion session at any given corresponding to one focused view. New * sessions are created only when {@link #onCreateInlineSuggestionsRequestLocked} is called.</p> * * <p>The class manages the interaction between the {@link com.android.server.autofill.Session} and * the inline suggestion session whenever inline suggestions can be provided. All calls to the Loading Loading @@ -83,7 +83,6 @@ final class AutofillInlineSessionController { @GuardedBy("mLock") void onCreateInlineSuggestionsRequestLocked(@NonNull AutofillId autofillId, @NonNull Consumer<InlineSuggestionsRequest> requestConsumer, @NonNull Bundle uiExtras) { // TODO(b/151123764): rename the method to better reflect what it does. if (mSession != null) { // Destroy the existing session. mSession.destroySessionLocked(); Loading
services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +2 −2 Original line number Diff line number Diff line Loading @@ -1055,7 +1055,7 @@ final class AutofillManagerServiceImpl pw.println(compatPkgs); } pw.print(prefix); pw.print("Inline Suggestions Enabled: "); pw.println(isInlineSuggestionsEnabled()); pw.println(isInlineSuggestionsEnabledLocked()); pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune); mDisabledInfoCache.dump(mUserId, prefix, pw); Loading Loading @@ -1168,7 +1168,7 @@ final class AutofillManagerServiceImpl } @GuardedBy("mLock") boolean isInlineSuggestionsEnabled() { boolean isInlineSuggestionsEnabledLocked() { if (mInfo != null) { return mInfo.isInlineSuggestionsEnabled(); } Loading
services/autofill/java/com/android/server/autofill/Helper.java +44 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,9 @@ import android.app.assist.AssistStructure.WindowNode; import android.content.ComponentName; import android.metrics.LogMaker; import android.service.autofill.Dataset; import android.service.autofill.InternalSanitizer; import android.service.autofill.SaveInfo; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; Loading @@ -38,6 +41,7 @@ import com.android.internal.util.ArrayUtils; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; public final class Helper { Loading Loading @@ -234,6 +238,46 @@ public final class Helper { } } @Nullable static ArrayMap<AutofillId, InternalSanitizer> createSanitizers(@Nullable SaveInfo saveInfo) { if (saveInfo == null) return null; final InternalSanitizer[] sanitizerKeys = saveInfo.getSanitizerKeys(); if (sanitizerKeys == null) return null; final int size = sanitizerKeys.length; final ArrayMap<AutofillId, InternalSanitizer> sanitizers = new ArrayMap<>(size); if (sDebug) Slog.d(TAG, "Service provided " + size + " sanitizers"); final AutofillId[][] sanitizerValues = saveInfo.getSanitizerValues(); for (int i = 0; i < size; i++) { final InternalSanitizer sanitizer = sanitizerKeys[i]; final AutofillId[] ids = sanitizerValues[i]; if (sDebug) { Slog.d(TAG, "sanitizer #" + i + " (" + sanitizer + ") for ids " + Arrays.toString(ids)); } for (AutofillId id : ids) { sanitizers.put(id, sanitizer); } } return sanitizers; } /** * Returns true if {@code s1} contains all characters of {@code s2}, in order. */ static boolean containsCharsInOrder(String s1, String s2) { int prevIndex = -1; for (char ch : s2.toCharArray()) { int index = TextUtils.indexOf(s1, ch, prevIndex + 1); if (index == -1) { return false; } prevIndex = index; } return true; } private interface ViewNodeFilter { boolean matches(ViewNode node); } Loading
services/autofill/java/com/android/server/autofill/Session.java +29 −63 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.server.autofill.Helper.containsCharsInOrder; import static com.android.server.autofill.Helper.createSanitizers; import static com.android.server.autofill.Helper.getNumericValue; import static com.android.server.autofill.Helper.sDebug; import static com.android.server.autofill.Helper.sVerbose; Loading Loading @@ -545,6 +547,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return ids; } /** * Returns the String value of an {@link AutofillValue} by {@link AutofillId id} if it is of * type {@code AUTOFILL_TYPE_TEXT} or {@code AUTOFILL_TYPE_LIST}. */ @Override @Nullable public String findByAutofillId(@NonNull AutofillId id) { Loading Loading @@ -706,7 +712,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState * Autofill provider). */ private boolean isInlineSuggestionsEnabledByAutofillProviderLocked() { return mService.isInlineSuggestionsEnabled(); return mService.isInlineSuggestionsEnabledLocked(); } private boolean isViewFocusedLocked(int flags) { Loading Loading @@ -767,7 +773,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // triggers a new partition and we end up with many duplicate partitions. This is // enhanced as the focus change can be much faster than the taking of the assist structure. // Hence remove the currently queued request and replace it with the one queued after the // structure is taken. This causes only one fill request per bust of focus changes. // structure is taken. This causes only one fill request per burst of focus changes. cancelCurrentRequestLocked(); // Only ask IME to create inline suggestions request if Autofill provider supports it and Loading @@ -794,8 +800,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState viewState.setState(ViewState.STATE_PENDING_CREATE_INLINE_REQUEST); } } else { mAssistReceiver.newAutofillRequestLocked(viewState, /*isInlineRequest=*/ false); mAssistReceiver.newAutofillRequestLocked(viewState, /* isInlineRequest= */ false); } // Now request the assist structure data. Loading Loading @@ -1172,7 +1177,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return null; } // FillServiceCallbacks // VultureCallback @Override public void onServiceDied(@NonNull RemoteFillService service) { Slog.w(TAG, "removing session because service died"); forceRemoveSelfLocked(); } // AutoFillUiCallback @Override public void authenticate(int requestId, int datasetIndex, IntentSender intent, Bundle extras, boolean authenticateInline) { Loading Loading @@ -1202,13 +1214,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState this, authenticationId, intent, fillInIntent, authenticateInline)); } // VultureCallback @Override public void onServiceDied(@NonNull RemoteFillService service) { Slog.w(TAG, "removing session because service died"); forceRemoveSelfLocked(); } // AutoFillUiCallback @Override public void fill(int requestId, int datasetIndex, Dataset dataset) { Loading Loading @@ -1282,6 +1287,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } // AutoFillUiCallback @Override public void dispatchUnhandledKey(AutofillId id, KeyEvent keyEvent) { synchronized (mLock) { Loading Loading @@ -2280,31 +2286,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mService.logSaveShown(id, mClientState); } @Nullable private ArrayMap<AutofillId, InternalSanitizer> createSanitizers(@Nullable SaveInfo saveInfo) { if (saveInfo == null) return null; final InternalSanitizer[] sanitizerKeys = saveInfo.getSanitizerKeys(); if (sanitizerKeys == null) return null; final int size = sanitizerKeys.length ; final ArrayMap<AutofillId, InternalSanitizer> sanitizers = new ArrayMap<>(size); if (sDebug) Slog.d(TAG, "Service provided " + size + " sanitizers"); final AutofillId[][] sanitizerValues = saveInfo.getSanitizerValues(); for (int i = 0; i < size; i++) { final InternalSanitizer sanitizer = sanitizerKeys[i]; final AutofillId[] ids = sanitizerValues[i]; if (sDebug) { Slog.d(TAG, "sanitizer #" + i + " (" + sanitizer + ") for ids " + Arrays.toString(ids)); } for (AutofillId id : ids) { sanitizers.put(id, sanitizer); } } return sanitizers; } @Nullable private AutofillValue getSanitizedValue( @Nullable ArrayMap<AutofillId, InternalSanitizer> sanitizers, Loading Loading @@ -2369,12 +2350,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState */ @GuardedBy("mLock") @Nullable private CharSequence[] getAutofillOptionsFromContextsLocked(AutofillId id) { private CharSequence[] getAutofillOptionsFromContextsLocked(@NonNull AutofillId autofillId) { final int numContexts = mContexts.size(); for (int i = numContexts - 1; i >= 0; i--) { final FillContext context = mContexts.get(i); final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(), id); final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(), autofillId); if (node != null && node.getAutofillOptions() != null) { return node.getAutofillOptions(); } Loading Loading @@ -2480,7 +2461,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // TODO(b/113281366): rather than merge it here, it might be better to simply reuse the old // session instead of creating a new one. But we need to consider what would happen on corner // cases such as "Main Activity M -> activity A with username -> activity B with password" // If user follows the normal workflow, than session A would be merged with session B as // If user follows the normal workflow, then session A would be merged with session B as // expected. But if when on Activity A the user taps back or somehow launches another activity, // session A could be merged with the wrong session. /** Loading Loading @@ -2573,12 +2554,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } requestNewFillResponseLocked(viewState, ViewState.STATE_STARTED_PARTITION, flags); return true; } else { } if (sVerbose) { Slog.v(TAG, "Not starting new partition for view " + id + ": " + viewState.getStateAsString()); } } return false; } Loading Loading @@ -2938,21 +2919,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } /** * Returns true if {@code s1} contains all characters of {@code s2}, in order. */ private static boolean containsCharsInOrder(String s1, String s2) { int prevIndex = -1; for (char ch : s2.toCharArray()) { int index = TextUtils.indexOf(s1, ch, prevIndex + 1); if (index == -1) { return false; } prevIndex = index; } return true; } @Override public void onFillReady(@NonNull FillResponse response, @NonNull AutofillId filledId, @Nullable AutofillValue value) { Loading Loading @@ -3421,7 +3387,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mInlineSessionController.getInlineSuggestionsRequestLocked().orElse(null)); } if (mAugmentedAutofillDestroyer == null) { mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest(); mAugmentedAutofillDestroyer = remoteService::onDestroyAutofillWindowsRequest; } return mAugmentedAutofillDestroyer; } Loading