Upstream version 10.38.220.0
[platform/framework/web/crosswalk.git] / src / content / public / android / java / src / org / chromium / content / browser / input / InputDialogContainer.java
index bca0f01..49123b2 100644 (file)
@@ -1,60 +1,42 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 package org.chromium.content.browser.input;
 
 import android.app.AlertDialog;
-import android.app.DatePickerDialog;
-import android.app.TimePickerDialog;
 import android.app.DatePickerDialog.OnDateSetListener;
-import android.app.TimePickerDialog.OnTimeSetListener;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnDismissListener;
-import android.text.TextUtils;
 import android.text.format.DateFormat;
-import android.text.format.Time;
+import android.view.View;
+import android.widget.AdapterView;
 import android.widget.DatePicker;
+import android.widget.ListView;
 import android.widget.TimePicker;
 
+import org.chromium.content.R;
 import org.chromium.content.browser.input.DateTimePickerDialog.OnDateTimeSetListener;
 import org.chromium.content.browser.input.MultiFieldTimePickerDialog.OnMultiFieldTimeSetListener;
-import org.chromium.content.browser.input.TwoFieldDatePickerDialog;
-import org.chromium.content.R;
 
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
+import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
 
+/**
+ * Opens the approprate date/time picker dialog for the given dialog type.
+ */
 public class InputDialogContainer {
 
     interface InputActionDelegate {
         void cancelDateTimeDialog();
-        void replaceDateTime(int dialogType,
-            int year, int month, int day, int hour, int minute, int second, int milli, int week);
+        void replaceDateTime(double value);
     }
 
-    // Default values used in Time representations of selected date/time before formatting.
-    // They are never displayed to the user.
-    private static final int YEAR_DEFAULT = 1970;
-    private static final int MONTH_DEFAULT = 0;
-    private static final int MONTHDAY_DEFAULT = 1;
-    private static final int HOUR_DEFAULT = 0;
-    private static final int MINUTE_DEFAULT = 0;
-    private static final int WEEK_DEFAULT = 0;
-
-    // Date formats as accepted by Time.format.
-    private static final String HTML_DATE_FORMAT = "%Y-%m-%d";
-    private static final String HTML_TIME_FORMAT = "%H:%M";
-    // For datetime we always send selected time as UTC, as we have no timezone selector.
-    // This is consistent with other browsers.
-    private static final String HTML_DATE_TIME_FORMAT = "%Y-%m-%dT%H:%MZ";
-    private static final String HTML_DATE_TIME_LOCAL_FORMAT = "%Y-%m-%dT%H:%M";
-    private static final String HTML_MONTH_FORMAT = "%Y-%m";
-    private static final String HTML_WEEK_FORMAT = "%Y-%w";
-
     private static int sTextInputTypeDate;
     private static int sTextInputTypeDateTime;
     private static int sTextInputTypeDateTimeLocal;
@@ -62,13 +44,13 @@ public class InputDialogContainer {
     private static int sTextInputTypeTime;
     private static int sTextInputTypeWeek;
 
-    private Context mContext;
+    private final Context mContext;
 
     // Prevents sending two notifications (from onClick and from onDismiss)
     private boolean mDialogAlreadyDismissed;
 
     private AlertDialog mDialog;
-    private InputActionDelegate mInputActionDelegate;
+    private final InputActionDelegate mInputActionDelegate;
 
     static void initializeInputTypes(int textInputTypeDate,
             int textInputTypeDateTime, int textInputTypeDateTimeLocal,
@@ -93,79 +75,183 @@ public class InputDialogContainer {
         mInputActionDelegate = inputActionDelegate;
     }
 
-    private Time normalizeTime(int year, int month, int monthDay,
-                               int hour, int minute, int second) {
-        Time result = new Time();
-        if (year == 0 && month == 0 && monthDay == 0 && hour == 0 &&
-                minute == 0 && second == 0) {
-            Calendar cal = Calendar.getInstance();
-            result.set(cal.get(Calendar.SECOND), cal.get(Calendar.MINUTE),
-                    cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.DATE),
-                    cal.get(Calendar.MONTH), cal.get(Calendar.YEAR));
+    void showPickerDialog(final int dialogType, double dialogValue,
+        double min, double max, double step) {
+        Calendar cal;
+        // |dialogValue|, |min|, |max| mean different things depending on the |dialogType|.
+        // For input type=month is the number of months since 1970.
+        // For input type=time it is milliseconds since midnight.
+        // For other types they are just milliseconds since 1970.
+        // If |dialogValue| is NaN it means an empty value. We will show the current time.
+        if (Double.isNaN(dialogValue)) {
+            cal = Calendar.getInstance();
+            cal.set(Calendar.MILLISECOND, 0);
+        } else {
+            if (dialogType == sTextInputTypeMonth) {
+                cal = MonthPicker.createDateFromValue(dialogValue);
+            } else if (dialogType == sTextInputTypeWeek) {
+                cal = WeekPicker.createDateFromValue(dialogValue);
+            } else {
+                GregorianCalendar gregorianCalendar =
+                        new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+                // According to the HTML spec we only use the Gregorian calendar
+                // so we ignore the Julian/Gregorian transition.
+                gregorianCalendar.setGregorianChange(new Date(Long.MIN_VALUE));
+                gregorianCalendar.setTimeInMillis((long) dialogValue);
+                cal =  gregorianCalendar;
+            }
+        }
+        if (dialogType == sTextInputTypeDate) {
+            showPickerDialog(dialogType,
+                    cal.get(Calendar.YEAR),
+                    cal.get(Calendar.MONTH),
+                    cal.get(Calendar.DAY_OF_MONTH),
+                    0, 0, 0, 0, 0, min, max, step);
+        } else if (dialogType == sTextInputTypeTime) {
+            showPickerDialog(dialogType, 0, 0, 0,
+                    cal.get(Calendar.HOUR_OF_DAY),
+                    cal.get(Calendar.MINUTE),
+                    0, 0, 0, min, max, step);
+        } else if (dialogType == sTextInputTypeDateTime ||
+                dialogType == sTextInputTypeDateTimeLocal) {
+            showPickerDialog(dialogType,
+                    cal.get(Calendar.YEAR),
+                    cal.get(Calendar.MONTH),
+                    cal.get(Calendar.DAY_OF_MONTH),
+                    cal.get(Calendar.HOUR_OF_DAY),
+                    cal.get(Calendar.MINUTE),
+                    cal.get(Calendar.SECOND),
+                    cal.get(Calendar.MILLISECOND),
+                    0, min, max, step);
+        } else if (dialogType == sTextInputTypeMonth) {
+            showPickerDialog(dialogType, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 0,
+                    0, 0, 0, 0, 0, min, max, step);
+        } else if (dialogType == sTextInputTypeWeek) {
+            int year = WeekPicker.getISOWeekYearForDate(cal);
+            int week = WeekPicker.getWeekForDate(cal);
+            showPickerDialog(dialogType, year, 0, 0, 0, 0, 0, 0, week, min, max, step);
+        }
+    }
+
+    void showSuggestionDialog(final int dialogType,
+            final double dialogValue,
+            final double min, final double max, final double step,
+            DateTimeSuggestion[] suggestions) {
+        ListView suggestionListView = new ListView(mContext);
+        final DateTimeSuggestionListAdapter adapter =
+            new DateTimeSuggestionListAdapter(mContext, Arrays.asList(suggestions));
+        suggestionListView.setAdapter(adapter);
+        suggestionListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                if (position == adapter.getCount() - 1) {
+                    dismissDialog();
+                    showPickerDialog(dialogType, dialogValue, min, max, step);
+                } else {
+                    double suggestionValue = adapter.getItem(position).value();
+                    mInputActionDelegate.replaceDateTime(suggestionValue);
+                    dismissDialog();
+                    mDialogAlreadyDismissed = true;
+                }
+            }
+        });
+
+        int dialogTitleId = R.string.date_picker_dialog_title;
+        if (dialogType == sTextInputTypeTime) {
+            dialogTitleId = R.string.time_picker_dialog_title;
+        } else if (dialogType == sTextInputTypeDateTime ||
+                dialogType == sTextInputTypeDateTimeLocal) {
+            dialogTitleId = R.string.date_time_picker_dialog_title;
+        } else if (dialogType == sTextInputTypeMonth) {
+            dialogTitleId = R.string.month_picker_dialog_title;
+        } else if (dialogType == sTextInputTypeWeek) {
+            dialogTitleId = R.string.week_picker_dialog_title;
+        }
+
+        mDialog = new AlertDialog.Builder(mContext)
+            .setTitle(dialogTitleId)
+            .setView(suggestionListView)
+            .setNegativeButton(mContext.getText(android.R.string.cancel),
+                new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        dismissDialog();
+                    }
+                })
+            .create();
+
+        mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+            @Override
+            public void onDismiss(DialogInterface dialog) {
+                if (mDialog == dialog && !mDialogAlreadyDismissed) {
+                    mDialogAlreadyDismissed = true;
+                    mInputActionDelegate.cancelDateTimeDialog();
+                }
+            }
+        });
+        mDialogAlreadyDismissed = false;
+        mDialog.show();
+    }
+
+    void showDialog(final int type, final double value,
+                    double min, double max, double step,
+                    DateTimeSuggestion[] suggestions) {
+        // When the web page asks to show a dialog while there is one already open,
+        // dismiss the old one.
+        dismissDialog();
+        if (suggestions == null) {
+            showPickerDialog(type, value, min, max, step);
         } else {
-            result.set(second, minute, hour, monthDay, month, year);
+            showSuggestionDialog(type, value, min, max, step, suggestions);
         }
-        return result;
     }
 
