• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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.content.Context;
9 import android.content.DialogInterface;
10 import android.content.DialogInterface.OnClickListener;
11 import android.view.LayoutInflater;
12 import android.view.View;
13 import android.widget.NumberPicker;
14 
15 import org.chromium.content.R;
16 
17 import java.util.ArrayList;
18 
19 /**
20  * A time picker dialog with upto 5 number pickers left to right:
21  *  hour, minute, second, milli, AM/PM.
22  *
23  * If is24hourFormat is true then AM/PM picker is not displayed and
24  * hour range is 0..23. Otherwise hour range is 1..12.
25  * The milli picker is not displayed if step >= SECOND_IN_MILLIS
26  * The second picker is not displayed if step >= MINUTE_IN_MILLIS.
27  */
28 public class MultiFieldTimePickerDialog
29         extends AlertDialog implements OnClickListener {
30 
31     private final NumberPicker mHourSpinner;
32     private final NumberPicker mMinuteSpinner;
33     private final NumberPicker mSecSpinner;
34     private final NumberPicker mMilliSpinner;
35     private final NumberPicker mAmPmSpinner;
36     private final OnMultiFieldTimeSetListener mListener;
37     private final int mStep;
38     private final int mBaseMilli;
39     private final boolean mIs24hourFormat;
40 
41     public interface OnMultiFieldTimeSetListener {
onTimeSet(int hourOfDay, int minute, int second, int milli)42         void onTimeSet(int hourOfDay, int minute, int second, int milli);
43     }
44 
45     private static final int SECOND_IN_MILLIS = 1000;
46     private static final int MINUTE_IN_MILLIS = 60 * SECOND_IN_MILLIS;
47     private static final int HOUR_IN_MILLIS = 60 * MINUTE_IN_MILLIS;
48 
MultiFieldTimePickerDialog( Context context, int theme, int hour, int minute, int second, int milli, int min, int max, int step, boolean is24hourFormat, OnMultiFieldTimeSetListener listener)49     public MultiFieldTimePickerDialog(
50             Context context,
51             int theme,
52             int hour, int minute, int second, int milli,
53             int min, int max, int step, boolean is24hourFormat,
54             OnMultiFieldTimeSetListener listener) {
55         super(context, theme);
56         mListener = listener;
57         mStep = step;
58         mIs24hourFormat = is24hourFormat;
59 
60         if (min >= max) {
61             min = 0;
62             max = 24 * HOUR_IN_MILLIS - 1;
63         }
64         if (step < 0 || step >= 24 * HOUR_IN_MILLIS) {
65             step = MINUTE_IN_MILLIS;
66         }
67 
68         LayoutInflater inflater =
69                 (LayoutInflater) context.getSystemService(
70                         Context.LAYOUT_INFLATER_SERVICE);
71         View view = inflater.inflate(R.layout.multi_field_time_picker_dialog, null);
72         setView(view);
73 
74         mHourSpinner = (NumberPicker) view.findViewById(R.id.hour);
75         mMinuteSpinner = (NumberPicker) view.findViewById(R.id.minute);
76         mSecSpinner = (NumberPicker) view.findViewById(R.id.second);
77         mMilliSpinner = (NumberPicker) view.findViewById(R.id.milli);
78         mAmPmSpinner = (NumberPicker) view.findViewById(R.id.ampm);
79 
80         int minHour = min / HOUR_IN_MILLIS;
81         int maxHour = max / HOUR_IN_MILLIS;
82         min -= minHour * HOUR_IN_MILLIS;
83         max -= maxHour * HOUR_IN_MILLIS;
84 
85         if (minHour == maxHour) {
86             mHourSpinner.setEnabled(false);
87             hour = minHour;
88         }
89 
90         if (is24hourFormat) {
91             mAmPmSpinner.setVisibility(View.GONE);
92         } else {
93             int minAmPm = minHour / 12;
94             int maxAmPm = maxHour / 12;
95             int amPm = hour / 12;
96             mAmPmSpinner.setMinValue(minAmPm);
97             mAmPmSpinner.setMaxValue(maxAmPm);
98             mAmPmSpinner.setDisplayedValues(new String[] {
99                     context.getString(R.string.time_picker_dialog_am),
100                     context.getString(R.string.time_picker_dialog_pm)
101             });
102 
103             hour %= 12;
104             if (hour == 0) {
105                 hour = 12;
106             }
107             if (minAmPm == maxAmPm) {
108                 mAmPmSpinner.setEnabled(false);
109                 amPm = minAmPm;
110 
111                 minHour %= 12;
112                 maxHour %= 12;
113                 if (minHour == 0 && maxHour == 0) {
114                     minHour = 12;
115                     maxHour = 12;
116                 } else if (minHour == 0) {
117                     minHour = maxHour;
118                     maxHour = 12;
119                 } else if (maxHour == 0) {
120                     maxHour = 12;
121                 }
122             } else {
123                 minHour = 1;
124                 maxHour = 12;
125             }
126             mAmPmSpinner.setValue(amPm);
127         }
128 
129         if (minHour == maxHour) {
130             mHourSpinner.setEnabled(false);
131         }
132         mHourSpinner.setMinValue(minHour);
133         mHourSpinner.setMaxValue(maxHour);
134         mHourSpinner.setValue(hour);
135 
136         NumberFormatter twoDigitPaddingFormatter = new NumberFormatter("%02d");
137 
138         int minMinute = min / MINUTE_IN_MILLIS;
139         int maxMinute = max / MINUTE_IN_MILLIS;
140         min -= minMinute * MINUTE_IN_MILLIS;
141         max -= maxMinute * MINUTE_IN_MILLIS;
142 
143         if (minHour == maxHour) {
144             mMinuteSpinner.setMinValue(minMinute);
145             mMinuteSpinner.setMaxValue(maxMinute);
146             if (minMinute == maxMinute) {
147                 // Set this otherwise the box is empty until you stroke it.
148                 mMinuteSpinner.setDisplayedValues(
149                     new String[] { twoDigitPaddingFormatter.format(minMinute) });
150                 mMinuteSpinner.setEnabled(false);
151                 minute = minMinute;
152             }
153         } else {
154             mMinuteSpinner.setMinValue(0);
155             mMinuteSpinner.setMaxValue(59);
156         }
157 
158         if (step >= HOUR_IN_MILLIS) {
159             mMinuteSpinner.setEnabled(false);
160         }
161 
162         mMinuteSpinner.setValue(minute);
163         mMinuteSpinner.setFormatter(twoDigitPaddingFormatter);
164 
165         if (step >= MINUTE_IN_MILLIS) {
166             // Remove the ':' in front of the second spinner as well.
167             view.findViewById(R.id.second_colon).setVisibility(View.GONE);
168             mSecSpinner.setVisibility(View.GONE);
169         }
170 
171         int minSecond = min / SECOND_IN_MILLIS;
172         int maxSecond = max / SECOND_IN_MILLIS;
173         min -= minSecond * SECOND_IN_MILLIS;
174         max -= maxSecond * SECOND_IN_MILLIS;
175 
176         if (minHour == maxHour && minMinute == maxMinute) {
177             mSecSpinner.setMinValue(minSecond);
178             mSecSpinner.setMaxValue(maxSecond);
179             if (minSecond == maxSecond) {
180                 // Set this otherwise the box is empty until you stroke it.
181                 mSecSpinner.setDisplayedValues(
182                     new String[] { twoDigitPaddingFormatter.format(minSecond) });
183                 mSecSpinner.setEnabled(false);
184                 second = minSecond;
185             }
186         } else {
187             mSecSpinner.setMinValue(0);
188             mSecSpinner.setMaxValue(59);
189         }
190 
191         mSecSpinner.setValue(second);
192         mSecSpinner.setFormatter(twoDigitPaddingFormatter);
193 
194         if (step >= SECOND_IN_MILLIS) {
195             // Remove the '.' in front of the milli spinner as well.
196             view.findViewById(R.id.second_dot).setVisibility(View.GONE);
197             mMilliSpinner.setVisibility(View.GONE);
198         }
199 
200         // Round to the nearest step.
201         milli = ((milli + step / 2) / step) * step;
202         if (step == 1 || step == 10 || step == 100) {
203             if (minHour == maxHour && minMinute == maxMinute &&
204                 minSecond == maxSecond) {
205                 mMilliSpinner.setMinValue(min / step);
206                 mMilliSpinner.setMaxValue(max / step);
207 
208                 if (min == max) {
209                     mMilliSpinner.setEnabled(false);
210                     milli = min;
211                 }
212             } else {
213                 mMilliSpinner.setMinValue(0);
214                 mMilliSpinner.setMaxValue(999 / step);
215             }
216 
217             if (step == 1) {
218                 mMilliSpinner.setFormatter(new NumberFormatter("%03d"));
219             } else if (step == 10) {
220                 mMilliSpinner.setFormatter(new NumberFormatter("%02d"));
221             } else if (step == 100) {
222                 mMilliSpinner.setFormatter(new NumberFormatter("%d"));
223             }
224             mMilliSpinner.setValue(milli / step);
225             mBaseMilli = 0;
226         } else if (step < SECOND_IN_MILLIS) {
227             // Non-decimal step value.
228             ArrayList<String> strValue = new ArrayList<String>();
229             for (int i = min; i < max; i += step) {
230                 strValue.add(String.format("%03d", i));
231             }
232             mMilliSpinner.setMinValue(0);
233             mMilliSpinner.setMaxValue(strValue.size() - 1);
234             mMilliSpinner.setValue((milli - min) / step);
235             mMilliSpinner.setDisplayedValues(
236                 strValue.toArray(new String[strValue.size()]));
237             mBaseMilli = min;
238         } else {
239             mBaseMilli = 0;
240         }
241     }
242 
243     @Override
onClick(DialogInterface dialog, int which)244     public void onClick(DialogInterface dialog, int which) {
245         notifyDateSet();
246     }
247 
notifyDateSet()248     private void notifyDateSet() {
249         int hour = mHourSpinner.getValue();
250         int minute = mMinuteSpinner.getValue();
251         int sec = mSecSpinner.getValue();
252         int milli = mMilliSpinner.getValue() * mStep + mBaseMilli;
253         if (!mIs24hourFormat) {
254             int ampm = mAmPmSpinner.getValue();
255             if (hour == 12) {
256                 hour = 0;
257             }
258             hour += ampm * 12;
259         }
260         mListener.onTimeSet(hour, minute, sec, milli);
261     }
262 
263     private static class NumberFormatter implements NumberPicker.Formatter {
264         private final String mFormat;
265 
NumberFormatter(String format)266         NumberFormatter(String format) {
267             mFormat = format;
268         }
269 
270         @Override
format(int value)271         public String format(int value) {
272             return String.format(mFormat, value);
273         }
274     }
275 }
276