• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.widget;
18 
19 import android.annotation.Widget;
20 import android.content.Context;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.util.AttributeSet;
24 import android.view.LayoutInflater;
25 import android.view.View;
26 import android.widget.NumberPicker;
27 
28 import com.android.internal.R;
29 
30 import java.text.DateFormatSymbols;
31 import java.util.Calendar;
32 
33 /**
34  * A view for selecting the time of day, in either 24 hour or AM/PM mode.
35  *
36  * The hour, each minute digit, and AM/PM (if applicable) can be conrolled by
37  * vertical spinners.
38  *
39  * The hour can be entered by keyboard input.  Entering in two digit hours
40  * can be accomplished by hitting two digits within a timeout of about a
41  * second (e.g. '1' then '2' to select 12).
42  *
43  * The minutes can be entered by entering single digits.
44  *
45  * Under AM/PM mode, the user can hit 'a', 'A", 'p' or 'P' to pick.
46  *
47  * For a dialog using this view, see {@link android.app.TimePickerDialog}.
48  *
49  * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-timepicker.html">Time Picker
50  * tutorial</a>.</p>
51  */
52 @Widget
53 public class TimePicker extends FrameLayout {
54 
55     /**
56      * A no-op callback used in the constructor to avoid null checks
57      * later in the code.
58      */
59     private static final OnTimeChangedListener NO_OP_CHANGE_LISTENER = new OnTimeChangedListener() {
60         public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
61         }
62     };
63 
64     // state
65     private int mCurrentHour = 0; // 0-23
66     private int mCurrentMinute = 0; // 0-59
67     private Boolean mIs24HourView = false;
68     private boolean mIsAm;
69 
70     // ui components
71     private final NumberPicker mHourPicker;
72     private final NumberPicker mMinutePicker;
73     private final Button mAmPmButton;
74     private final String mAmText;
75     private final String mPmText;
76 
77     // callbacks
78     private OnTimeChangedListener mOnTimeChangedListener;
79 
80     /**
81      * The callback interface used to indicate the time has been adjusted.
82      */
83     public interface OnTimeChangedListener {
84 
85         /**
86          * @param view The view associated with this listener.
87          * @param hourOfDay The current hour.
88          * @param minute The current minute.
89          */
onTimeChanged(TimePicker view, int hourOfDay, int minute)90         void onTimeChanged(TimePicker view, int hourOfDay, int minute);
91     }
92 
TimePicker(Context context)93     public TimePicker(Context context) {
94         this(context, null);
95     }
96 
TimePicker(Context context, AttributeSet attrs)97     public TimePicker(Context context, AttributeSet attrs) {
98         this(context, attrs, 0);
99     }
100 
TimePicker(Context context, AttributeSet attrs, int defStyle)101     public TimePicker(Context context, AttributeSet attrs, int defStyle) {
102         super(context, attrs, defStyle);
103 
104         LayoutInflater inflater =
105                 (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
106         inflater.inflate(R.layout.time_picker,
107             this, // we are the parent
108             true);
109 
110         // hour
111         mHourPicker = (NumberPicker) findViewById(R.id.hour);
112         mHourPicker.setOnChangeListener(new NumberPicker.OnChangedListener() {
113             public void onChanged(NumberPicker spinner, int oldVal, int newVal) {
114                 mCurrentHour = newVal;
115                 if (!mIs24HourView) {
116                     // adjust from [1-12] to [0-11] internally, with the times
117                     // written "12:xx" being the start of the half-day
118                     if (mCurrentHour == 12) {
119                         mCurrentHour = 0;
120                     }
121                     if (!mIsAm) {
122                         // PM means 12 hours later than nominal
123                         mCurrentHour += 12;
124                     }
125                 }
126                 onTimeChanged();
127             }
128         });
129 
130         // digits of minute
131         mMinutePicker = (NumberPicker) findViewById(R.id.minute);
132         mMinutePicker.setRange(0, 59);
133         mMinutePicker.setSpeed(100);
134         mMinutePicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
135         mMinutePicker.setOnChangeListener(new NumberPicker.OnChangedListener() {
136             public void onChanged(NumberPicker spinner, int oldVal, int newVal) {
137                 mCurrentMinute = newVal;
138                 onTimeChanged();
139             }
140         });
141 
142         // am/pm
143         mAmPmButton = (Button) findViewById(R.id.amPm);
144 
145         // now that the hour/minute picker objects have been initialized, set
146         // the hour range properly based on the 12/24 hour display mode.
147         configurePickerRanges();
148 
149         // initialize to current time
150         Calendar cal = Calendar.getInstance();
151         setOnTimeChangedListener(NO_OP_CHANGE_LISTENER);
152 
153         // by default we're not in 24 hour mode
154         setCurrentHour(cal.get(Calendar.HOUR_OF_DAY));
155         setCurrentMinute(cal.get(Calendar.MINUTE));
156 
157         mIsAm = (mCurrentHour < 12);
158 
159         /* Get the localized am/pm strings and use them in the spinner */
160         DateFormatSymbols dfs = new DateFormatSymbols();
161         String[] dfsAmPm = dfs.getAmPmStrings();
162         mAmText = dfsAmPm[Calendar.AM];
163         mPmText = dfsAmPm[Calendar.PM];
164         mAmPmButton.setText(mIsAm ? mAmText : mPmText);
165         mAmPmButton.setOnClickListener(new OnClickListener() {
166             public void onClick(View v) {
167                 requestFocus();
168                 if (mIsAm) {
169 
170                     // Currently AM switching to PM
171                     if (mCurrentHour < 12) {
172                         mCurrentHour += 12;
173                     }
174                 } else {
175 
176                     // Currently PM switching to AM
177                     if (mCurrentHour >= 12) {
178                         mCurrentHour -= 12;
179                     }
180                 }
181                 mIsAm = !mIsAm;
182                 mAmPmButton.setText(mIsAm ? mAmText : mPmText);
183                 onTimeChanged();
184             }
185         });
186 
187         if (!isEnabled()) {
188             setEnabled(false);
189         }
190     }
191 
192     @Override
setEnabled(boolean enabled)193     public void setEnabled(boolean enabled) {
194         super.setEnabled(enabled);
195         mMinutePicker.setEnabled(enabled);
196         mHourPicker.setEnabled(enabled);
197         mAmPmButton.setEnabled(enabled);
198     }
199 
200     /**
201      * Used to save / restore state of time picker
202      */
203     private static class SavedState extends BaseSavedState {
204 
205         private final int mHour;
206         private final int mMinute;
207 
SavedState(Parcelable superState, int hour, int minute)208         private SavedState(Parcelable superState, int hour, int minute) {
209             super(superState);
210             mHour = hour;
211             mMinute = minute;
212         }
213 
SavedState(Parcel in)214         private SavedState(Parcel in) {
215             super(in);
216             mHour = in.readInt();
217             mMinute = in.readInt();
218         }
219 
getHour()220         public int getHour() {
221             return mHour;
222         }
223 
getMinute()224         public int getMinute() {
225             return mMinute;
226         }
227 
228         @Override
writeToParcel(Parcel dest, int flags)229         public void writeToParcel(Parcel dest, int flags) {
230             super.writeToParcel(dest, flags);
231             dest.writeInt(mHour);
232             dest.writeInt(mMinute);
233         }
234 
235         public static final Parcelable.Creator<SavedState> CREATOR
236                 = new Creator<SavedState>() {
237             public SavedState createFromParcel(Parcel in) {
238                 return new SavedState(in);
239             }
240 
241             public SavedState[] newArray(int size) {
242                 return new SavedState[size];
243             }
244         };
245     }
246 
247     @Override
onSaveInstanceState()248     protected Parcelable onSaveInstanceState() {
249         Parcelable superState = super.onSaveInstanceState();
250         return new SavedState(superState, mCurrentHour, mCurrentMinute);
251     }
252 
253     @Override
onRestoreInstanceState(Parcelable state)254     protected void onRestoreInstanceState(Parcelable state) {
255         SavedState ss = (SavedState) state;
256         super.onRestoreInstanceState(ss.getSuperState());
257         setCurrentHour(ss.getHour());
258         setCurrentMinute(ss.getMinute());
259     }
260 
261     /**
262      * Set the callback that indicates the time has been adjusted by the user.
263      * @param onTimeChangedListener the callback, should not be null.
264      */
setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener)265     public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) {
266         mOnTimeChangedListener = onTimeChangedListener;
267     }
268 
269     /**
270      * @return The current hour (0-23).
271      */
getCurrentHour()272     public Integer getCurrentHour() {
273         return mCurrentHour;
274     }
275 
276     /**
277      * Set the current hour.
278      */
setCurrentHour(Integer currentHour)279     public void setCurrentHour(Integer currentHour) {
280         this.mCurrentHour = currentHour;
281         updateHourDisplay();
282     }
283 
284     /**
285      * Set whether in 24 hour or AM/PM mode.
286      * @param is24HourView True = 24 hour mode. False = AM/PM.
287      */
setIs24HourView(Boolean is24HourView)288     public void setIs24HourView(Boolean is24HourView) {
289         if (mIs24HourView != is24HourView) {
290             mIs24HourView = is24HourView;
291             configurePickerRanges();
292             updateHourDisplay();
293         }
294     }
295 
296     /**
297      * @return true if this is in 24 hour view else false.
298      */
is24HourView()299     public boolean is24HourView() {
300         return mIs24HourView;
301     }
302 
303     /**
304      * @return The current minute.
305      */
getCurrentMinute()306     public Integer getCurrentMinute() {
307         return mCurrentMinute;
308     }
309 
310     /**
311      * Set the current minute (0-59).
312      */
setCurrentMinute(Integer currentMinute)313     public void setCurrentMinute(Integer currentMinute) {
314         this.mCurrentMinute = currentMinute;
315         updateMinuteDisplay();
316     }
317 
318     @Override
getBaseline()319     public int getBaseline() {
320         return mHourPicker.getBaseline();
321     }
322 
323     /**
324      * Set the state of the spinners appropriate to the current hour.
325      */
updateHourDisplay()326     private void updateHourDisplay() {
327         int currentHour = mCurrentHour;
328         if (!mIs24HourView) {
329             // convert [0,23] ordinal to wall clock display
330             if (currentHour > 12) currentHour -= 12;
331             else if (currentHour == 0) currentHour = 12;
332         }
333         mHourPicker.setCurrent(currentHour);
334         mIsAm = mCurrentHour < 12;
335         mAmPmButton.setText(mIsAm ? mAmText : mPmText);
336         onTimeChanged();
337     }
338 
339     private void configurePickerRanges() {
340         if (mIs24HourView) {
341             mHourPicker.setRange(0, 23);
342             mHourPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
343             mAmPmButton.setVisibility(View.GONE);
344         } else {
345             mHourPicker.setRange(1, 12);
346             mHourPicker.setFormatter(null);
347             mAmPmButton.setVisibility(View.VISIBLE);
348         }
349     }
350 
351     private void onTimeChanged() {
352         mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute());
353     }
354 
355     /**
356      * Set the state of the spinners appropriate to the current minute.
357      */
358     private void updateMinuteDisplay() {
359         mMinutePicker.setCurrent(mCurrentMinute);
360         mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute());
361     }
362 }
363