-    void showDialog(final int dialogType, int year, int month, int monthDay,
-                    int hour, int minute, int second, int milli, int week,
-                    double min, double max, double step) {
+    void showPickerDialog(final int dialogType,
+            int year, int month, int monthDay,
+            int hourOfDay, int minute, int second, int millis, int week,
+            double min, double max, double step) {
         if (isDialogShowing()) mDialog.dismiss();
 
-        // Java Date dialogs like longs but Blink prefers doubles..
-        // Both parameters mean different things depending on the type
-        // For input type=month min and max come as number on months since 1970
-        // For other types (including type=time) they are just milliseconds since 1970
-        // In any case the cast here is safe given the above restrictions.
-        long minTime = (long) min;
-        long maxTime = (long) max;
         int stepTime = (int) step;
 
-        if (milli > 1000) {
-            second += milli / 1000;
-            milli %= 1000;
-        }
-        Time time = normalizeTime(year, month, monthDay, hour, minute, second);
         if (dialogType == sTextInputTypeDate) {
-            DatePickerDialog dialog = new DatePickerDialog(mContext,
-                    new DateListener(dialogType), time.year, time.month, time.monthDay);
+            ChromeDatePickerDialog dialog = new ChromeDatePickerDialog(mContext,
+                    new DateListener(dialogType),
+                    year, month, monthDay);
             DateDialogNormalizer.normalize(dialog.getDatePicker(), dialog,
-                    time.year, time.month, time.monthDay, 0, 0, minTime, maxTime);
+                    year, month, monthDay,
+                    0, 0,
+                    (long) min, (long) max);
 
             dialog.setTitle(mContext.getText(R.string.date_picker_dialog_title));
             mDialog = dialog;
         } else if (dialogType == sTextInputTypeTime) {
             mDialog = new MultiFieldTimePickerDialog(
                 mContext, 0 /* theme */ ,
-                time.hour, time.minute, time.second, milli,
-                (int) minTime, (int) maxTime, stepTime,
+                hourOfDay, minute, second, millis,
+                (int) min, (int) max, stepTime,
                 DateFormat.is24HourFormat(mContext),
                 new FullTimeListener(dialogType));
         } else if (dialogType == sTextInputTypeDateTime ||
                 dialogType == sTextInputTypeDateTimeLocal) {
             mDialog = new DateTimePickerDialog(mContext,
                     new DateTimeListener(dialogType),
-                    time.year, time.month, time.monthDay,
-                    time.hour, time.minute, DateFormat.is24HourFormat(mContext),
-                    minTime, maxTime);
+                    year, month, monthDay,
+                    hourOfDay, minute,
+                    DateFormat.is24HourFormat(mContext), min, max);
         } else if (dialogType == sTextInputTypeMonth) {
             mDialog = new MonthPickerDialog(mContext, new MonthOrWeekListener(dialogType),
-                    time.year, time.month, minTime, maxTime);
+                    year, month, min, max);
         } else if (dialogType == sTextInputTypeWeek) {
-            if (week == 0) {
-                Calendar cal = Calendar.getInstance();
-                year = WeekPicker.getISOWeekYearForDate(cal);
-                week = WeekPicker.getWeekForDate(cal);
-            }
             mDialog = new WeekPickerDialog(mContext, new MonthOrWeekListener(dialogType),
-                    year, week, minTime, maxTime);
+                    year, week, min, max);
         }
 
         mDialog.setButton(DialogInterface.BUTTON_POSITIVE,
                 mContext.getText(R.string.date_picker_dialog_set),
                 (DialogInterface.OnClickListener) mDialog);
 
