Merge "Fixed scenario where an authentication response has no dataset." into oc-dev
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 277c622..9487760 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -174,6 +174,7 @@
                SAVE_DATA_TYPE_PASSWORD,
                SAVE_DATA_TYPE_ADDRESS,
                SAVE_DATA_TYPE_CREDIT_CARD,
+               SAVE_DATA_TYPE_USERNAME,
                SAVE_DATA_TYPE_EMAIL_ADDRESS})
     @Retention(RetentionPolicy.SOURCE)
     @interface SaveDataType{}
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index cbf97dd..8d947b9 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -20,9 +20,7 @@
 import android.app.assist.AssistStructure;
 import android.app.assist.AssistStructure.ViewNode;
 import android.os.Bundle;
-import android.util.DebugUtils;
 import android.view.autofill.AutofillId;
-import android.view.autofill.AutofillManager;
 
 import java.util.Arrays;
 import java.util.Objects;
@@ -68,10 +66,6 @@
         return builder.toString();
     }
 
-    static String getUpdateActionAsString(int action) {
-        return DebugUtils.flagsToString(AutofillManager.class, "ACTION_", action);
-    }
-
     static ViewNode findViewNodeById(@NonNull AssistStructure structure, @NonNull AutofillId id) {
         final int size = structure.getWindowNodeCount();
         for (int i = 0; i < size; i++) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 3c85034..a98821d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -26,7 +26,6 @@
 import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
 
 import static com.android.server.autofill.Helper.findViewNodeById;
-import static com.android.server.autofill.Helper.getUpdateActionAsString;
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sVerbose;
 import static com.android.server.autofill.ViewState.STATE_AUTOFILLED;
@@ -689,6 +688,8 @@
         } else {
             final Parcelable result = data.getParcelable(
                     AutofillManager.EXTRA_AUTHENTICATION_RESULT);
+            if (sVerbose) Slog.d(TAG, "setAuthenticationResultLocked() for " + result);
+
             if (result instanceof FillResponse) {
                 FillResponse response = (FillResponse) result;
 
@@ -697,6 +698,16 @@
                 mResponseWaitingAuth = null;
                 if (requestIndex >= 0) {
                     response.setRequestId(mResponses.keyAt(requestIndex));
+                    if (response.getDatasets() == null || response.getDatasets().isEmpty()) {
+                        // TODO(b/37424539): there is a race condition that causes the authentication
+                        // dialog to be shown again after the service authreplied with a no-datasets
+                        // response. We're fixing it by hiding the UI when that happens, but that
+                        // sounds like a hack - hopefully the real problem will go away when we
+                        // refactor auth to support partitions; if it doesn't, we need to
+                        // investigate it further (it can be reproduced by running
+                        // LoginActivityTest.testFillResponseAuthServiceHasNoData())
+                        mUi.hideAll();
+                    }
                     processResponseLocked(response);
                 } else {
                     Slog.e(TAG, "Error cannot find id for auth response");
@@ -1005,18 +1016,14 @@
             return;
         }
         if (sVerbose) {
-            Slog.v(TAG, "updateLocked(): id=" + id + ", action=" + getUpdateActionAsString(action)
-                    + ", flags=" + flags);
+            Slog.v(TAG, "updateLocked(): id=" + id + ", action=" + action + ", flags=" + flags);
         }
         ViewState viewState = mViewStates.get(id);
 
         if (viewState == null) {
             if (action == ACTION_START_SESSION || action == ACTION_VALUE_CHANGED
                     || action == ACTION_VIEW_ENTERED) {
-                if (sVerbose) {
-                    Slog.v(TAG,
-                            "Creating viewState for " + id + " on " + getActionAsString(action));
-                }
+                if (sVerbose) Slog.v(TAG, "Creating viewState for " + id + " on " + action);
                 boolean isIgnored = isIgnoredLocked(id);
                 viewState = new ViewState(this, id, value, this,
                         isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL);
@@ -1026,7 +1033,7 @@
                     return;
                 }
             } else {
-                if (sVerbose) Slog.v(TAG, "Ignored " + getActionAsString(action) + " for " + id);
+                if (sVerbose) Slog.v(TAG, "Ignored action " + action + " for " + id);
                 return;
             }
         }
@@ -1078,6 +1085,7 @@
                 break;
             case ACTION_VIEW_EXITED:
                 if (mCurrentViewId == viewState.id) {
+                    if (sVerbose) Slog.d(TAG, "Exiting view " + id);
                     mUi.hideFillUi(viewState.id);
                     mCurrentViewId = null;
                 }
@@ -1118,10 +1126,6 @@
         getUiForShowing().showFillUi(filledId, response, filterText, mPackageName);
     }
 
-    String getActionAsString(int flag) {
-        return DebugUtils.flagsToString(AutofillManager.class, "ACTION_", flag);
-    }
-
     boolean isDestroyed() {
         synchronized (mLock) {
             return mDestroyed;
@@ -1180,14 +1184,15 @@
     }
 
     private void processResponseLocked(@NonNull FillResponse response) {
+        final int requestId = response.getRequestId();
         if (sVerbose) {
-            Slog.v(TAG, "processResponseLocked(mCurrentViewId=" + mCurrentViewId + "):" + response);
+            Slog.v(TAG, "processResponseLocked(): mCurrentViewId=" + mCurrentViewId
+                    + ", reqId=" + requestId + ", resp=" + response);
         }
 
         if (mResponses == null) {
             mResponses = new SparseArray<>(4);
         }
-        final int requestId = response.getRequestId();
         mResponses.put(requestId, response);
         mClientState = response.getClientState();