diff options
author | keishi@chromium.org <keishi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-07 02:56:17 +0000 |
---|---|---|
committer | keishi@chromium.org <keishi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-07 02:56:17 +0000 |
commit | 6e08bfb743b8dcf8b7ae3052c685b0ef284aa737 (patch) | |
tree | 0b3ecd219a0cf41f798afee689360ac630b965fa | |
parent | 14e864b164494e7c3dae5a53d2956eef91b1f19f (diff) | |
download | chromium_src-6e08bfb743b8dcf8b7ae3052c685b0ef284aa737.zip chromium_src-6e08bfb743b8dcf8b7ae3052c685b0ef284aa737.tar.gz chromium_src-6e08bfb743b8dcf8b7ae3052c685b0ef284aa737.tar.bz2 |
Support datalist for date/time input types on Android
BUG=242455
Review URL: https://codereview.chromium.org/23623019
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@239290 0039d316-1c4b-4281-b951-d872f2087c98
19 files changed, 454 insertions, 56 deletions
diff --git a/content/browser/android/date_time_chooser_android.cc b/content/browser/android/date_time_chooser_android.cc index 87f02b9f..f6b50c9 100644 --- a/content/browser/android/date_time_chooser_android.cc +++ b/content/browser/android/date_time_chooser_android.cc @@ -4,17 +4,41 @@ #include "content/browser/android/date_time_chooser_android.h" +#include "base/android/jni_android.h" #include "base/android/jni_string.h" +#include "base/i18n/char_iterator.h" +#include "content/common/date_time_suggestion.h" #include "content/common/view_messages.h" #include "content/public/browser/android/content_view_core.h" #include "content/public/browser/render_view_host.h" #include "jni/DateTimeChooserAndroid_jni.h" +#include "third_party/icu/source/common/unicode/uchar.h" +#include "third_party/icu/source/common/unicode/unistr.h" using base::android::AttachCurrentThread; using base::android::ConvertJavaStringToUTF16; using base::android::ConvertUTF8ToJavaString; +using base::android::ConvertUTF16ToJavaString; +namespace { + +string16 SanitizeSuggestionString(const string16& string) { + string16 trimmed = string.substr(0, 255); + icu::UnicodeString sanitized; + base::i18n::UTF16CharIterator sanitized_iterator(&trimmed); + while (!sanitized_iterator.end()) { + UChar c = sanitized_iterator.get(); + if (u_isprint(c)) + sanitized.append(c); + sanitized_iterator.Advance(); + } + return string16(sanitized.getBuffer(), + static_cast<size_t>(sanitized.length())); +} + +} // namespace + namespace content { // DateTimeChooserAndroid implementation @@ -55,10 +79,29 @@ void DateTimeChooserAndroid::ShowDialog( double dialog_value, double min, double max, - double step) { + double step, + const std::vector<DateTimeSuggestion>& suggestions) { host_ = host; JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobjectArray> suggestions_array; + + if (suggestions.size() > 0) { + suggestions_array = + Java_DateTimeChooserAndroid_createSuggestionsArray(env, + suggestions.size()); + for (size_t i = 0; i < suggestions.size(); ++i) { + const content::DateTimeSuggestion& suggestion = suggestions[i]; + ScopedJavaLocalRef<jstring> localized_value = ConvertUTF16ToJavaString( + env, SanitizeSuggestionString(suggestion.localized_value)); + ScopedJavaLocalRef<jstring> label = ConvertUTF16ToJavaString( + env, SanitizeSuggestionString(suggestion.label)); + Java_DateTimeChooserAndroid_setDateTimeSuggestionAt(env, + suggestions_array.obj(), i, + suggestion.value, localized_value.obj(), label.obj()); + } + } + j_date_time_chooser_.Reset(Java_DateTimeChooserAndroid_createDateTimeChooser( env, content->GetJavaObject().obj(), @@ -67,7 +110,8 @@ void DateTimeChooserAndroid::ShowDialog( dialog_value, min, max, - step)); + step, + suggestions_array.obj())); } // ---------------------------------------------------------------------------- diff --git a/content/browser/android/date_time_chooser_android.h b/content/browser/android/date_time_chooser_android.h index a04850f..c02ecf5 100644 --- a/content/browser/android/date_time_chooser_android.h +++ b/content/browser/android/date_time_chooser_android.h @@ -6,6 +6,7 @@ #define CONTENT_BROWSER_ANDROID_DATE_TIME_CHOOSER_ANDROID_H_ #include <string> +#include <vector> #include "base/android/jni_helper.h" #include "base/memory/scoped_ptr.h" @@ -15,6 +16,7 @@ namespace content { class ContentViewCore; class RenderViewHost; +struct DateTimeSuggestion; // Android implementation for DateTimeChooser dialogs. class DateTimeChooserAndroid { @@ -31,7 +33,8 @@ class DateTimeChooserAndroid { double dialog_value, double min, double max, - double step); + double step, + const std::vector<DateTimeSuggestion>& suggestions); // Replaces the current value void ReplaceDateTime(JNIEnv* env, jobject, jdouble value); diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index bb681ed..81edfed 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc @@ -2376,7 +2376,8 @@ void WebContentsImpl::OnOpenDateTimeDialog( value.dialog_value, value.minimum, value.maximum, - value.step); + value.step, + value.suggestions); } void WebContentsImpl::OnJavaBridgeGetChannelHandle(IPC::Message* reply_msg) { diff --git a/content/common/date_time_suggestion.h b/content/common/date_time_suggestion.h new file mode 100644 index 0000000..ce35430 --- /dev/null +++ b/content/common/date_time_suggestion.h @@ -0,0 +1,31 @@ +// Copyright 2013 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. + +#ifndef CONTENT_COMMON_DATE_TIME_SUGGESTION_H_ +#define CONTENT_COMMON_DATE_TIME_SUGGESTION_H_ + +#include <vector> + +#include "base/strings/string16.h" +#include "content/common/content_export.h" +#include "third_party/skia/include/core/SkColor.h" + +namespace content { + +// Container for information about datalist suggestion for the date/time input +// control. Keep in sync with DateTimeSuggestion.java +struct CONTENT_EXPORT DateTimeSuggestion { + DateTimeSuggestion() {} + + // The date/time value represented as a double. + double value; + // The localized value to be shown to the user. + base::string16 localized_value; + // The label for the suggestion. + base::string16 label; +}; + +} // namespace content + +#endif // CONTENT_COMMON_DATE_TIME_SUGGESTION_H_ diff --git a/content/common/view_messages.h b/content/common/view_messages.h index a5dc8b9..edf8337 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h @@ -35,6 +35,7 @@ #include "content/public/common/stop_find_action.h" #include "content/public/common/three_d_api_types.h" #include "content/public/common/window_container_type.h" +#include "content/common/date_time_suggestion.h" #include "ipc/ipc_channel_handle.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_platform_file.h" @@ -165,6 +166,12 @@ IPC_STRUCT_TRAITS_BEGIN(content::ColorSuggestion) IPC_STRUCT_TRAITS_MEMBER(label) IPC_STRUCT_TRAITS_END() +IPC_STRUCT_TRAITS_BEGIN(content::DateTimeSuggestion) + IPC_STRUCT_TRAITS_MEMBER(value) + IPC_STRUCT_TRAITS_MEMBER(localized_value) + IPC_STRUCT_TRAITS_MEMBER(label) +IPC_STRUCT_TRAITS_END() + IPC_STRUCT_TRAITS_BEGIN(content::ContextMenuParams) IPC_STRUCT_TRAITS_MEMBER(media_type) IPC_STRUCT_TRAITS_MEMBER(x) @@ -404,6 +411,7 @@ IPC_STRUCT_BEGIN(ViewHostMsg_DateTimeDialogValue_Params) IPC_STRUCT_MEMBER(double, minimum) IPC_STRUCT_MEMBER(double, maximum) IPC_STRUCT_MEMBER(double, step) + IPC_STRUCT_MEMBER(std::vector<content::DateTimeSuggestion>, suggestions) IPC_STRUCT_END() IPC_STRUCT_BEGIN(ViewHostMsg_DidFailProvisionalLoadWithError_Params) diff --git a/content/content_common.gypi b/content/content_common.gypi index e49acba..395b710 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -152,6 +152,7 @@ 'common/cookie_data.cc', 'common/cookie_data.h', 'common/database_messages.h', + 'common/date_time_suggestion.h', 'common/desktop_notification_messages.h', 'common/device_orientation/device_motion_hardware_buffer.h', 'common/device_orientation/device_motion_messages.h', diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 0dad876..8b949de 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -102,6 +102,8 @@ 'renderer/context_menu_params_builder.h', 'renderer/cursor_utils.cc', 'renderer/cursor_utils.h', + 'renderer/date_time_suggestion_builder.cc', + 'renderer/date_time_suggestion_builder.h', 'renderer/device_orientation/device_motion_event_pump.cc', 'renderer/device_orientation/device_motion_event_pump.h', 'renderer/device_orientation/device_orientation_event_pump.cc', diff --git a/content/public/android/java/resource_map/org/chromium/content/R.java b/content/public/android/java/resource_map/org/chromium/content/R.java index 44d0859..ac39779 100644 --- a/content/public/android/java/resource_map/org/chromium/content/R.java +++ b/content/public/android/java/resource_map/org/chromium/content/R.java @@ -29,6 +29,8 @@ public final class R { public static final class id { public static int ampm; public static int date_picker; + public static int date_time_suggestion_value; + public static int date_time_suggestion_label; public static int hour; public static int milli; public static int minute; @@ -48,6 +50,7 @@ public final class R { } public static final class layout { public static int date_time_picker_dialog; + public static int date_time_suggestion; public static int two_field_date_picker; public static int multi_field_time_picker_dialog; } @@ -66,6 +69,7 @@ public final class R { public static int date_picker_dialog_clear; public static int date_picker_dialog_set; public static int date_picker_dialog_title; + public static int date_picker_dialog_other_button_label; public static int date_time_picker_dialog_title; public static int media_player_error_button; public static int media_player_error_text_invalid_progressive_playback; @@ -82,6 +86,7 @@ public final class R { public static int time_picker_dialog_minute_second_separator; public static int time_picker_dialog_second_subsecond_separator; public static int time_picker_dialog_pm; + public static int time_picker_dialog_title; public static int week_picker_dialog_title; } public static final class style { diff --git a/content/public/android/java/src/org/chromium/content/browser/input/DateDialogNormalizer.java b/content/public/android/java/src/org/chromium/content/browser/input/DateDialogNormalizer.java index 4634808..709d0e7 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/DateDialogNormalizer.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/DateDialogNormalizer.java @@ -15,15 +15,15 @@ import java.util.TimeZone; */ class DateDialogNormalizer { - private static void setLimits(DatePicker picker, long min, long max) { + private static void setLimits(DatePicker picker, long minMillis, long maxMillis) { // DatePicker intervals are non inclusive, the DatePicker will throw an // exception when setting the min/max attribute to the current date // so make sure this never happens - if (max <= min) { + if (maxMillis <= minMillis) { return; } - Calendar minCal = trimToDate(min); - Calendar maxCal = trimToDate(max); + Calendar minCal = trimToDate(minMillis); + Calendar maxCal = trimToDate(maxMillis); int currentYear = picker.getYear(); int currentMonth = picker.getMonth(); int currentDayOfMonth = picker.getDayOfMonth(); @@ -57,21 +57,21 @@ class DateDialogNormalizer { * needed to comply with the {@code min} and {@code max} attributes. */ static void normalize(DatePicker picker, OnDateChangedListener listener, - int year, int month, int day, int hour, int minute, long min, long max) { + int year, int month, int day, int hour, int minute, long minMillis, long maxMillis) { Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT")); calendar.clear(); calendar.set(year, month, day, hour, minute, 0); - if (calendar.getTimeInMillis() < min) { + if (calendar.getTimeInMillis() < minMillis) { calendar.clear(); - calendar.setTimeInMillis(min); - } else if (calendar.getTimeInMillis() > max) { + calendar.setTimeInMillis(minMillis); + } else if (calendar.getTimeInMillis() > maxMillis) { calendar.clear(); - calendar.setTimeInMillis(max); + calendar.setTimeInMillis(maxMillis); } picker.init( calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), listener); - setLimits(picker, min, max); + setLimits(picker, minMillis, maxMillis); } } diff --git a/content/public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java b/content/public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java index a45bc57..8cc41ff9 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java @@ -38,8 +38,9 @@ class DateTimeChooserAndroid { } private void showDialog(int dialogType, double dialogValue, - double min, double max, double step) { - mInputDialogContainer.showDialog(dialogType, dialogValue, min, max, step); + double min, double max, double step, + DateTimeSuggestion[] suggestions) { + mInputDialogContainer.showDialog(dialogType, dialogValue, min, max, step, suggestions); } @CalledByNative @@ -47,21 +48,41 @@ class DateTimeChooserAndroid { ContentViewCore contentViewCore, long nativeDateTimeChooserAndroid, int dialogType, double dialogValue, - double min, double max, double step) { + double min, double max, double step, + DateTimeSuggestion[] suggestions) { DateTimeChooserAndroid chooser = new DateTimeChooserAndroid( contentViewCore.getContext(), nativeDateTimeChooserAndroid); - chooser.showDialog(dialogType, dialogValue, min, max, step); + chooser.showDialog(dialogType, dialogValue, min, max, step, suggestions); return chooser; } @CalledByNative + private static DateTimeSuggestion[] createSuggestionsArray(int size) { + return new DateTimeSuggestion[size]; + } + + /** + * @param array DateTimeSuggestion array that should get a new suggestion set. + * @param index Index in the array where to place a new suggestion. + * @param value Value of the suggestion. + * @param localizedValue Localized value of the suggestion. + * @param label Label of the suggestion. + */ + @CalledByNative + private static void setDateTimeSuggestionAt(DateTimeSuggestion[] array, int index, + double value, String localizedValue, String label) { + array[index] = new DateTimeSuggestion(value, localizedValue, label); + } + + @CalledByNative private static void initializeDateInputTypes( int textInputTypeDate, int textInputTypeDateTime, int textInputTypeDateTimeLocal, int textInputTypeMonth, int textInputTypeTime, int textInputTypeWeek) { - InputDialogContainer.initializeInputTypes(textInputTypeDate, + InputDialogContainer.initializeInputTypes( + textInputTypeDate, textInputTypeDateTime, textInputTypeDateTimeLocal, textInputTypeMonth, textInputTypeTime, textInputTypeWeek); } diff --git a/content/public/android/java/src/org/chromium/content/browser/input/DateTimeSuggestion.java b/content/public/android/java/src/org/chromium/content/browser/input/DateTimeSuggestion.java new file mode 100644 index 0000000..5416c31 --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/browser/input/DateTimeSuggestion.java @@ -0,0 +1,59 @@ +// Copyright 2013 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; + +/** + * Date/time suggestion container used to store information for each suggestion that will be shown + * in the suggestion list dialog. Keep in sync with date_time_suggestion.h. + */ +class DateTimeSuggestion { + private final double mValue; + private final String mLocalizedValue; + private final String mLabel; + + /** + * Constructs a color suggestion container. + * @param value The suggested date/time value. + * @param localizedValue The suggested value localized. + * @param label The label for the suggestion. + */ + DateTimeSuggestion(double value, String localizedValue, String label) { + mValue = value; + mLocalizedValue = localizedValue; + mLabel = label; + } + + double value() { + return mValue; + } + + String localizedValue() { + return mLocalizedValue; + } + + String label() { + return mLabel; + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof DateTimeSuggestion)) { + return false; + } + final DateTimeSuggestion other = (DateTimeSuggestion) object; + return mValue == other.mValue && + mLocalizedValue == other.mLocalizedValue && + mLabel == other.mLabel; + } + + @Override + public int hashCode() { + int hash = 31; + hash = 37 * hash + (int) mValue; + hash = 37 * hash + mLocalizedValue.hashCode(); + hash = 37 * hash + mLabel.hashCode(); + return hash; + } +} diff --git a/content/public/android/java/src/org/chromium/content/browser/input/DateTimeSuggestionListAdapter.java b/content/public/android/java/src/org/chromium/content/browser/input/DateTimeSuggestionListAdapter.java new file mode 100644 index 0000000..7e6a980 --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/browser/input/DateTimeSuggestionListAdapter.java @@ -0,0 +1,56 @@ +// Copyright 2013 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.content.Context; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +import org.chromium.content.R; + +import java.util.List; + +/** + * Date/time suggestion adapter for the suggestion dialog. + */ +class DateTimeSuggestionListAdapter extends ArrayAdapter<DateTimeSuggestion> { + private final Context mContext; + + DateTimeSuggestionListAdapter(Context context, List<DateTimeSuggestion> objects) { + super(context, R.layout.date_time_suggestion, objects); + mContext = context; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View layout = convertView; + if (convertView == null) { + LayoutInflater inflater = LayoutInflater.from(mContext); + layout = inflater.inflate(R.layout.date_time_suggestion, parent, false); + } + TextView labelView = (TextView) layout.findViewById(R.id.date_time_suggestion_value); + TextView sublabelView = (TextView) layout.findViewById(R.id.date_time_suggestion_label); + + if (position == getCount() - 1) { + labelView.setText(mContext.getText(R.string.date_picker_dialog_other_button_label)); + sublabelView.setText(""); + } else { + labelView.setText(getItem(position).localizedValue()); + sublabelView.setText(getItem(position).label()); + } + + return layout; + } + + @Override + public int getCount() { + return super.getCount() + 1; + } +} diff --git a/content/public/android/java/src/org/chromium/content/browser/input/InputDialogContainer.java b/content/public/android/java/src/org/chromium/content/browser/input/InputDialogContainer.java index 7ec81cb..22ebfef 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/InputDialogContainer.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/InputDialogContainer.java @@ -13,13 +13,19 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnDismissListener; 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.SimpleAdapter; +import android.widget.TextView; 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 java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; @@ -71,7 +77,7 @@ public class InputDialogContainer { mInputActionDelegate = inputActionDelegate; } - void showDialog(final int dialogType, double dialogValue, + 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|. @@ -98,19 +104,19 @@ public class InputDialogContainer { } } if (dialogType == sTextInputTypeDate) { - showDialog(dialogType, + 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) { - showDialog(dialogType, 0, 0, 0, + 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) { - showDialog(dialogType, + showPickerDialog(dialogType, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), @@ -120,16 +126,89 @@ public class InputDialogContainer { cal.get(Calendar.MILLISECOND), 0, min, max, step); } else if (dialogType == sTextInputTypeMonth) { - showDialog(dialogType, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 0, + 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); - showDialog(dialogType, year, 0, 0, 0, 0, 0, 0, week, min, max, step); + showPickerDialog(dialogType, year, 0, 0, 0, 0, 0, 0, week, min, max, step); } } - void showDialog(final int dialogType, + 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) + .setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + if (mDialog == dialog && !mDialogAlreadyDismissed) { + mDialogAlreadyDismissed = true; + mInputActionDelegate.cancelDateTimeDialog(); + } + } + }) + .setNegativeButton(mContext.getText(android.R.string.cancel), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dismissDialog(); + } + }) + .create(); + + 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 { + showSuggestionDialog(type, value, min, max, step, suggestions); + } + } + + 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) { @@ -293,14 +372,14 @@ public class InputDialogContainer { 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); + 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((double) cal.getTimeInMillis()); } } diff --git a/content/public/android/java/strings/android_content_strings.grd b/content/public/android/java/strings/android_content_strings.grd index 2ec7d77..580dd79 100644 --- a/content/public/android/java/strings/android_content_strings.grd +++ b/content/public/android/java/strings/android_content_strings.grd @@ -11,14 +11,17 @@ <message desc="Content description for the content view that holds the web contents [CHAR-LIMIT=32]" name="IDS_ACCESSIBILITY_CONTENT_VIEW"> Web View </message> + <message desc="Title for the date picker dialog, which can be used to choose a date. [CHAR-LIMIT=32]" name="IDS_DATE_PICKER_DIALOG_TITLE"> + Set date + </message> <message desc="Label for 'set' button in date picker dialog and time picker dialog, used to replace the contents of a field with the chosen date or time [CHAR-LIMIT=12]" name="IDS_DATE_PICKER_DIALOG_SET"> Set </message> <message desc="Label for 'clear' button in date picker dialog and time picker dialog, used to replace the contents of a field with the empty string [CHAR-LIMIT=12]" name="IDS_DATE_PICKER_DIALOG_CLEAR"> Clear </message> - <message desc="Title for the date picker dialog, which can be used to choose a date. [CHAR-LIMIT=32]" name="IDS_DATE_PICKER_DIALOG_TITLE"> - Set date + <message desc="Label for 'other' button in date picker dialog and time picker dialog, used to close the list of suggestions and open the the full date/time picker [CHAR-LIMIT=32]" name="IDS_DATE_PICKER_DIALOG_OTHER_BUTTON_LABEL"> + Other </message> <message desc="Title for the date/time picker dialog, which can be used to choose a date and time. [CHAR-LIMIT=32]" name="IDS_DATE_TIME_PICKER_DIALOG_TITLE"> Set date and time diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/InputDialogContainerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/InputDialogContainerTest.java index 235a859..003a92f 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/input/InputDialogContainerTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/input/InputDialogContainerTest.java @@ -54,28 +54,28 @@ public class InputDialogContainerTest extends AndroidTestCase { 1970, 0, 1, 0, 0, 0, 0, 0, DATE_DIALOG_DEFAULT_MIN, DATE_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_DATE, 0.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_DATE, 0.0, DATE_DIALOG_DEFAULT_MIN, DATE_DIALOG_DEFAULT_MAX, 1.0); mInputDialogContainer.setShowDialogExpectation(TEXT_INPUT_TYPE_DATE, 1, 0, 1, 0, 0, 0, 0, 0, DATE_DIALOG_DEFAULT_MIN, DATE_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_DATE, -62135596800000.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_DATE, -62135596800000.0, DATE_DIALOG_DEFAULT_MIN, DATE_DIALOG_DEFAULT_MAX, 1.0); mInputDialogContainer.setShowDialogExpectation(TEXT_INPUT_TYPE_DATE, 275760, 8, 13, 0, 0, 0, 0, 0, DATE_DIALOG_DEFAULT_MIN, DATE_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_DATE, 8640000000000000.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_DATE, 8640000000000000.0, DATE_DIALOG_DEFAULT_MIN, DATE_DIALOG_DEFAULT_MAX, 1.0); mInputDialogContainer.setShowDialogExpectation(TEXT_INPUT_TYPE_DATE, 2013, 10, 7, 0, 0, 0, 0, 0, DATE_DIALOG_DEFAULT_MIN, DATE_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_DATE, 1383782400000.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_DATE, 1383782400000.0, DATE_DIALOG_DEFAULT_MIN, DATE_DIALOG_DEFAULT_MAX, 1.0); } @@ -86,28 +86,28 @@ public class InputDialogContainerTest extends AndroidTestCase { 1970, 0, 1, 0, 0, 0, 0, 0, DATETIMELOCAL_DIALOG_DEFAULT_MIN, DATETIMELOCAL_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_DATETIMELOCAL, 0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_DATETIMELOCAL, 0, DATETIMELOCAL_DIALOG_DEFAULT_MIN, DATETIMELOCAL_DIALOG_DEFAULT_MAX, 1.0); mInputDialogContainer.setShowDialogExpectation(TEXT_INPUT_TYPE_DATETIMELOCAL, 1, 0, 1, 0, 0, 0, 0, 0, DATETIMELOCAL_DIALOG_DEFAULT_MIN, DATETIMELOCAL_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_DATETIMELOCAL, -62135596800000.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_DATETIMELOCAL, -62135596800000.0, DATETIMELOCAL_DIALOG_DEFAULT_MIN, DATETIMELOCAL_DIALOG_DEFAULT_MAX, 1.0); mInputDialogContainer.setShowDialogExpectation(TEXT_INPUT_TYPE_DATETIMELOCAL, 275760, 8, 13, 0, 0, 0, 0, 0, DATETIMELOCAL_DIALOG_DEFAULT_MIN, DATETIMELOCAL_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_DATETIMELOCAL, 8640000000000000.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_DATETIMELOCAL, 8640000000000000.0, DATETIMELOCAL_DIALOG_DEFAULT_MIN, DATETIMELOCAL_DIALOG_DEFAULT_MAX, 1.0); mInputDialogContainer.setShowDialogExpectation(TEXT_INPUT_TYPE_DATETIMELOCAL, 2013, 10, 8, 1, 1, 2, 196, 0, DATETIMELOCAL_DIALOG_DEFAULT_MIN, DATETIMELOCAL_DIALOG_DEFAULT_MAX, 0.001); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_DATETIMELOCAL, 1383872462196.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_DATETIMELOCAL, 1383872462196.0, DATETIMELOCAL_DIALOG_DEFAULT_MIN, DATETIMELOCAL_DIALOG_DEFAULT_MAX, 0.001); } @@ -118,28 +118,28 @@ public class InputDialogContainerTest extends AndroidTestCase { 1970, 0, 0, 0, 0, 0, 0, 0, MONTH_DIALOG_DEFAULT_MIN, MONTH_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_MONTH, 0.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_MONTH, 0.0, MONTH_DIALOG_DEFAULT_MIN, MONTH_DIALOG_DEFAULT_MAX, 1.0); mInputDialogContainer.setShowDialogExpectation(TEXT_INPUT_TYPE_MONTH, 1, 0, 0, 0, 0, 0, 0, 0, MONTH_DIALOG_DEFAULT_MIN, MONTH_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_MONTH, -23628.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_MONTH, -23628.0, MONTH_DIALOG_DEFAULT_MIN, MONTH_DIALOG_DEFAULT_MAX, 1.0); mInputDialogContainer.setShowDialogExpectation(TEXT_INPUT_TYPE_MONTH, 275760, 8, 0, 0, 0, 0, 0, 0, MONTH_DIALOG_DEFAULT_MIN, MONTH_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_MONTH, 3285488.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_MONTH, 3285488.0, MONTH_DIALOG_DEFAULT_MIN, MONTH_DIALOG_DEFAULT_MAX, 1.0); mInputDialogContainer.setShowDialogExpectation(TEXT_INPUT_TYPE_MONTH, 2013, 10, 0, 0, 0, 0, 0, 0, MONTH_DIALOG_DEFAULT_MIN, MONTH_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_MONTH, 526.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_MONTH, 526.0, MONTH_DIALOG_DEFAULT_MIN, MONTH_DIALOG_DEFAULT_MAX, 1.0); } @@ -150,7 +150,7 @@ public class InputDialogContainerTest extends AndroidTestCase { 0, 0, 0, 0, 0, 0, 0, 0, TIME_DIALOG_DEFAULT_MIN, TIME_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_TIME, 0.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_TIME, 0.0, TIME_DIALOG_DEFAULT_MIN, TIME_DIALOG_DEFAULT_MAX, 1.0); // Time dialog only shows the hour and minute fields. @@ -158,14 +158,14 @@ public class InputDialogContainerTest extends AndroidTestCase { 0, 0, 0, 23, 59, 0, 0, 0, TIME_DIALOG_DEFAULT_MIN, TIME_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_TIME, 86399999.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_TIME, 86399999.0, TIME_DIALOG_DEFAULT_MIN, TIME_DIALOG_DEFAULT_MAX, 1.0); mInputDialogContainer.setShowDialogExpectation(TEXT_INPUT_TYPE_TIME, 0, 0, 0, 15, 23, 0, 0, 0, TIME_DIALOG_DEFAULT_MIN, TIME_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_TIME, 55425678.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_TIME, 55425678.0, TIME_DIALOG_DEFAULT_MIN, TIME_DIALOG_DEFAULT_MAX, 1.0); } @@ -176,28 +176,28 @@ public class InputDialogContainerTest extends AndroidTestCase { 1970, 0, 0, 0, 0, 0, 0, 1, WEEK_DIALOG_DEFAULT_MIN, WEEK_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_WEEK, -259200000.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_WEEK, -259200000.0, WEEK_DIALOG_DEFAULT_MIN, WEEK_DIALOG_DEFAULT_MAX, 1.0); mInputDialogContainer.setShowDialogExpectation(TEXT_INPUT_TYPE_WEEK, 1, 0, 0, 0, 0, 0, 0, 1, WEEK_DIALOG_DEFAULT_MIN, WEEK_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_WEEK, -62135596800000.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_WEEK, -62135596800000.0, WEEK_DIALOG_DEFAULT_MIN, WEEK_DIALOG_DEFAULT_MAX, 1.0); mInputDialogContainer.setShowDialogExpectation(TEXT_INPUT_TYPE_WEEK, 275760, 0, 0, 0, 0, 0, 0, 37, WEEK_DIALOG_DEFAULT_MIN, WEEK_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_WEEK, 8639999568000000.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_WEEK, 8639999568000000.0, WEEK_DIALOG_DEFAULT_MIN, WEEK_DIALOG_DEFAULT_MAX, 1.0); mInputDialogContainer.setShowDialogExpectation(TEXT_INPUT_TYPE_WEEK, 2013, 0, 0, 0, 0, 0, 0, 44, WEEK_DIALOG_DEFAULT_MIN, WEEK_DIALOG_DEFAULT_MAX, 1.0); - mInputDialogContainer.showDialog(TEXT_INPUT_TYPE_WEEK, 1382918400000.0, + mInputDialogContainer.showPickerDialog(TEXT_INPUT_TYPE_WEEK, 1382918400000.0, WEEK_DIALOG_DEFAULT_MIN, WEEK_DIALOG_DEFAULT_MAX, 1.0); } @@ -373,7 +373,7 @@ public class InputDialogContainerTest extends AndroidTestCase { } @Override - void showDialog(final int dialogType, + 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) { diff --git a/content/renderer/date_time_suggestion_builder.cc b/content/renderer/date_time_suggestion_builder.cc new file mode 100644 index 0000000..7dff00d --- /dev/null +++ b/content/renderer/date_time_suggestion_builder.cc @@ -0,0 +1,22 @@ +// Copyright 2013 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. + +#include "content/renderer/date_time_suggestion_builder.h" + +#include "content/common/date_time_suggestion.h" +#include "third_party/WebKit/public/web/WebDateTimeSuggestion.h" + +namespace content { + +// static +DateTimeSuggestion DateTimeSuggestionBuilder::Build( + const blink::WebDateTimeSuggestion& suggestion) { + DateTimeSuggestion result; + result.value = suggestion.value; + result.localized_value = suggestion.localizedValue; + result.label = suggestion.label; + return result; +} + +} // namespace content diff --git a/content/renderer/date_time_suggestion_builder.h b/content/renderer/date_time_suggestion_builder.h new file mode 100644 index 0000000..5087051 --- /dev/null +++ b/content/renderer/date_time_suggestion_builder.h @@ -0,0 +1,23 @@ +// Copyright 2013 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. + +#ifndef CONTENT_RENDERER_DATE_TIME_SUGGESTION_BUILDER_H_ +#define CONTENT_RENDERER_DATE_TIME_SUGGESTION_BUILDER_H_ + +namespace blink { +struct WebDateTimeSuggestion; +} // namespace blink + +namespace content { +struct DateTimeSuggestion; + +class DateTimeSuggestionBuilder { + public: + static DateTimeSuggestion Build( + const blink::WebDateTimeSuggestion& suggestion); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_DATE_TIME_SUGGESTION_BUILDER_H_ diff --git a/content/renderer/renderer_date_time_picker.cc b/content/renderer/renderer_date_time_picker.cc index 8c3a8f2..592e249 100644 --- a/content/renderer/renderer_date_time_picker.cc +++ b/content/renderer/renderer_date_time_picker.cc @@ -6,6 +6,7 @@ #include "base/strings/string_util.h" #include "content/common/view_messages.h" +#include "content/renderer/date_time_suggestion_builder.h" #include "content/renderer/render_view_impl.h" #include "third_party/WebKit/public/web/WebDateTimeChooserCompletion.h" #include "third_party/WebKit/public/web/WebDateTimeChooserParams.h" @@ -61,6 +62,10 @@ bool RendererDateTimePicker::Open() { message.minimum = chooser_params_.minimum; message.maximum = chooser_params_.maximum; message.step = chooser_params_.step; + for (size_t i = 0; i < chooser_params_.suggestions.size(); i++) { + message.suggestions.push_back( + DateTimeSuggestionBuilder::Build(chooser_params_.suggestions[i])); + } Send(new ViewHostMsg_OpenDateTimeDialog(routing_id(), message)); return true; } diff --git a/ui/android/java/res/layout/date_time_suggestion.xml b/ui/android/java/res/layout/date_time_suggestion.xml new file mode 100644 index 0000000..e47ac76 --- /dev/null +++ b/ui/android/java/res/layout/date_time_suggestion.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2013 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/date_time_suggestion" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="44dp" + android:orientation="horizontal" + android:gravity="center_vertical"> + <TextView + android:id="@+id/date_time_suggestion_value" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="10dp" + android:layout_marginEnd="10dp" + android:ellipsize="end" + android:singleLine="true" + android:textSize="18sp" /> + <TextView + android:id="@+id/date_time_suggestion_label" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginEnd="10dp" + android:layout_weight="1" + android:textSize="18sp" + android:gravity="end" + android:textColor="#8b8b8b" + android:ellipsize="end" + android:singleLine="true" /> +</LinearLayout> |