+
         mDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
                 mContext.getText(android.R.string.cancel),
                 (DialogInterface.OnClickListener) null);
@@ -176,12 +262,13 @@ public class InputDialogContainer {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
                         mDialogAlreadyDismissed = true;
-                        mInputActionDelegate.replaceDateTime(dialogType, 0, 0, 0, 0, 0, 0, 0, 0);
+                        mInputActionDelegate.replaceDateTime(Double.NaN);
                     }
                 });
 
         mDialog.setOnDismissListener(
                 new OnDismissListener() {
+                    @Override
                     public void onDismiss(final DialogInterface dialog) {
                         if (!mDialogAlreadyDismissed) {
                             mDialogAlreadyDismissed = true;
@@ -211,33 +298,11 @@ public class InputDialogContainer {
 
         @Override
         public void onDateSet(DatePicker view, int year, int month, int monthDay) {
-            if (!mDialogAlreadyDismissed) {
-                setFieldDateTimeValue(mDialogType,
-                        year, month, monthDay,
-                        HOUR_DEFAULT, MINUTE_DEFAULT, WEEK_DEFAULT,
-                        HTML_DATE_FORMAT);
-            }
-        }
-    }
-
-    private class TimeListener implements OnTimeSetListener {
-        private final int mDialogType;
-
-        TimeListener(int dialogType) {
-            mDialogType = dialogType;
-        }
-
-        @Override
-        public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
-            if (!mDialogAlreadyDismissed) {
-                setFieldDateTimeValue(mDialogType,
-                        YEAR_DEFAULT, MONTH_DEFAULT, MONTHDAY_DEFAULT,
-                        hourOfDay, minute, WEEK_DEFAULT, HTML_TIME_FORMAT);
-            }
+            setFieldDateTimeValue(mDialogType, year, month, monthDay, 0, 0, 0, 0, 0);
         }
     }
 
-  private class FullTimeListener implements OnMultiFieldTimeSetListener {
+    private class FullTimeListener implements OnMultiFieldTimeSetListener {
         private final int mDialogType;
         FullTimeListener(int dialogType) {
             mDialogType = dialogType;
@@ -245,11 +310,7 @@ public class InputDialogContainer {
 
         @Override
         public void onTimeSet(int hourOfDay, int minute, int second, int milli) {
-            if (!mDialogAlreadyDismissed) {
-                setFieldDateTimeValue(mDialogType,
-                        YEAR_DEFAULT, MONTH_DEFAULT, MONTHDAY_DEFAULT,
-                        hourOfDay, minute, second, milli, WEEK_DEFAULT, HTML_TIME_FORMAT);
-            }
+            setFieldDateTimeValue(mDialogType, 0, 0, 0, hourOfDay, minute, second, milli, 0);
         }
     }
 
@@ -266,11 +327,7 @@ public class InputDialogContainer {
         public void onDateTimeSet(DatePicker dateView, TimePicker timeView,
                 int year, int month, int monthDay,
                 int hourOfDay, int minute) {
-            if (!mDialogAlreadyDismissed) {
-                setFieldDateTimeValue(mDialogType, year, month, monthDay,
-                        hourOfDay, minute, WEEK_DEFAULT,
-                        mLocal ? HTML_DATE_TIME_LOCAL_FORMAT : HTML_DATE_TIME_FORMAT);
-            }
+            setFieldDateTimeValue(mDialogType, year, month, monthDay, hourOfDay, minute, 0, 0, 0);
         }
     }
 
@@ -283,38 +340,45 @@ public class InputDialogContainer {
 
         @Override
         public void onValueSet(int year, int positionInYear) {
-            if (!mDialogAlreadyDismissed) {
-                if (mDialogType == sTextInputTypeMonth) {
-                    setFieldDateTimeValue(mDialogType, year, positionInYear, MONTHDAY_DEFAULT,
-                            HOUR_DEFAULT, MINUTE_DEFAULT, WEEK_DEFAULT,
-                            HTML_MONTH_FORMAT);
-                } else {
-                    setFieldDateTimeValue(mDialogType, year, MONTH_DEFAULT, MONTHDAY_DEFAULT,
-                            HOUR_DEFAULT, MINUTE_DEFAULT, positionInYear, HTML_WEEK_FORMAT);
-                }
+            if (mDialogType == sTextInputTypeMonth) {
+                setFieldDateTimeValue(mDialogType, year, positionInYear, 0, 0, 0, 0, 0, 0);
+            } else {
+                setFieldDateTimeValue(mDialogType, year, 0, 0, 0, 0, 0, 0, positionInYear);
             }
         }
     }
 
-    private void setFieldDateTimeValue(int dialogType,
-            int year, int month, int monthDay, int hourOfDay,
-            int minute, int week, String dateFormat) {
-        // Prevents more than one callback being sent to the native
-        // side when the dialog triggers multiple events.
-        mDialogAlreadyDismissed = true;
-
-        mInputActionDelegate.replaceDateTime(dialogType,
-            year, month, monthDay, hourOfDay, minute, 0 /* second */, 0 /* milli */, week);
-    }
-
-    private void setFieldDateTimeValue(int dialogType,
-            int year, int month, int monthDay, int hourOfDay,
-            int minute, int second, int milli, int week, String dateFormat) {
+    protected void setFieldDateTimeValue(int dialogType,
+                                       int year, int month, int monthDay,
+                                       int hourOfDay, int minute, int second, int millis,
+                                       int week) {
         // Prevents more than one callback being sent to the native
         // side when the dialog triggers multiple events.
+        if (mDialogAlreadyDismissed)
+            return;
         mDialogAlreadyDismissed = true;
 
-        mInputActionDelegate.replaceDateTime(
-            dialogType, year, month, monthDay, hourOfDay, minute, second, milli, week);
+        if (dialogType == sTextInputTypeMonth) {
+            mInputActionDelegate.replaceDateTime((year - 1970) * 12 + month);
+        } else if (dialogType == sTextInputTypeWeek) {
+            mInputActionDelegate.replaceDateTime(
+                  WeekPicker.createDateFromWeek(year, week).getTimeInMillis());
+        } else if (dialogType == sTextInputTypeTime) {
+            mInputActionDelegate.replaceDateTime(TimeUnit.HOURS.toMillis(hourOfDay) +
+                                                 TimeUnit.MINUTES.toMillis(minute) +
+                                                 TimeUnit.SECONDS.toMillis(second) +
+                                                 millis);
+        } else {
+            Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+            cal.clear();
+            cal.set(Calendar.YEAR, year);
+            cal.set(Calendar.MONTH, month);
+            cal.set(Calendar.DAY_OF_MONTH, monthDay);
+            cal.set(Calendar.HOUR_OF_DAY, hourOfDay);
+            cal.set(Calendar.MINUTE, minute);
+            cal.set(Calendar.SECOND, second);
+            cal.set(Calendar.MILLISECOND, millis);
+            mInputActionDelegate.replaceDateTime(cal.getTimeInMillis());
+        }
     }
 }