Merge "Merge "Improved autofill support on DatePicker and TimePicker:" into oc-mr1-dev am: 6598a4ed52 am: e6be222bdf"
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 8094bfc..dfb3642 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -524,12 +524,13 @@
         void setAutoFillChangeListener(OnDateChangedListener onDateChangedListener);
 
         void updateDate(int year, int month, int dayOfMonth);
-        void updateDate(long date);
 
         int getYear();
         int getMonth();
         int getDayOfMonth();
-        long getDate();
+
+        void autofill(AutofillValue value);
+        AutofillValue getAutofillValue();
 
         void setFirstDayOfWeek(int firstDayOfWeek);
         int getFirstDayOfWeek();
@@ -572,6 +573,7 @@
         // The context
         protected Context mContext;
 
+        // NOTE: when subclasses change this variable, they must call resetAutofilledValue().
         protected Calendar mCurrentDate;
 
         // The current locale
@@ -582,6 +584,11 @@
         protected OnDateChangedListener mAutoFillChangeListener;
         protected ValidationCallback mValidationCallback;
 
+        // The value that was passed to autofill() - it must be stored because it getAutofillValue()
+        // must return the exact same value that was autofilled, otherwise the widget will not be
+        // properly highlighted after autofill().
+        private long mAutofilledValue;
+
         public AbstractDatePickerDelegate(DatePicker delegator, Context context) {
             mDelegator = delegator;
             mContext = context;
@@ -612,16 +619,38 @@
         }
 
         @Override
-        public void updateDate(long date) {
-            Calendar cal = Calendar.getInstance(mCurrentLocale);
-            cal.setTimeInMillis(date);
+        public final void autofill(AutofillValue value) {
+            if (value == null || !value.isDate()) {
+                Log.w(LOG_TAG, value + " could not be autofilled into " + this);
+                return;
+            }
+
+            final long time = value.getDateValue();
+
+            final Calendar cal = Calendar.getInstance(mCurrentLocale);
+            cal.setTimeInMillis(time);
             updateDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
                     cal.get(Calendar.DAY_OF_MONTH));
+
+            // Must set mAutofilledValue *after* calling subclass method to make sure the value
+            // returned by getAutofillValue() matches it.
+            mAutofilledValue = time;
         }
 
         @Override
-        public long getDate() {
-            return mCurrentDate.getTimeInMillis();
+        public final AutofillValue getAutofillValue() {
+            final long time = mAutofilledValue != 0
+                    ? mAutofilledValue
+                    : mCurrentDate.getTimeInMillis();
+            return AutofillValue.forDate(time);
+        }
+
+        /**
+         * This method must be called every time the value of the year, month, and/or day is
+         * changed by a subclass method.
+         */
+        protected void resetAutofilledValue() {
+            mAutofilledValue = 0;
         }
 
         protected void onValidationChanged(boolean valid) {
@@ -777,12 +806,7 @@
     public void autofill(AutofillValue value) {
         if (!isEnabled()) return;
 
-        if (!value.isDate()) {
-            Log.w(LOG_TAG, value + " could not be autofilled into " + this);
-            return;
-        }
-
-        mDelegate.updateDate(value.getDateValue());
+        mDelegate.autofill(value);
     }
 
     @Override
@@ -792,6 +816,6 @@
 
     @Override
     public AutofillValue getAutofillValue() {
-        return isEnabled() ? AutofillValue.forDate(mDelegate.getDate()) : null;
+        return isEnabled() ? mDelegate.getAutofillValue() : null;
     }
 }
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 636519b..60b4757 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -368,12 +368,9 @@
     }
 
     @Override
