blob: cb9ed619613c01b9dad9137e0104fbbc9e75c73e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.widget;
18
19import android.annotation.Widget;
20import android.content.Context;
Svetoslav Ganovf5926962011-07-12 12:26:20 -070021import android.content.res.Configuration;
Svetoslav Ganov4243dc32011-01-18 19:39:57 -080022import android.content.res.TypedArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.os.Parcel;
24import android.os.Parcelable;
Svetoslav Ganov8a2a8952011-01-27 17:40:13 -080025import android.text.format.DateUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.util.AttributeSet;
27import android.view.LayoutInflater;
28import android.view.View;
Svetoslav Ganov8a2a8952011-01-27 17:40:13 -080029import android.view.accessibility.AccessibilityEvent;
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -080030import android.view.accessibility.AccessibilityNodeInfo;
Svetoslav Ganova53efe92011-09-08 18:08:36 -070031import android.view.inputmethod.EditorInfo;
Svetoslav Ganov6304b0d2011-10-19 19:55:44 -070032import android.view.inputmethod.InputMethodManager;
Svetoslav Ganovcedc4462011-01-19 19:25:46 -080033import android.widget.NumberPicker.OnValueChangeListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
Svetoslav Ganova53efe92011-09-08 18:08:36 -070035import com.android.internal.R;
36
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import java.text.DateFormatSymbols;
38import java.util.Calendar;
Svetoslav Ganovf5926962011-07-12 12:26:20 -070039import java.util.Locale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040
41/**
Svetoslav Ganov4243dc32011-01-18 19:39:57 -080042 * A view for selecting the time of day, in either 24 hour or AM/PM mode. The
43 * hour, each minute digit, and AM/PM (if applicable) can be conrolled by
44 * vertical spinners. The hour can be entered by keyboard input. Entering in two
45 * digit hours can be accomplished by hitting two digits within a timeout of
46 * about a second (e.g. '1' then '2' to select 12). The minutes can be entered
47 * by entering single digits. Under AM/PM mode, the user can hit 'a', 'A", 'p'
48 * or 'P' to pick. For a dialog using this view, see
49 * {@link android.app.TimePickerDialog}.
50 *<p>
Scott Main4c359b72012-07-24 15:51:27 -070051 * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
52 * guide.
Svetoslav Ganov4243dc32011-01-18 19:39:57 -080053 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 */
55@Widget
56public class TimePicker extends FrameLayout {
Svetoslav Ganov206316a2010-11-19 00:04:05 -080057
Svetoslav Ganov25f84f32010-12-29 22:39:54 -080058 private static final boolean DEFAULT_ENABLED_STATE = true;
59
Svetoslav Ganov4243dc32011-01-18 19:39:57 -080060 private static final int HOURS_IN_HALF_DAY = 12;
61
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062 /**
Svetoslav Ganov4243dc32011-01-18 19:39:57 -080063 * A no-op callback used in the constructor to avoid null checks later in
64 * the code.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065 */
66 private static final OnTimeChangedListener NO_OP_CHANGE_LISTENER = new OnTimeChangedListener() {
67 public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
68 }
69 };
Svetoslav Ganov4243dc32011-01-18 19:39:57 -080070
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 // state
Svetoslav Ganov4243dc32011-01-18 19:39:57 -080072 private boolean mIs24HourView;
73
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 private boolean mIsAm;
75
76 // ui components
Svetoslav Ganove9730bf2010-12-20 21:25:20 -080077 private final NumberPicker mHourSpinner;
Svetoslav Ganov4243dc32011-01-18 19:39:57 -080078
Svetoslav Ganove9730bf2010-12-20 21:25:20 -080079 private final NumberPicker mMinuteSpinner;
Svetoslav Ganov4243dc32011-01-18 19:39:57 -080080
Svetoslav Ganove9730bf2010-12-20 21:25:20 -080081 private final NumberPicker mAmPmSpinner;
Svetoslav Ganov4243dc32011-01-18 19:39:57 -080082
Svetoslav Ganov6304b0d2011-10-19 19:55:44 -070083 private final EditText mHourSpinnerInput;
84
85 private final EditText mMinuteSpinnerInput;
86
87 private final EditText mAmPmSpinnerInput;
88
Svetoslav Ganov206316a2010-11-19 00:04:05 -080089 private final TextView mDivider;
90
Svetoslav Ganov4243dc32011-01-18 19:39:57 -080091 // Note that the legacy implementation of the TimePicker is
92 // using a button for toggling between AM/PM while the new
93 // version uses a NumberPicker spinner. Therefore the code
94 // accommodates these two cases to be backwards compatible.
95 private final Button mAmPmButton;
96
Svetoslav Ganov206316a2010-11-19 00:04:05 -080097 private final String[] mAmPmStrings;
98
Svetoslav Ganov25f84f32010-12-29 22:39:54 -080099 private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
Svetoslav Ganov51c52ed2010-12-28 13:45:03 -0800100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 // callbacks
102 private OnTimeChangedListener mOnTimeChangedListener;
103
Svetoslav Ganov8a2a8952011-01-27 17:40:13 -0800104 private Calendar mTempCalendar;
105
Svetoslav Ganovf5926962011-07-12 12:26:20 -0700106 private Locale mCurrentLocale;
107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 /**
109 * The callback interface used to indicate the time has been adjusted.
110 */
111 public interface OnTimeChangedListener {
112
113 /**
114 * @param view The view associated with this listener.
115 * @param hourOfDay The current hour.
116 * @param minute The current minute.
117 */
118 void onTimeChanged(TimePicker view, int hourOfDay, int minute);
119 }
120
121 public TimePicker(Context context) {
122 this(context, null);
123 }
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 public TimePicker(Context context, AttributeSet attrs) {
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800126 this(context, attrs, R.attr.timePickerStyle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 }
128
129 public TimePicker(Context context, AttributeSet attrs, int defStyle) {
130 super(context, attrs, defStyle);
131
Svetoslav Ganovf5926962011-07-12 12:26:20 -0700132 // initialization based on locale
133 setCurrentLocale(Locale.getDefault());
134
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800135 // process style attributes
136 TypedArray attributesArray = context.obtainStyledAttributes(
137 attrs, R.styleable.TimePicker, defStyle, 0);
138 int layoutResourceId = attributesArray.getResourceId(
Svetoslav Ganov53b948d2012-03-02 14:03:35 -0800139 R.styleable.TimePicker_internalLayout, R.layout.time_picker);
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800140 attributesArray.recycle();
141
142 LayoutInflater inflater = (LayoutInflater) context.getSystemService(
143 Context.LAYOUT_INFLATER_SERVICE);
144 inflater.inflate(layoutResourceId, this, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145
146 // hour
Svetoslav Ganove9730bf2010-12-20 21:25:20 -0800147 mHourSpinner = (NumberPicker) findViewById(R.id.hour);
Svetoslav Ganovcedc4462011-01-19 19:25:46 -0800148 mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
Svetoslav Ganove9730bf2010-12-20 21:25:20 -0800149 public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
Svetoslav Ganov6304b0d2011-10-19 19:55:44 -0700150 updateInputState();
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800151 if (!is24HourView()) {
Svetoslav Ganovbe17a7f2011-01-31 14:21:56 -0800152 if ((oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY)
153 || (oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1)) {
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800154 mIsAm = !mIsAm;
155 updateAmPmControl();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 }
157 }
158 onTimeChanged();
159 }
160 });
Svetoslav Ganov6304b0d2011-10-19 19:55:44 -0700161 mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
162 mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800164 // divider (only for the new widget style)
Svetoslav Ganov206316a2010-11-19 00:04:05 -0800165 mDivider = (TextView) findViewById(R.id.divider);
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800166 if (mDivider != null) {
167 mDivider.setText(R.string.time_picker_separator);
168 }
Svetoslav Ganov206316a2010-11-19 00:04:05 -0800169
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800170 // minute
Svetoslav Ganove9730bf2010-12-20 21:25:20 -0800171 mMinuteSpinner = (NumberPicker) findViewById(R.id.minute);
172 mMinuteSpinner.setMinValue(0);
173 mMinuteSpinner.setMaxValue(59);
174 mMinuteSpinner.setOnLongPressUpdateInterval(100);
175 mMinuteSpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
Svetoslav Ganovcedc4462011-01-19 19:25:46 -0800176 mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
Svetoslav Ganove9730bf2010-12-20 21:25:20 -0800177 public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
Svetoslav Ganov6304b0d2011-10-19 19:55:44 -0700178 updateInputState();
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800179 int minValue = mMinuteSpinner.getMinValue();
180 int maxValue = mMinuteSpinner.getMaxValue();
181 if (oldVal == maxValue && newVal == minValue) {
Svetoslav Ganovbe17a7f2011-01-31 14:21:56 -0800182 int newHour = mHourSpinner.getValue() + 1;
183 if (!is24HourView() && newHour == HOURS_IN_HALF_DAY) {
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800184 mIsAm = !mIsAm;
185 updateAmPmControl();
Svetoslav Ganov206316a2010-11-19 00:04:05 -0800186 }
Svetoslav Ganovbe17a7f2011-01-31 14:21:56 -0800187 mHourSpinner.setValue(newHour);
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800188 } else if (oldVal == minValue && newVal == maxValue) {
Svetoslav Ganovbe17a7f2011-01-31 14:21:56 -0800189 int newHour = mHourSpinner.getValue() - 1;
190 if (!is24HourView() && newHour == HOURS_IN_HALF_DAY - 1) {
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800191 mIsAm = !mIsAm;
192 updateAmPmControl();
Svetoslav Ganov206316a2010-11-19 00:04:05 -0800193 }
Svetoslav Ganovbe17a7f2011-01-31 14:21:56 -0800194 mHourSpinner.setValue(newHour);
Svetoslav Ganov206316a2010-11-19 00:04:05 -0800195 }
Svetoslav Ganov206316a2010-11-19 00:04:05 -0800196 onTimeChanged();
197 }
198 });
Svetoslav Ganov6304b0d2011-10-19 19:55:44 -0700199 mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
200 mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
Svetoslav Ganov206316a2010-11-19 00:04:05 -0800201
202 /* Get the localized am/pm strings and use them in the spinner */
203 mAmPmStrings = new DateFormatSymbols().getAmPmStrings();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800205 // am/pm
206 View amPmView = findViewById(R.id.amPm);
207 if (amPmView instanceof Button) {
208 mAmPmSpinner = null;
Svetoslav Ganov6304b0d2011-10-19 19:55:44 -0700209 mAmPmSpinnerInput = null;
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800210 mAmPmButton = (Button) amPmView;
211 mAmPmButton.setOnClickListener(new OnClickListener() {
212 public void onClick(View button) {
213 button.requestFocus();
214 mIsAm = !mIsAm;
215 updateAmPmControl();
SeongJae Parkf821ce72012-01-17 15:20:23 +0900216 onTimeChanged();
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800217 }
218 });
219 } else {
220 mAmPmButton = null;
221 mAmPmSpinner = (NumberPicker) amPmView;
222 mAmPmSpinner.setMinValue(0);
223 mAmPmSpinner.setMaxValue(1);
224 mAmPmSpinner.setDisplayedValues(mAmPmStrings);
Svetoslav Ganovcedc4462011-01-19 19:25:46 -0800225 mAmPmSpinner.setOnValueChangedListener(new OnValueChangeListener() {
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800226 public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
Svetoslav Ganov6304b0d2011-10-19 19:55:44 -0700227 updateInputState();
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800228 picker.requestFocus();
229 mIsAm = !mIsAm;
230 updateAmPmControl();
SeongJae Parkf821ce72012-01-17 15:20:23 +0900231 onTimeChanged();
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800232 }
233 });
Svetoslav Ganov6304b0d2011-10-19 19:55:44 -0700234 mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
235 mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800236 }
237
238 // update controls to initial state
239 updateHourControl();
240 updateAmPmControl();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 setOnTimeChangedListener(NO_OP_CHANGE_LISTENER);
Svetoslav Ganov206316a2010-11-19 00:04:05 -0800243
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800244 // set to current time
Svetoslav Ganov8a2a8952011-01-27 17:40:13 -0800245 setCurrentHour(mTempCalendar.get(Calendar.HOUR_OF_DAY));
246 setCurrentMinute(mTempCalendar.get(Calendar.MINUTE));
Svetoslav Ganov206316a2010-11-19 00:04:05 -0800247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 if (!isEnabled()) {
249 setEnabled(false);
250 }
Svetoslav Ganov3fec3fe2011-09-01 14:48:37 -0700251
252 // set the content descriptions
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -0700253 setContentDescriptions();
Svetoslav Ganov42138042012-03-20 11:51:39 -0700254
255 // If not explicitly specified this view is important for accessibility.
256 if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
257 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
258 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 }
Svetoslav Ganov50f34d12010-12-03 16:05:40 -0800260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 @Override
262 public void setEnabled(boolean enabled) {
Svetoslav Ganov51c52ed2010-12-28 13:45:03 -0800263 if (mIsEnabled == enabled) {
264 return;
265 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 super.setEnabled(enabled);
Svetoslav Ganove9730bf2010-12-20 21:25:20 -0800267 mMinuteSpinner.setEnabled(enabled);
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800268 if (mDivider != null) {
269 mDivider.setEnabled(enabled);
270 }
Svetoslav Ganove9730bf2010-12-20 21:25:20 -0800271 mHourSpinner.setEnabled(enabled);
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800272 if (mAmPmSpinner != null) {
273 mAmPmSpinner.setEnabled(enabled);
274 } else {
275 mAmPmButton.setEnabled(enabled);
276 }
Svetoslav Ganov51c52ed2010-12-28 13:45:03 -0800277 mIsEnabled = enabled;
278 }
279
280 @Override
281 public boolean isEnabled() {
282 return mIsEnabled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 }
284
Svetoslav Ganovf5926962011-07-12 12:26:20 -0700285 @Override
286 protected void onConfigurationChanged(Configuration newConfig) {
287 super.onConfigurationChanged(newConfig);
288 setCurrentLocale(newConfig.locale);
289 }
290
291 /**
292 * Sets the current locale.
293 *
294 * @param locale The current locale.
295 */
296 private void setCurrentLocale(Locale locale) {
297 if (locale.equals(mCurrentLocale)) {
298 return;
299 }
300 mCurrentLocale = locale;
301 mTempCalendar = Calendar.getInstance(locale);
302 }
303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 /**
305 * Used to save / restore state of time picker
306 */
307 private static class SavedState extends BaseSavedState {
308
309 private final int mHour;
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800310
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 private final int mMinute;
312
313 private SavedState(Parcelable superState, int hour, int minute) {
314 super(superState);
315 mHour = hour;
316 mMinute = minute;
317 }
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 private SavedState(Parcel in) {
320 super(in);
321 mHour = in.readInt();
322 mMinute = in.readInt();
323 }
324
325 public int getHour() {
326 return mHour;
327 }
328
329 public int getMinute() {
330 return mMinute;
331 }
332
333 @Override
334 public void writeToParcel(Parcel dest, int flags) {
335 super.writeToParcel(dest, flags);
336 dest.writeInt(mHour);
337 dest.writeInt(mMinute);
338 }
339
Svetoslav Ganov6304b0d2011-10-19 19:55:44 -0700340 @SuppressWarnings({"unused", "hiding"})
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800341 public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 public SavedState createFromParcel(Parcel in) {
343 return new SavedState(in);
344 }
345
346 public SavedState[] newArray(int size) {
347 return new SavedState[size];
348 }
349 };
350 }
351
352 @Override
353 protected Parcelable onSaveInstanceState() {
354 Parcelable superState = super.onSaveInstanceState();
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800355 return new SavedState(superState, getCurrentHour(), getCurrentMinute());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 }
357
358 @Override
359 protected void onRestoreInstanceState(Parcelable state) {
360 SavedState ss = (SavedState) state;
361 super.onRestoreInstanceState(ss.getSuperState());
362 setCurrentHour(ss.getHour());
363 setCurrentMinute(ss.getMinute());
364 }
365
366 /**
367 * Set the callback that indicates the time has been adjusted by the user.
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800368 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 * @param onTimeChangedListener the callback, should not be null.
370 */
371 public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) {
372 mOnTimeChangedListener = onTimeChangedListener;
373 }
374
375 /**
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800376 * @return The current hour in the range (0-23).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 */
378 public Integer getCurrentHour() {
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800379 int currentHour = mHourSpinner.getValue();
Svetoslav Ganovbe17a7f2011-01-31 14:21:56 -0800380 if (is24HourView()) {
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800381 return currentHour;
Svetoslav Ganovbe17a7f2011-01-31 14:21:56 -0800382 } else if (mIsAm) {
383 return currentHour % HOURS_IN_HALF_DAY;
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800384 } else {
Svetoslav Ganovbe17a7f2011-01-31 14:21:56 -0800385 return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY;
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800386 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 }
388
389 /**
390 * Set the current hour.
391 */
392 public void setCurrentHour(Integer currentHour) {
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800393 // why was Integer used in the first place?
394 if (currentHour == null || currentHour == getCurrentHour()) {
395 return;
396 }
397 if (!is24HourView()) {
398 // convert [0,23] ordinal to wall clock display
Svetoslav Ganovbe17a7f2011-01-31 14:21:56 -0800399 if (currentHour >= HOURS_IN_HALF_DAY) {
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800400 mIsAm = false;
Svetoslav Ganovbe17a7f2011-01-31 14:21:56 -0800401 if (currentHour > HOURS_IN_HALF_DAY) {
402 currentHour = currentHour - HOURS_IN_HALF_DAY;
403 }
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800404 } else {
Svetoslav Ganovbe17a7f2011-01-31 14:21:56 -0800405 mIsAm = true;
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800406 if (currentHour == 0) {
407 currentHour = HOURS_IN_HALF_DAY;
408 }
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800409 }
410 updateAmPmControl();
411 }
412 mHourSpinner.setValue(currentHour);
413 onTimeChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 }
415
416 /**
417 * Set whether in 24 hour or AM/PM mode.
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800418 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 * @param is24HourView True = 24 hour mode. False = AM/PM.
420 */
421 public void setIs24HourView(Boolean is24HourView) {
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800422 if (mIs24HourView == is24HourView) {
423 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 }
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800425 mIs24HourView = is24HourView;
426 // cache the current hour since spinner range changes
427 int currentHour = getCurrentHour();
428 updateHourControl();
429 // set value after spinner range is updated
430 setCurrentHour(currentHour);
431 updateAmPmControl();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 }
433
434 /**
435 * @return true if this is in 24 hour view else false.
436 */
437 public boolean is24HourView() {
438 return mIs24HourView;
439 }
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 /**
442 * @return The current minute.
443 */
444 public Integer getCurrentMinute() {
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800445 return mMinuteSpinner.getValue();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 }
447
448 /**
449 * Set the current minute (0-59).
450 */
451 public void setCurrentMinute(Integer currentMinute) {
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800452 if (currentMinute == getCurrentMinute()) {
453 return;
454 }
455 mMinuteSpinner.setValue(currentMinute);
456 onTimeChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 }
458
459 @Override
460 public int getBaseline() {
Svetoslav Ganove9730bf2010-12-20 21:25:20 -0800461 return mHourSpinner.getBaseline();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 }
463
Svetoslav Ganov8a2a8952011-01-27 17:40:13 -0800464 @Override
Svetoslav Ganov3fec3fe2011-09-01 14:48:37 -0700465 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
466 onPopulateAccessibilityEvent(event);
467 return true;
468 }
469
470 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700471 public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
472 super.onPopulateAccessibilityEvent(event);
473
Svetoslav Ganov8a2a8952011-01-27 17:40:13 -0800474 int flags = DateUtils.FORMAT_SHOW_TIME;
475 if (mIs24HourView) {
476 flags |= DateUtils.FORMAT_24HOUR;
477 } else {
478 flags |= DateUtils.FORMAT_12HOUR;
479 }
480 mTempCalendar.set(Calendar.HOUR_OF_DAY, getCurrentHour());
481 mTempCalendar.set(Calendar.MINUTE, getCurrentMinute());
482 String selectedDateUtterance = DateUtils.formatDateTime(mContext,
483 mTempCalendar.getTimeInMillis(), flags);
484 event.getText().add(selectedDateUtterance);
Svetoslav Ganov8a2a8952011-01-27 17:40:13 -0800485 }
486
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -0800487 @Override
488 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
489 super.onInitializeAccessibilityEvent(event);
490 event.setClassName(TimePicker.class.getName());
491 }
492
493 @Override
494 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
495 super.onInitializeAccessibilityNodeInfo(info);
496 info.setClassName(TimePicker.class.getName());
497 }
498
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800499 private void updateHourControl() {
500 if (is24HourView()) {
Svetoslav Ganove9730bf2010-12-20 21:25:20 -0800501 mHourSpinner.setMinValue(0);
502 mHourSpinner.setMaxValue(23);
503 mHourSpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 } else {
Svetoslav Ganove9730bf2010-12-20 21:25:20 -0800505 mHourSpinner.setMinValue(1);
506 mHourSpinner.setMaxValue(12);
507 mHourSpinner.setFormatter(null);
Svetoslav Ganov4243dc32011-01-18 19:39:57 -0800508 }
509 }
510
511 private void updateAmPmControl() {
512 if (is24HourView()) {
513 if (mAmPmSpinner != null) {
514 mAmPmSpinner.setVisibility(View.GONE);
515 } else {
516 mAmPmButton.setVisibility(View.GONE);
517 }
518 } else {
519 int index = mIsAm ? Calendar.AM : Calendar.PM;
520 if (mAmPmSpinner != null) {
521 mAmPmSpinner.setValue(index);
522 mAmPmSpinner.setVisibility(View.VISIBLE);
523 } else {
524 mAmPmButton.setText(mAmPmStrings[index]);
525 mAmPmButton.setVisibility(View.VISIBLE);
526 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 }
Svetoslav Ganov8a2a8952011-01-27 17:40:13 -0800528 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 }
530
531 private void onTimeChanged() {
Svetoslav Ganov8a2a8952011-01-27 17:40:13 -0800532 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
Svetoslav Ganov206316a2010-11-19 00:04:05 -0800533 if (mOnTimeChangedListener != null) {
534 mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute());
535 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 }
Svetoslav Ganov3fec3fe2011-09-01 14:48:37 -0700537
538 private void setContentDescriptions() {
539 // Minute
Svetoslav Ganovd11e6152012-03-20 12:13:02 -0700540 trySetContentDescription(mMinuteSpinner, R.id.increment,
541 R.string.time_picker_increment_minute_button);
542 trySetContentDescription(mMinuteSpinner, R.id.decrement,
543 R.string.time_picker_decrement_minute_button);
Svetoslav Ganov3fec3fe2011-09-01 14:48:37 -0700544 // Hour
Svetoslav Ganovd11e6152012-03-20 12:13:02 -0700545 trySetContentDescription(mHourSpinner, R.id.increment,
546 R.string.time_picker_increment_hour_button);
547 trySetContentDescription(mHourSpinner, R.id.decrement,
548 R.string.time_picker_decrement_hour_button);
Svetoslav Ganov3fec3fe2011-09-01 14:48:37 -0700549 // AM/PM
Svetoslav Ganov11c91322011-09-14 18:35:44 -0700550 if (mAmPmSpinner != null) {
Svetoslav Ganovd11e6152012-03-20 12:13:02 -0700551 trySetContentDescription(mAmPmSpinner, R.id.increment,
552 R.string.time_picker_increment_set_pm_button);
553 trySetContentDescription(mAmPmSpinner, R.id.decrement,
554 R.string.time_picker_decrement_set_am_button);
555 }
556 }
557
558 private void trySetContentDescription(View root, int viewId, int contDescResId) {
559 View target = root.findViewById(viewId);
560 if (target != null) {
561 target.setContentDescription(mContext.getString(contDescResId));
Svetoslav Ganov11c91322011-09-14 18:35:44 -0700562 }
Svetoslav Ganov3fec3fe2011-09-01 14:48:37 -0700563 }
Svetoslav Ganov6304b0d2011-10-19 19:55:44 -0700564
565 private void updateInputState() {
566 // Make sure that if the user changes the value and the IME is active
567 // for one of the inputs if this widget, the IME is closed. If the user
568 // changed the value via the IME and there is a next input the IME will
569 // be shown, otherwise the user chose another means of changing the
570 // value and having the IME up makes no sense.
571 InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
572 if (inputMethodManager != null) {
573 if (inputMethodManager.isActive(mHourSpinnerInput)) {
574 mHourSpinnerInput.clearFocus();
575 inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
576 } else if (inputMethodManager.isActive(mMinuteSpinnerInput)) {
577 mMinuteSpinnerInput.clearFocus();
578 inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
579 } else if (inputMethodManager.isActive(mAmPmSpinnerInput)) {
580 mAmPmSpinnerInput.clearFocus();
581 inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
582 }
583 }
584 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585}