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