summaryrefslogtreecommitdiff
path: root/android/view/autofill/AutofillManager.java
diff options
context:
space:
mode:
authorJeff Davidson <jpd@google.com>2018-02-08 15:30:06 -0800
committerJeff Davidson <jpd@google.com>2018-02-08 15:30:06 -0800
commita192cc2a132cb0ee8588e2df755563ec7008c179 (patch)
tree380e4db22df19c819bd37df34bf06e7568916a50 /android/view/autofill/AutofillManager.java
parent98fe7819c6d14f4f464a5cac047f9e82dee5da58 (diff)
downloadandroid-28-a192cc2a132cb0ee8588e2df755563ec7008c179.tar.gz
Update fullsdk to 4575844
/google/data/ro/projects/android/fetch_artifact \ --bid 4575844 \ --target sdk_phone_x86_64-sdk \ sdk-repo-linux-sources-4575844.zip Test: TreeHugger Change-Id: I81e0eb157b4ac3b38408d0ef86f9d6286471f87a
Diffstat (limited to 'android/view/autofill/AutofillManager.java')
-rw-r--r--android/view/autofill/AutofillManager.java211
1 files changed, 173 insertions, 38 deletions
diff --git a/android/view/autofill/AutofillManager.java b/android/view/autofill/AutofillManager.java
index 26974545..4b24a71c 100644
--- a/android/view/autofill/AutofillManager.java
+++ b/android/view/autofill/AutofillManager.java
@@ -53,6 +53,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -168,7 +170,6 @@ public final class AutofillManager {
public static final String EXTRA_CLIENT_STATE =
"android.view.autofill.extra.CLIENT_STATE";
-
/** @hide */
public static final String EXTRA_RESTORE_SESSION_TOKEN =
"android.view.autofill.extra.RESTORE_SESSION_TOKEN";
@@ -258,6 +259,12 @@ public final class AutofillManager {
public static final int STATE_DISABLED_BY_SERVICE = 4;
/**
+ * Timeout in ms for calls to the field classification service.
+ * @hide
+ */
+ public static final int FC_SERVICE_TIMEOUT = 5000;
+
+ /**
* Makes an authentication id from a request id and a dataset id.
*
* @param requestId The request id.
@@ -340,6 +347,10 @@ public final class AutofillManager {
@GuardedBy("mLock")
@Nullable private AutofillId mSaveTriggerId;
+ /** set to true when onInvisibleForAutofill is called, used by onAuthenticationResult */
+ @GuardedBy("mLock")
+ private boolean mOnInvisibleCalled;
+
/** If set, session is commited when the activity is finished; otherwise session is canceled. */
@GuardedBy("mLock")
private boolean mSaveOnFinish;
@@ -396,6 +407,11 @@ public final class AutofillManager {
boolean isVisibleForAutofill();
/**
+ * Client might disable enter/exit event e.g. when activity is paused.
+ */
+ boolean isDisablingEnterExitEventForAutofill();
+
+ /**
* Finds views by traversing the hierarchies of the client.
*
* @param viewIds The autofill ids of the views to find
@@ -498,6 +514,19 @@ public final class AutofillManager {
}
/**
+ * Called once the client becomes invisible.
+ *
+ * @see AutofillClient#isVisibleForAutofill()
+ *
+ * {@hide}
+ */
+ public void onInvisibleForAutofill() {
+ synchronized (mLock) {
+ mOnInvisibleCalled = true;
+ }
+ }
+
+ /**
* Save state before activity lifecycle
*
* @param outState Place to store the state
@@ -622,21 +651,45 @@ public final class AutofillManager {
return false;
}
+ private boolean isClientVisibleForAutofillLocked() {
+ final AutofillClient client = getClient();
+ return client != null && client.isVisibleForAutofill();
+ }
+
+ private boolean isClientDisablingEnterExitEvent() {
+ final AutofillClient client = getClient();
+ return client != null && client.isDisablingEnterExitEventForAutofill();
+ }
+
private void notifyViewEntered(@NonNull View view, int flags) {
if (!hasAutofillFeature()) {
return;
}
- AutofillCallback callback = null;
+ AutofillCallback callback;
synchronized (mLock) {
- if (shouldIgnoreViewEnteredLocked(view, flags)) return;
+ callback = notifyViewEnteredLocked(view, flags);
+ }
- ensureServiceClientAddedIfNeededLocked();
+ if (callback != null) {
+ mCallback.onAutofillEvent(view, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
+ }
+ }
- if (!mEnabled) {
- if (mCallback != null) {
- callback = mCallback;
- }
- } else {
+ /** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */
+ private AutofillCallback notifyViewEnteredLocked(@NonNull View view, int flags) {
+ if (shouldIgnoreViewEnteredLocked(view, flags)) return null;
+
+ AutofillCallback callback = null;
+
+ ensureServiceClientAddedIfNeededLocked();
+
+ if (!mEnabled) {
+ if (mCallback != null) {
+ callback = mCallback;
+ }
+ } else {
+ // don't notify entered when Activity is already in background
+ if (!isClientDisablingEnterExitEvent()) {
final AutofillId id = getAutofillId(view);
final AutofillValue value = view.getAutofillValue();
@@ -649,10 +702,7 @@ public final class AutofillManager {
}
}
}
-
- if (callback != null) {
- mCallback.onAutofillEvent(view, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
- }
+ return callback;
}
/**
@@ -665,9 +715,16 @@ public final class AutofillManager {
return;
}
synchronized (mLock) {
- ensureServiceClientAddedIfNeededLocked();
+ notifyViewExitedLocked(view);
+ }
+ }
- if (mEnabled && isActiveLocked()) {
+ void notifyViewExitedLocked(@NonNull View view) {
+ ensureServiceClientAddedIfNeededLocked();
+
+ if (mEnabled && isActiveLocked()) {
+ // dont notify exited when Activity is already in background
+ if (!isClientDisablingEnterExitEvent()) {
final AutofillId id = getAutofillId(view);
// Update focus on existing session.
@@ -718,7 +775,7 @@ public final class AutofillManager {
}
}
if (mTrackedViews != null) {
- mTrackedViews.notifyViewVisibilityChanged(id, isVisible);
+ mTrackedViews.notifyViewVisibilityChangedLocked(id, isVisible);
}
}
}
@@ -751,17 +808,32 @@ public final class AutofillManager {
if (!hasAutofillFeature()) {
return;
}
- AutofillCallback callback = null;
+ AutofillCallback callback;
synchronized (mLock) {
- if (shouldIgnoreViewEnteredLocked(view, flags)) return;
+ callback = notifyViewEnteredLocked(view, virtualId, bounds, flags);
+ }
- ensureServiceClientAddedIfNeededLocked();
+ if (callback != null) {
+ callback.onAutofillEvent(view, virtualId,
+ AutofillCallback.EVENT_INPUT_UNAVAILABLE);
+ }
+ }
- if (!mEnabled) {
- if (mCallback != null) {
- callback = mCallback;
- }
- } else {
+ /** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */
+ private AutofillCallback notifyViewEnteredLocked(View view, int virtualId, Rect bounds,
+ int flags) {
+ AutofillCallback callback = null;
+ if (shouldIgnoreViewEnteredLocked(view, flags)) return callback;
+
+ ensureServiceClientAddedIfNeededLocked();
+
+ if (!mEnabled) {
+ if (mCallback != null) {
+ callback = mCallback;
+ }
+ } else {
+ // don't notify entered when Activity is already in background
+ if (!isClientDisablingEnterExitEvent()) {
final AutofillId id = getAutofillId(view, virtualId);
if (!isActiveLocked()) {
@@ -773,11 +845,7 @@ public final class AutofillManager {
}
}
}
-
- if (callback != null) {
- callback.onAutofillEvent(view, virtualId,
- AutofillCallback.EVENT_INPUT_UNAVAILABLE);
- }
+ return callback;
}
/**
@@ -791,9 +859,16 @@ public final class AutofillManager {
return;
}
synchronized (mLock) {
- ensureServiceClientAddedIfNeededLocked();
+ notifyViewExitedLocked(view, virtualId);
+ }
+ }
- if (mEnabled && isActiveLocked()) {
+ private void notifyViewExitedLocked(@NonNull View view, int virtualId) {
+ ensureServiceClientAddedIfNeededLocked();
+
+ if (mEnabled && isActiveLocked()) {
+ // don't notify exited when Activity is already in background
+ if (!isClientDisablingEnterExitEvent()) {
final AutofillId id = getAutofillId(view, virtualId);
// Update focus on existing session.
@@ -1027,7 +1102,9 @@ public final class AutofillManager {
* Gets the user data used for
* <a href="AutofillService.html#FieldClassification">field classification</a>.
*
- * <p><b>Note:</b> This method should only be called by an app providing an autofill service.
+ * <p><b>Note:</b> This method should only be called by an app providing an autofill service,
+ * and it's ignored if the caller currently doesn't have an enabled autofill service for
+ * the user.
*
* @return value previously set by {@link #setUserData(UserData)} or {@code null} if it was
* reset or if the caller currently does not have an enabled autofill service for the user.
@@ -1079,6 +1156,47 @@ public final class AutofillManager {
}
/**
+ * Gets the name of the default algorithm used for
+ * <a href="AutofillService.html#FieldClassification">field classification</a>.
+ *
+ * <p>The default algorithm is used when the algorithm on {@link UserData} is invalid or not
+ * set.
+ *
+ * <p><b>Note:</b> This method should only be called by an app providing an autofill service,
+ * and it's ignored if the caller currently doesn't have an enabled autofill service for
+ * the user.
+ */
+ @Nullable
+ public String getDefaultFieldClassificationAlgorithm() {
+ try {
+ return mService.getDefaultFieldClassificationAlgorithm();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return null;
+ }
+ }
+
+ /**
+ * Gets the name of all algorithms currently available for
+ * <a href="AutofillService.html#FieldClassification">field classification</a>.
+ *
+ * <p><b>Note:</b> This method should only be called by an app providing an autofill service,
+ * and it returns an empty list if the caller currently doesn't have an enabled autofill service
+ * for the user.
+ */
+ @NonNull
+ public List<String> getAvailableFieldClassificationAlgorithms() {
+ final String[] algorithms;
+ try {
+ algorithms = mService.getAvailableFieldClassificationAlgorithms();
+ return algorithms != null ? Arrays.asList(algorithms) : Collections.emptyList();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return null;
+ }
+ }
+
+ /**
* Returns {@code true} if autofill is supported by the current device and
* is supported for this user.
*
@@ -1109,7 +1227,7 @@ public final class AutofillManager {
}
/** @hide */
- public void onAuthenticationResult(int authenticationId, Intent data) {
+ public void onAuthenticationResult(int authenticationId, Intent data, View focusView) {
if (!hasAutofillFeature()) {
return;
}
@@ -1121,9 +1239,24 @@ public final class AutofillManager {
if (sDebug) Log.d(TAG, "onAuthenticationResult(): d=" + data);
synchronized (mLock) {
- if (!isActiveLocked() || data == null) {
+ if (!isActiveLocked()) {
+ return;
+ }
+ // If authenticate activity closes itself during onCreate(), there is no onStop/onStart
+ // of app activity. We enforce enter event to re-show fill ui in such case.
+ // CTS example:
+ // LoginActivityTest#testDatasetAuthTwoFieldsUserCancelsFirstAttempt
+ // LoginActivityTest#testFillResponseAuthBothFieldsUserCancelsFirstAttempt
+ if (!mOnInvisibleCalled && focusView != null
+ && focusView.canNotifyAutofillEnterExitEvent()) {
+ notifyViewExitedLocked(focusView);
+ notifyViewEnteredLocked(focusView, 0);
+ }
+ if (data == null) {
+ // data is set to null when result is not RESULT_OK
return;
}
+
final Parcelable result = data.getParcelableExtra(EXTRA_AUTHENTICATION_RESULT);
final Bundle responseData = new Bundle();
responseData.putParcelable(EXTRA_AUTHENTICATION_RESULT, result);
@@ -1356,6 +1489,9 @@ public final class AutofillManager {
if (sessionId == mSessionId) {
final AutofillClient client = getClient();
if (client != null) {
+ // clear mOnInvisibleCalled and we will see if receive onInvisibleForAutofill()
+ // before onAuthenticationResult()
+ mOnInvisibleCalled = false;
client.autofillCallbackAuthenticate(authenticationId, intent, fillInIntent);
}
}
@@ -1721,6 +1857,7 @@ public final class AutofillManager {
pw.print(pfx); pw.print("enabled: "); pw.println(mEnabled);
pw.print(pfx); pw.print("hasService: "); pw.println(mService != null);
pw.print(pfx); pw.print("hasCallback: "); pw.println(mCallback != null);
+ pw.print(pfx); pw.print("onInvisibleCalled "); pw.println(mOnInvisibleCalled);
pw.print(pfx); pw.print("last autofilled data: "); pw.println(mLastAutofilledData);
pw.print(pfx); pw.print("tracked views: ");
if (mTrackedViews == null) {
@@ -1891,15 +2028,13 @@ public final class AutofillManager {
* @param id the id of the view/virtual view whose visibility changed.
* @param isVisible visible if the view is visible in the view hierarchy.
*/
- void notifyViewVisibilityChanged(@NonNull AutofillId id, boolean isVisible) {
- AutofillClient client = getClient();
-
+ void notifyViewVisibilityChangedLocked(@NonNull AutofillId id, boolean isVisible) {
if (sDebug) {
Log.d(TAG, "notifyViewVisibilityChanged(): id=" + id + " isVisible="
+ isVisible);
}
- if (client != null && client.isVisibleForAutofill()) {
+ if (isClientVisibleForAutofillLocked()) {
if (isVisible) {
if (isInSet(mInvisibleTrackedIds, id)) {
mInvisibleTrackedIds = removeFromSet(mInvisibleTrackedIds, id);