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 |