| OLD | NEW |
| (Empty) |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package org.chromium.content.browser.input; | |
| 6 | |
| 7 import android.app.AlertDialog; | |
| 8 import android.app.DatePickerDialog.OnDateSetListener; | |
| 9 import android.content.Context; | |
| 10 import android.content.DialogInterface; | |
| 11 import android.content.DialogInterface.OnDismissListener; | |
| 12 import android.text.format.DateFormat; | |
| 13 import android.view.View; | |
| 14 import android.widget.AdapterView; | |
| 15 import android.widget.DatePicker; | |
| 16 import android.widget.ListView; | |
| 17 import android.widget.TimePicker; | |
| 18 | |
| 19 import org.chromium.content.R; | |
| 20 import org.chromium.content.browser.input.DateTimePickerDialog.OnDateTimeSetList
ener; | |
| 21 import org.chromium.content.browser.input.MultiFieldTimePickerDialog.OnMultiFiel
dTimeSetListener; | |
| 22 | |
| 23 import java.util.Arrays; | |
| 24 import java.util.Calendar; | |
| 25 import java.util.Date; | |
| 26 import java.util.GregorianCalendar; | |
| 27 import java.util.TimeZone; | |
| 28 import java.util.concurrent.TimeUnit; | |
| 29 | |
| 30 /** | |
| 31 * Opens the approprate date/time picker dialog for the given dialog type. | |
| 32 */ | |
| 33 public class InputDialogContainer { | |
| 34 | |
| 35 interface InputActionDelegate { | |
| 36 void cancelDateTimeDialog(); | |
| 37 void replaceDateTime(double value); | |
| 38 } | |
| 39 | |
| 40 private static int sTextInputTypeDate; | |
| 41 private static int sTextInputTypeDateTime; | |
| 42 private static int sTextInputTypeDateTimeLocal; | |
| 43 private static int sTextInputTypeMonth; | |
| 44 private static int sTextInputTypeTime; | |
| 45 private static int sTextInputTypeWeek; | |
| 46 | |
| 47 private final Context mContext; | |
| 48 | |
| 49 // Prevents sending two notifications (from onClick and from onDismiss) | |
| 50 private boolean mDialogAlreadyDismissed; | |
| 51 | |
| 52 private AlertDialog mDialog; | |
| 53 private final InputActionDelegate mInputActionDelegate; | |
| 54 | |
| 55 static void initializeInputTypes(int textInputTypeDate, | |
| 56 int textInputTypeDateTime, int textInputTypeDateTimeLocal, | |
| 57 int textInputTypeMonth, int textInputTypeTime, | |
| 58 int textInputTypeWeek) { | |
| 59 sTextInputTypeDate = textInputTypeDate; | |
| 60 sTextInputTypeDateTime = textInputTypeDateTime; | |
| 61 sTextInputTypeDateTimeLocal = textInputTypeDateTimeLocal; | |
| 62 sTextInputTypeMonth = textInputTypeMonth; | |
| 63 sTextInputTypeTime = textInputTypeTime; | |
| 64 sTextInputTypeWeek = textInputTypeWeek; | |
| 65 } | |
| 66 | |
| 67 static boolean isDialogInputType(int type) { | |
| 68 return type == sTextInputTypeDate || type == sTextInputTypeTime | |
| 69 || type == sTextInputTypeDateTime || type == sTextInputTypeDateT
imeLocal | |
| 70 || type == sTextInputTypeMonth || type == sTextInputTypeWeek; | |
| 71 } | |
| 72 | |
| 73 InputDialogContainer(Context context, InputActionDelegate inputActionDelegat
e) { | |
| 74 mContext = context; | |
| 75 mInputActionDelegate = inputActionDelegate; | |
| 76 } | |
| 77 | |
| 78 void showPickerDialog(final int dialogType, double dialogValue, | |
| 79 double min, double max, double step) { | |
| 80 Calendar cal; | |
| 81 // |dialogValue|, |min|, |max| mean different things depending on the |d
ialogType|. | |
| 82 // For input type=month is the number of months since 1970. | |
| 83 // For input type=time it is milliseconds since midnight. | |
| 84 // For other types they are just milliseconds since 1970. | |
| 85 // If |dialogValue| is NaN it means an empty value. We will show the cur
rent time. | |
| 86 if (Double.isNaN(dialogValue)) { | |
| 87 cal = Calendar.getInstance(); | |
| 88 cal.set(Calendar.MILLISECOND, 0); | |
| 89 } else { | |
| 90 if (dialogType == sTextInputTypeMonth) { | |
| 91 cal = MonthPicker.createDateFromValue(dialogValue); | |
| 92 } else if (dialogType == sTextInputTypeWeek) { | |
| 93 cal = WeekPicker.createDateFromValue(dialogValue); | |
| 94 } else { | |
| 95 GregorianCalendar gregorianCalendar = | |
| 96 new GregorianCalendar(TimeZone.getTimeZone("UTC")); | |
| 97 // According to the HTML spec we only use the Gregorian calendar | |
| 98 // so we ignore the Julian/Gregorian transition. | |
| 99 gregorianCalendar.setGregorianChange(new Date(Long.MIN_VALUE)); | |
| 100 gregorianCalendar.setTimeInMillis((long) dialogValue); | |
| 101 cal = gregorianCalendar; | |
| 102 } | |
| 103 } | |
| 104 if (dialogType == sTextInputTypeDate) { | |
| 105 showPickerDialog(dialogType, | |
| 106 cal.get(Calendar.YEAR), | |
| 107 cal.get(Calendar.MONTH), | |
| 108 cal.get(Calendar.DAY_OF_MONTH), | |
| 109 0, 0, 0, 0, 0, min, max, step); | |
| 110 } else if (dialogType == sTextInputTypeTime) { | |
| 111 showPickerDialog(dialogType, 0, 0, 0, | |
| 112 cal.get(Calendar.HOUR_OF_DAY), | |
| 113 cal.get(Calendar.MINUTE), | |
| 114 0, 0, 0, min, max, step); | |
| 115 } else if (dialogType == sTextInputTypeDateTime || | |
| 116 dialogType == sTextInputTypeDateTimeLocal) { | |
| 117 showPickerDialog(dialogType, | |
| 118 cal.get(Calendar.YEAR), | |
| 119 cal.get(Calendar.MONTH), | |
| 120 cal.get(Calendar.DAY_OF_MONTH), | |
| 121 cal.get(Calendar.HOUR_OF_DAY), | |
| 122 cal.get(Calendar.MINUTE), | |
| 123 cal.get(Calendar.SECOND), | |
| 124 cal.get(Calendar.MILLISECOND), | |
| 125 0, min, max, step); | |
| 126 } else if (dialogType == sTextInputTypeMonth) { | |
| 127 showPickerDialog(dialogType, cal.get(Calendar.YEAR), cal.get(Calenda
r.MONTH), 0, | |
| 128 0, 0, 0, 0, 0, min, max, step); | |
| 129 } else if (dialogType == sTextInputTypeWeek) { | |
| 130 int year = WeekPicker.getISOWeekYearForDate(cal); | |
| 131 int week = WeekPicker.getWeekForDate(cal); | |
| 132 showPickerDialog(dialogType, year, 0, 0, 0, 0, 0, 0, week, min, max,
step); | |
| 133 } | |
| 134 } | |
| 135 | |
| 136 void showSuggestionDialog(final int dialogType, | |
| 137 final double dialogValue, | |
| 138 final double min, final double max, final double step, | |
| 139 DateTimeSuggestion[] suggestions) { | |
| 140 ListView suggestionListView = new ListView(mContext); | |
| 141 final DateTimeSuggestionListAdapter adapter = | |
| 142 new DateTimeSuggestionListAdapter(mContext, Arrays.asList(suggestion
s)); | |
| 143 suggestionListView.setAdapter(adapter); | |
| 144 suggestionListView.setOnItemClickListener(new AdapterView.OnItemClickLis
tener() { | |
| 145 @Override | |
| 146 public void onItemClick(AdapterView<?> parent, View view, int positi
on, long id) { | |
| 147 if (position == adapter.getCount() - 1) { | |
| 148 dismissDialog(); | |
| 149 showPickerDialog(dialogType, dialogValue, min, max, step); | |
| 150 } else { | |
| 151 double suggestionValue = adapter.getItem(position).value(); | |
| 152 mInputActionDelegate.replaceDateTime(suggestionValue); | |
| 153 dismissDialog(); | |
| 154 mDialogAlreadyDismissed = true; | |
| 155 } | |
| 156 } | |
| 157 }); | |
| 158 | |
| 159 int dialogTitleId = R.string.date_picker_dialog_title; | |
| 160 if (dialogType == sTextInputTypeTime) { | |
| 161 dialogTitleId = R.string.time_picker_dialog_title; | |
| 162 } else if (dialogType == sTextInputTypeDateTime || | |
| 163 dialogType == sTextInputTypeDateTimeLocal) { | |
| 164 dialogTitleId = R.string.date_time_picker_dialog_title; | |
| 165 } else if (dialogType == sTextInputTypeMonth) { | |
| 166 dialogTitleId = R.string.month_picker_dialog_title; | |
| 167 } else if (dialogType == sTextInputTypeWeek) { | |
| 168 dialogTitleId = R.string.week_picker_dialog_title; | |
| 169 } | |
| 170 | |
| 171 mDialog = new AlertDialog.Builder(mContext) | |
| 172 .setTitle(dialogTitleId) | |
| 173 .setView(suggestionListView) | |
| 174 .setNegativeButton(mContext.getText(android.R.string.cancel), | |
| 175 new DialogInterface.OnClickListener() { | |
| 176 @Override | |
| 177 public void onClick(DialogInterface dialog, int which) { | |
| 178 dismissDialog(); | |
| 179 } | |
| 180 }) | |
| 181 .create(); | |
| 182 | |
| 183 mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { | |
| 184 @Override | |
| 185 public void onDismiss(DialogInterface dialog) { | |
| 186 if (mDialog == dialog && !mDialogAlreadyDismissed) { | |
| 187 mDialogAlreadyDismissed = true; | |
| 188 mInputActionDelegate.cancelDateTimeDialog(); | |
| 189 } | |
| 190 } | |
| 191 }); | |
| 192 mDialogAlreadyDismissed = false; | |
| 193 mDialog.show(); | |
| 194 } | |
| 195 | |
| 196 void showDialog(final int type, final double value, | |
| 197 double min, double max, double step, | |
| 198 DateTimeSuggestion[] suggestions) { | |
| 199 // When the web page asks to show a dialog while there is one already op
en, | |
| 200 // dismiss the old one. | |
| 201 dismissDialog(); | |
| 202 if (suggestions == null) { | |
| 203 showPickerDialog(type, value, min, max, step); | |
| 204 } else { | |
| 205 showSuggestionDialog(type, value, min, max, step, suggestions); | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 void showPickerDialog(final int dialogType, | |
| 210 int year, int month, int monthDay, | |
| 211 int hourOfDay, int minute, int second, int millis, int week, | |
| 212 double min, double max, double step) { | |
| 213 if (isDialogShowing()) mDialog.dismiss(); | |
| 214 | |
| 215 int stepTime = (int) step; | |
| 216 | |
| 217 if (dialogType == sTextInputTypeDate) { | |
| 218 ChromeDatePickerDialog dialog = new ChromeDatePickerDialog(mContext, | |
| 219 new DateListener(dialogType), | |
| 220 year, month, monthDay); | |
| 221 DateDialogNormalizer.normalize(dialog.getDatePicker(), dialog, | |
| 222 year, month, monthDay, | |
| 223 0, 0, | |
| 224 (long) min, (long) max); | |
| 225 | |
| 226 dialog.setTitle(mContext.getText(R.string.date_picker_dialog_title))
; | |
| 227 mDialog = dialog; | |
| 228 } else if (dialogType == sTextInputTypeTime) { | |
| 229 mDialog = new MultiFieldTimePickerDialog( | |
| 230 mContext, 0 /* theme */ , | |
| 231 hourOfDay, minute, second, millis, | |
| 232 (int) min, (int) max, stepTime, | |
| 233 DateFormat.is24HourFormat(mContext), | |
| 234 new FullTimeListener(dialogType)); | |
| 235 } else if (dialogType == sTextInputTypeDateTime || | |
| 236 dialogType == sTextInputTypeDateTimeLocal) { | |
| 237 mDialog = new DateTimePickerDialog(mContext, | |
| 238 new DateTimeListener(dialogType), | |
| 239 year, month, monthDay, | |
| 240 hourOfDay, minute, | |
| 241 DateFormat.is24HourFormat(mContext), min, max); | |
| 242 } else if (dialogType == sTextInputTypeMonth) { | |
| 243 mDialog = new MonthPickerDialog(mContext, new MonthOrWeekListener(di
alogType), | |
| 244 year, month, min, max); | |
| 245 } else if (dialogType == sTextInputTypeWeek) { | |
| 246 mDialog = new WeekPickerDialog(mContext, new MonthOrWeekListener(dia
logType), | |
| 247 year, week, min, max); | |
| 248 } | |
| 249 | |
| 250 mDialog.setButton(DialogInterface.BUTTON_POSITIVE, | |
| 251 mContext.getText(R.string.date_picker_dialog_set), | |
| 252 (DialogInterface.OnClickListener) mDialog); | |
| 253 | |
| 254 | |
| 255 mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, | |
| 256 mContext.getText(android.R.string.cancel), | |
| 257 (DialogInterface.OnClickListener) null); | |
| 258 | |
| 259 mDialog.setButton(DialogInterface.BUTTON_NEUTRAL, | |
| 260 mContext.getText(R.string.date_picker_dialog_clear), | |
| 261 new DialogInterface.OnClickListener() { | |
| 262 @Override | |
| 263 public void onClick(DialogInterface dialog, int which) { | |
| 264 mDialogAlreadyDismissed = true; | |
| 265 mInputActionDelegate.replaceDateTime(Double.NaN); | |
| 266 } | |
| 267 }); | |
| 268 | |
| 269 mDialog.setOnDismissListener( | |
| 270 new OnDismissListener() { | |
| 271 @Override | |
| 272 public void onDismiss(final DialogInterface dialog) { | |
| 273 if (!mDialogAlreadyDismissed) { | |
| 274 mDialogAlreadyDismissed = true; | |
| 275 mInputActionDelegate.cancelDateTimeDialog(); | |
| 276 } | |
| 277 } | |
| 278 }); | |
| 279 | |
| 280 mDialogAlreadyDismissed = false; | |
| 281 mDialog.show(); | |
| 282 } | |
| 283 | |
| 284 boolean isDialogShowing() { | |
| 285 return mDialog != null && mDialog.isShowing(); | |
| 286 } | |
| 287 | |
| 288 void dismissDialog() { | |
| 289 if (isDialogShowing()) mDialog.dismiss(); | |
| 290 } | |
| 291 | |
| 292 private class DateListener implements OnDateSetListener { | |
| 293 private final int mDialogType; | |
| 294 | |
| 295 DateListener(int dialogType) { | |
| 296 mDialogType = dialogType; | |
| 297 } | |
| 298 | |
| 299 @Override | |
| 300 public void onDateSet(DatePicker view, int year, int month, int monthDay
) { | |
| 301 setFieldDateTimeValue(mDialogType, year, month, monthDay, 0, 0, 0, 0
, 0); | |
| 302 } | |
| 303 } | |
| 304 | |
| 305 private class FullTimeListener implements OnMultiFieldTimeSetListener { | |
| 306 private final int mDialogType; | |
| 307 FullTimeListener(int dialogType) { | |
| 308 mDialogType = dialogType; | |
| 309 } | |
| 310 | |
| 311 @Override | |
| 312 public void onTimeSet(int hourOfDay, int minute, int second, int milli)
{ | |
| 313 setFieldDateTimeValue(mDialogType, 0, 0, 0, hourOfDay, minute, secon
d, milli, 0); | |
| 314 } | |
| 315 } | |
| 316 | |
| 317 private class DateTimeListener implements OnDateTimeSetListener { | |
| 318 private final boolean mLocal; | |
| 319 private final int mDialogType; | |
| 320 | |
| 321 public DateTimeListener(int dialogType) { | |
| 322 mLocal = dialogType == sTextInputTypeDateTimeLocal; | |
| 323 mDialogType = dialogType; | |
| 324 } | |
| 325 | |
| 326 @Override | |
| 327 public void onDateTimeSet(DatePicker dateView, TimePicker timeView, | |
| 328 int year, int month, int monthDay, | |
| 329 int hourOfDay, int minute) { | |
| 330 setFieldDateTimeValue(mDialogType, year, month, monthDay, hourOfDay,
minute, 0, 0, 0); | |
| 331 } | |
| 332 } | |
| 333 | |
| 334 private class MonthOrWeekListener implements TwoFieldDatePickerDialog.OnValu
eSetListener { | |
| 335 private final int mDialogType; | |
| 336 | |
| 337 MonthOrWeekListener(int dialogType) { | |
| 338 mDialogType = dialogType; | |
| 339 } | |
| 340 | |
| 341 @Override | |
| 342 public void onValueSet(int year, int positionInYear) { | |
| 343 if (mDialogType == sTextInputTypeMonth) { | |
| 344 setFieldDateTimeValue(mDialogType, year, positionInYear, 0, 0, 0
, 0, 0, 0); | |
| 345 } else { | |
| 346 setFieldDateTimeValue(mDialogType, year, 0, 0, 0, 0, 0, 0, posit
ionInYear); | |
| 347 } | |
| 348 } | |
| 349 } | |
| 350 | |
| 351 protected void setFieldDateTimeValue(int dialogType, | |
| 352 int year, int month, int monthDay, | |
| 353 int hourOfDay, int minute, int second, in
t millis, | |
| 354 int week) { | |
| 355 // Prevents more than one callback being sent to the native | |
| 356 // side when the dialog triggers multiple events. | |
| 357 if (mDialogAlreadyDismissed) | |
| 358 return; | |
| 359 mDialogAlreadyDismissed = true; | |
| 360 | |
| 361 if (dialogType == sTextInputTypeMonth) { | |
| 362 mInputActionDelegate.replaceDateTime((year - 1970) * 12 + month); | |
| 363 } else if (dialogType == sTextInputTypeWeek) { | |
| 364 mInputActionDelegate.replaceDateTime( | |
| 365 WeekPicker.createDateFromWeek(year, week).getTimeInMillis()); | |
| 366 } else if (dialogType == sTextInputTypeTime) { | |
| 367 mInputActionDelegate.replaceDateTime(TimeUnit.HOURS.toMillis(hourOfD
ay) + | |
| 368 TimeUnit.MINUTES.toMillis(minut
e) + | |
| 369 TimeUnit.SECONDS.toMillis(secon
d) + | |
| 370 millis); | |
| 371 } else { | |
| 372 Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); | |
| 373 cal.clear(); | |
| 374 cal.set(Calendar.YEAR, year); | |
| 375 cal.set(Calendar.MONTH, month); | |
| 376 cal.set(Calendar.DAY_OF_MONTH, monthDay); | |
| 377 cal.set(Calendar.HOUR_OF_DAY, hourOfDay); | |
| 378 cal.set(Calendar.MINUTE, minute); | |
| 379 cal.set(Calendar.SECOND, second); | |
| 380 cal.set(Calendar.MILLISECOND, millis); | |
| 381 mInputActionDelegate.replaceDateTime(cal.getTimeInMillis()); | |
| 382 } | |
| 383 } | |
| 384 } | |
| OLD | NEW |