Merge "Use initial value on save when value didn't change." into oc-dev
diff --git a/core/java/android/service/autofill/FillContext.java b/core/java/android/service/autofill/FillContext.java
index 251d346..6956c8a 100644
--- a/core/java/android/service/autofill/FillContext.java
+++ b/core/java/android/service/autofill/FillContext.java
@@ -114,7 +114,7 @@
      *
      * @hide
      */
-    @NonNull public ViewNode[] findViewNodesByAutofillIds(@NonNull AutofillId[] ids) {
+    @NonNull public ViewNode[] findViewNodesByAutofillIds(@NonNull AutofillId... ids) {
         final LinkedList<ViewNode> nodesToProcess = new LinkedList<>();
         final ViewNode[] foundNodes = new AssistStructure.ViewNode[ids.length];
 
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 980a7d4..3c6e9b2 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -774,20 +774,29 @@
                 break;
             }
 
-            final AutofillValue currentValue = viewState.getCurrentValue();
-            if (currentValue == null || currentValue.isEmpty()) {
-                if (sDebug) {
-                    Slog.d(TAG, "showSaveLocked(): empty value for required " + id );
+            AutofillValue value = viewState.getCurrentValue();
+            if (value == null || value.isEmpty()) {
+                final AutofillValue initialValue = getValueFromContexts(id);
+                if (initialValue != null) {
+                    if (sDebug) {
+                        Slog.d(TAG, "Value of required field " + id + " didn't change; "
+                                + "using initial value (" + initialValue + ") instead");
+                    }
+                    value = initialValue;
+                } else {
+                    if (sDebug) {
+                        Slog.d(TAG, "showSaveLocked(): empty value for required " + id );
+                    }
+                    allRequiredAreNotEmpty = false;
+                    break;
                 }
-                allRequiredAreNotEmpty = false;
-                break;
             }
             final AutofillValue filledValue = viewState.getAutofilledValue();
 
-            if (!currentValue.equals(filledValue)) {
+            if (!value.equals(filledValue)) {
                 if (sDebug) {
                     Slog.d(TAG, "showSaveLocked(): found a change on required " + id + ": "
-                            + filledValue + " => " + currentValue);
+                            + filledValue + " => " + value);
                 }
                 atLeastOneChanged = true;
             }
@@ -845,6 +854,31 @@
     }
 
     /**
+     * Gets the latest non-empty value for the given id in the autofill contexts.
+     */
+    @Nullable
+    private AutofillValue getValueFromContexts(AutofillId id) {
+        AutofillValue value = null;
+        final int numContexts = mContexts.size();
+        for (int i = 0; i < numContexts; i++) {
+            final FillContext context = mContexts.get(i);
+            // TODO: create a function that gets just one node so it doesn't create an array
+            // unnecessarily
+            final ViewNode[] nodes = context.findViewNodesByAutofillIds(id);
+            if (nodes != null) {
+                AutofillValue candidate = nodes[0].getAutofillValue();
+                if (sDebug) {
+                    Slog.d(TAG, "getValueFromContexts(" + id + ") at " + i + ": " + candidate);
+                }
+                if (candidate != null && !candidate.isEmpty()) {
+                    value = candidate;
+                }
+            }
+        }
+        return value;
+    }
+
+    /**
      * Calls service when user requested save.
      */
     void callSaveLocked() {
@@ -1009,7 +1043,7 @@
                     || action == ACTION_VIEW_ENTERED) {
                 if (sVerbose) Slog.v(TAG, "Creating viewState for " + id + " on " + action);
                 boolean isIgnored = isIgnoredLocked(id);
-                viewState = new ViewState(this, id, value, this,
+                viewState = new ViewState(this, id, this,
                         isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL);
                 mViewStates.put(id, viewState);
                 if (isIgnored) {
@@ -1307,7 +1341,7 @@
         if (viewState != null)  {
             viewState.setState(state);
         } else {
-            viewState = new ViewState(this, id, null, this, state);
+            viewState = new ViewState(this, id, this, state);
             if (sVerbose) {
                 Slog.v(TAG, "Adding autofillable view with id " + id + " and state " + state);
             }
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index cd8f4a5..51659bb 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -74,16 +74,14 @@
     private final Session mSession;
 
     private FillResponse mResponse;
-    private AutofillValue mInitialValue;
     private AutofillValue mCurrentValue;
     private AutofillValue mAutofilledValue;
     private Rect mVirtualBounds;
     private int mState;
 
-    ViewState(Session session, AutofillId id, AutofillValue value, Listener listener, int state) {
+    ViewState(Session session, AutofillId id, Listener listener, int state) {
         mSession = session;
         this.id = id;
-        mInitialValue = value;
         mListener = listener;
         mState = state;
     }
@@ -118,11 +116,6 @@
     }
 
     @Nullable
-    AutofillValue getInitialValue() {
-        return mInitialValue;
-    }
-
-    @Nullable
     FillResponse getResponse() {
         return mResponse;
     }
@@ -189,8 +182,8 @@
 
     @Override
     public String toString() {
-        return "ViewState: [id=" + id + ", initialValue=" + mInitialValue
-                + ", currentValue=" + mCurrentValue + ", autofilledValue=" + mAutofilledValue
+        return "ViewState: [id=" + id + ", currentValue=" + mCurrentValue
+                + ", autofilledValue=" + mAutofilledValue
                 + ", bounds=" + mVirtualBounds + ", state=" + getStateAsString() + "]";
     }
 
@@ -207,7 +200,6 @@
                 pw.println(mResponse.getRequestId());
             }
         }
-        pw.print(prefix); pw.print("initialValue:" ); pw.println(mInitialValue);
         pw.print(prefix); pw.print("currentValue:" ); pw.println(mCurrentValue);
         pw.print(prefix); pw.print("autofilledValue:" ); pw.println(mAutofilledValue);
         pw.print(prefix); pw.print("virtualBounds:" ); pw.println(mVirtualBounds);