-    public void init(int year, int monthOfYear, int dayOfMonth,
+    public void init(int year, int month, int dayOfMonth,
             DatePicker.OnDateChangedListener callBack) {
-        mCurrentDate.set(Calendar.YEAR, year);
-        mCurrentDate.set(Calendar.MONTH, monthOfYear);
-        mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
-
+        setDate(year, month, dayOfMonth);
         onDateChanged(false, false);
 
         mOnDateChangedListener = callBack;
@@ -381,11 +378,15 @@
 
     @Override
     public void updateDate(int year, int month, int dayOfMonth) {
+        setDate(year, month, dayOfMonth);
+        onDateChanged(false, true);
+    }
+
+    private void setDate(int year, int month, int dayOfMonth) {
         mCurrentDate.set(Calendar.YEAR, year);
         mCurrentDate.set(Calendar.MONTH, month);
         mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
-
-        onDateChanged(false, true);
+        resetAutofilledValue();
     }
 
     private void onDateChanged(boolean fromUser, boolean callbackToClient) {
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index 4f9316f..dba74b1 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -504,6 +504,7 @@
 
     private void setDate(int year, int month, int dayOfMonth) {
         mCurrentDate.set(year, month, dayOfMonth);
+        resetAutofilledValue();
         if (mCurrentDate.before(mMinDate)) {
             mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
         } else if (mCurrentDate.after(mMaxDate)) {
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index de289bb..ae6881e 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -366,8 +366,11 @@
         void setMinute(@IntRange(from = 0, to = 59) int minute);
         int getMinute();
 
-        void setDate(long date);
-        long getDate();
+        void setDate(@IntRange(from = 0, to = 23) int hour,
+                @IntRange(from = 0, to = 59) int minute);
+
+        void autofill(AutofillValue value);
+        AutofillValue getAutofillValue();
 
         void setIs24Hour(boolean is24Hour);
         boolean is24Hour();
@@ -422,6 +425,11 @@
         protected OnTimeChangedListener mOnTimeChangedListener;
         protected OnTimeChangedListener mAutoFillChangeListener;
 
+        // The value that was passed to autofill() - it must be stored because it getAutofillValue()
+        // must return the exact same value that was autofilled, otherwise the widget will not be
+        // properly highlighted after autofill().
+        private long mAutofilledValue;
+
         public AbstractTimePickerDelegate(@NonNull TimePicker delegator, @NonNull Context context) {
             mDelegator = delegator;
             mContext = context;
@@ -439,19 +447,41 @@
         }
 
         @Override
-        public void setDate(long date) {
-            Calendar cal = Calendar.getInstance(mLocale);
-            cal.setTimeInMillis(date);
-            setHour(cal.get(Calendar.HOUR_OF_DAY));
-            setMinute(cal.get(Calendar.MINUTE));
+        public final void autofill(AutofillValue value) {
+            if (value == null || !value.isDate()) {
+                Log.w(LOG_TAG, value + " could not be autofilled into " + this);
+                return;
+            }
+
+            final long time = value.getDateValue();
+
+            final Calendar cal = Calendar.getInstance(mLocale);
+            cal.setTimeInMillis(time);
+            setDate(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE));
+
+            // Must set mAutofilledValue *after* calling subclass method to make sure the value
+            // returned by getAutofillValue() matches it.
+            mAutofilledValue = time;
         }
 
         @Override
-        public long getDate() {
-            Calendar cal = Calendar.getInstance(mLocale);
+        public final AutofillValue getAutofillValue() {
+            if (mAutofilledValue != 0) {
+                return AutofillValue.forDate(mAutofilledValue);
+            }
+
+            final Calendar cal = Calendar.getInstance(mLocale);
             cal.set(Calendar.HOUR_OF_DAY, getHour());
             cal.set(Calendar.MINUTE, getMinute());
-            return cal.getTimeInMillis();
+            return AutofillValue.forDate(cal.getTimeInMillis());
+        }
+
+        /**
+         * This method must be called every time the value of the hour and/or minute is changed by
+         * a subclass method.
+         */
+        protected void resetAutofilledValue() {
+            mAutofilledValue = 0;
         }
 
         protected static class SavedState extends View.BaseSavedState {
@@ -532,12 +562,7 @@
     public void autofill(AutofillValue value) {
         if (!isEnabled()) return;
 
-        if (!value.isDate()) {
-            Log.w(LOG_TAG, value + " could not be autofilled into " + this);
-            return;
-        }
-
-        mDelegate.setDate(value.getDateValue());
+        mDelegate.autofill(value);
     }
 
     @Override
@@ -547,6 +572,6 @@
 
     @Override
     public AutofillValue getAutofillValue() {
-        return isEnabled() ? AutofillValue.forDate(mDelegate.getDate()) : null;
+        return isEnabled() ? mDelegate.getAutofillValue() : null;
     }
 }
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 526246b..706b0ce 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -506,19 +506,29 @@
         mAmPmLayout.setLayoutParams(params);
     }
 
+    @Override
+    public void setDate(int hour, int minute) {
+        setHourInternal(hour, FROM_EXTERNAL_API, true, false);
+        setMinuteInternal(minute, FROM_EXTERNAL_API, false);
+
+        onTimeChanged();
+    }
+
     /**
      * Set the current hour.
      */
     @Override
     public void setHour(int hour) {
-        setHourInternal(hour, FROM_EXTERNAL_API, true);
+        setHourInternal(hour, FROM_EXTERNAL_API, true, true);
     }
 
-    private void setHourInternal(int hour, @ChangeSource int source, boolean announce) {
+    private void setHourInternal(int hour, @ChangeSource int source, boolean announce,
+            boolean notify) {
         if (mCurrentHour == hour) {
             return;
         }
 
+        resetAutofilledValue();
         mCurrentHour = hour;
         updateHeaderHour(hour, announce);
         updateHeaderAmPm();
@@ -532,7 +542,9 @@
         }
 
         mDelegator.invalidate();
-        onTimeChanged();
+        if (notify) {
+            onTimeChanged();
+        }
     }
 
     /**
@@ -557,14 +569,15 @@
      */
     @Override
     public void setMinute(int minute) {
-        setMinuteInternal(minute, FROM_EXTERNAL_API);
+        setMinuteInternal(minute, FROM_EXTERNAL_API, true);
     }
 
-    private void setMinuteInternal(int minute, @ChangeSource int source) {
+    private void setMinuteInternal(int minute, @ChangeSource int source, boolean notify) {
         if (mCurrentMinute == minute) {
             return;
         }
 
+        resetAutofilledValue();
         mCurrentMinute = minute;
         updateHeaderMinute(minute, true);
 
@@ -576,7 +589,9 @@
         }
 
         mDelegator.invalidate();
-        onTimeChanged();
+        if (notify) {
+            onTimeChanged();
+        }
     }
 
     /**
@@ -870,7 +885,7 @@
                         valueChanged = true;
                     }
                     final boolean isTransition = mAllowAutoAdvance && autoAdvance;
-                    setHourInternal(newValue, FROM_RADIAL_PICKER, !isTransition);
+                    setHourInternal(newValue, FROM_RADIAL_PICKER, !isTransition, true);
                     if (isTransition) {
                         setCurrentItemShowing(MINUTE_INDEX, true, false);
 
@@ -882,7 +897,7 @@
                     if (getMinute() != newValue) {
                         valueChanged = true;
                     }
-                    setMinuteInternal(newValue, FROM_RADIAL_PICKER);
+                    setMinuteInternal(newValue, FROM_RADIAL_PICKER, true);
                     break;
             }
 
@@ -897,10 +912,10 @@
         public void onValueChanged(int pickerType, int newValue) {
             switch (pickerType) {
                 case TextInputTimePickerView.HOURS:
-                    setHourInternal(newValue, FROM_INPUT_PICKER, false);
+                    setHourInternal(newValue, FROM_INPUT_PICKER, false, true);
                     break;
                 case TextInputTimePickerView.MINUTES:
-                    setMinuteInternal(newValue, FROM_INPUT_PICKER);
+                    setMinuteInternal(newValue, FROM_INPUT_PICKER, true);
                     break;
                 case TextInputTimePickerView.AMPM:
                     setAmOrPm(newValue);
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 7a7d9a9..cc79b9c 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -284,6 +284,14 @@
     }
 
     @Override
+    public void setDate(int hour, int minute) {
+        setCurrentHour(hour, false);
+        setCurrentMinute(minute, false);
+
+        onTimeChanged();
+    }
+
+    @Override
     public void setHour(int hour) {
         setCurrentHour(hour, true);
     }
@@ -293,6 +301,7 @@
         if (currentHour == getHour()) {
             return;
         }
+        resetAutofilledValue();
         if (!is24Hour()) {
             // convert [0,23] ordinal to wall clock display
             if (currentHour >= HOURS_IN_HALF_DAY) {
@@ -328,11 +337,18 @@
 
     @Override
     public void setMinute(int minute) {
+        setCurrentMinute(minute, true);
+    }
+
+    private void setCurrentMinute(int minute, boolean notifyTimeChanged) {
         if (minute == getMinute()) {
             return;
         }
+        resetAutofilledValue();
         mMinuteSpinner.setValue(minute);
-        onTimeChanged();
+        if (notifyTimeChanged) {
+            onTimeChanged();
+        }
     }
 
     @Override