Fix bug #7206086 NumberPicker widget should use locale digits

- fix for having the TwoDigitFormatter being able to be recreated if the locale is changed
- accept now also the Arabic and Persian digits

Change-Id: Ifbf7e274d971008f4a5782402d4b76d9472b68fc
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index b06da06..b834c8c 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -1573,7 +1573,8 @@
             // If we're showing the week number calculate it based on Monday
             int i = 0;
             if (mShowWeekNumber) {
-                mDayNumbers[0] = Integer.toString(mTempDate.get(Calendar.WEEK_OF_YEAR));
+                mDayNumbers[0] = String.format(Locale.getDefault(), "%d",
+                        mTempDate.get(Calendar.WEEK_OF_YEAR));
                 i++;
             }
 
@@ -1594,7 +1595,8 @@
                 if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) {
                     mDayNumbers[i] = "";
                 } else {
-                    mDayNumbers[i] = Integer.toString(mTempDate.get(Calendar.DAY_OF_MONTH));
+                    mDayNumbers[i] = String.format(Locale.getDefault(), "%d",
+                            mTempDate.get(Calendar.DAY_OF_MONTH));
                 }
                 mTempDate.add(Calendar.DAY_OF_MONTH, 1);
             }
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index ac3bedb..07d3a7a 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -220,7 +220,7 @@
 
         // day
         mDaySpinner = (NumberPicker) findViewById(R.id.day);
-        mDaySpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
+        mDaySpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
         mDaySpinner.setOnLongPressUpdateInterval(100);
         mDaySpinner.setOnValueChangedListener(onChangeListener);
         mDaySpinnerInput = (EditText) mDaySpinner.findViewById(R.id.numberpicker_input);
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index dbc777e..b4c11d5 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -51,10 +51,12 @@
 import android.view.inputmethod.InputMethodManager;
 
 import com.android.internal.R;
+import libcore.icu.LocaleData;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 
 /**
  * A widget that enables the user to select a number form a predefined range.
@@ -138,13 +140,6 @@
     private static final int DEFAULT_LAYOUT_RESOURCE_ID = R.layout.number_picker;
 
     /**
-     * The numbers accepted by the input text's {@link Filter}
-     */
-    private static final char[] DIGIT_CHARACTERS = new char[] {
-            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
-    };
-
-    /**
      * Constant for unspecified size.
      */
     private static final int SIZE_UNSPECIFIED = -1;
@@ -155,22 +150,51 @@
      * way to do this; it avoids creating temporary objects on every call to
      * format().
      *
-     * @hide
      */
-    public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = new NumberPicker.Formatter() {
+    private static class TwoDigitFormatter implements NumberPicker.Formatter {
         final StringBuilder mBuilder = new StringBuilder();
 
-        final java.util.Formatter mFmt = new java.util.Formatter(mBuilder, java.util.Locale.US);
+        char mZeroDigit;
+        java.util.Formatter mFmt;
 
         final Object[] mArgs = new Object[1];
 
+        TwoDigitFormatter() {
+            final Locale locale = Locale.getDefault();
+            init(locale);
+        }
+
+        private void init(Locale locale) {
+            mFmt = createFormatter(locale);
+            mZeroDigit = getZeroDigit(locale);
+        }
+
         public String format(int value) {
+            final Locale currentLocale = Locale.getDefault();
+            if (mZeroDigit != getZeroDigit(currentLocale)) {
+                init(currentLocale);
+            }
             mArgs[0] = value;
             mBuilder.delete(0, mBuilder.length());
             mFmt.format("%02d", mArgs);
             return mFmt.toString();
         }
-    };
+
+        private static char getZeroDigit(Locale locale) {
+            return LocaleData.get(locale).zeroDigit;
+        }
+
+        private java.util.Formatter createFormatter(Locale locale) {
+            return new java.util.Formatter(mBuilder, locale);
+        }
+    }
+
+    private static final TwoDigitFormatter sTwoDigitFormatter = new TwoDigitFormatter();
+
+    static final Formatter getTwoDigitFormatter() {
+        return sTwoDigitFormatter;
+    }
+
 
     /**
      * The increment button.
@@ -1156,7 +1180,7 @@
         if (mDisplayedValues == null) {
             float maxDigitWidth = 0;
             for (int i = 0; i <= 9; i++) {
-                final float digitWidth = mSelectorWheelPaint.measureText(String.valueOf(i));
+                final float digitWidth = mSelectorWheelPaint.measureText(formatNumberWithLocale(i));
                 if (digitWidth > maxDigitWidth) {
                     maxDigitWidth = digitWidth;
                 }
@@ -1689,7 +1713,7 @@
     }
 
     private String formatNumber(int value) {
-        return (mFormatter != null) ? mFormatter.format(value) : String.valueOf(value);
+        return (mFormatter != null) ? mFormatter.format(value) : formatNumberWithLocale(value);
     }
 
     private void validateInputTextView(View v) {
@@ -1849,6 +1873,20 @@
     }
 
     /**
+     * The numbers accepted by the input text's {@link Filter}
+     */
+    private static final char[] DIGIT_CHARACTERS = new char[] {
+            // Latin digits are the common case
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+            // Arabic-Indic
+            '\u0660', '\u0661', '\u0662', '\u0663', '\u0664', '\u0665', '\u0666', '\u0667', '\u0668'
+            , '\u0669',
+            // Extended Arabic-Indic
+            '\u06f0', '\u06f1', '\u06f2', '\u06f3', '\u06f4', '\u06f5', '\u06f6', '\u06f7', '\u06f8'
+            , '\u06f9'
+    };
+
+    /**
      * Filter for accepting only valid indices or prefixes of the string
      * representation of valid indices.
      */
@@ -2493,4 +2531,8 @@
             return null;
         }
     }
+
+    static private String formatNumberWithLocale(int value) {
+        return String.format(Locale.getDefault(), "%d", value);
+    }
 }
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index cb9ed61..e6796cb 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -172,7 +172,7 @@
         mMinuteSpinner.setMinValue(0);
         mMinuteSpinner.setMaxValue(59);
         mMinuteSpinner.setOnLongPressUpdateInterval(100);
-        mMinuteSpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
+        mMinuteSpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
         mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
             public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
                 updateInputState();
@@ -500,7 +500,7 @@
         if (is24HourView()) {
             mHourSpinner.setMinValue(0);
             mHourSpinner.setMaxValue(23);
-            mHourSpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
+            mHourSpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
         } else {
             mHourSpinner.setMinValue(1);
             mHourSpinner.setMaxValue(12);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/DatePicker.java b/tests/HwAccelerationTest/src/com/android/test/hwui/DatePicker.java
index db247e3..eb4e3fd 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/DatePicker.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/DatePicker.java
@@ -102,7 +102,7 @@
         inflater.inflate(R.layout.date_picker, this, true);
 
         mDayPicker = (NumberPicker) findViewById(R.id.day);
-        mDayPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
+        mDayPicker.setFormatter(NumberPicker.getTwoDigitFormatter());
         mDayPicker.setOnLongPressUpdateInterval(100);
         mDayPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
             public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
@@ -111,7 +111,7 @@
             }
         });
         mMonthPicker = (NumberPicker) findViewById(R.id.month);
-        mMonthPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
+        mMonthPicker.setFormatter(NumberPicker.getTwoDigitFormatter());
         DateFormatSymbols dfs = new DateFormatSymbols();
         String[] months = dfs.getShortMonths();