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.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.Widget;
22 import android.content.Context;
23 import android.content.res.Configuration;
24 import android.content.res.TypedArray;
25 import android.os.Parcelable;
26 import android.util.AttributeSet;
27 import android.view.accessibility.AccessibilityEvent;
28 import com.android.internal.R;
29 
30 import java.util.Locale;
31 
32 /**
33  * A widget for selecting the time of day, in either 24-hour or AM/PM mode.
34  * <p>
35  * For a dialog using this view, see {@link android.app.TimePickerDialog}. See
36  * the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
37  * guide for more information.
38  *
39  * @attr ref android.R.styleable#TimePicker_timePickerMode
40  */
41 @Widget
42 public class TimePicker extends FrameLayout {
43     private static final int MODE_SPINNER = 1;
44     private static final int MODE_CLOCK = 2;
45 
46     private final TimePickerDelegate mDelegate;
47 
48     /**
49      * The callback interface used to indicate the time has been adjusted.
50      */
51     public interface OnTimeChangedListener {
52 
53         /**
54          * @param view The view associated with this listener.
55          * @param hourOfDay The current hour.
56          * @param minute The current minute.
57          */
onTimeChanged(TimePicker view, int hourOfDay, int minute)58         void onTimeChanged(TimePicker view, int hourOfDay, int minute);
59     }
60 
TimePicker(Context context)61     public TimePicker(Context context) {
62         this(context, null);
63     }
64 
TimePicker(Context context, AttributeSet attrs)65     public TimePicker(Context context, AttributeSet attrs) {
66         this(context, attrs, R.attr.timePickerStyle);
67     }
68 
TimePicker(Context context, AttributeSet attrs, int defStyleAttr)69     public TimePicker(Context context, AttributeSet attrs, int defStyleAttr) {
70         this(context, attrs, defStyleAttr, 0);
71     }
72 
TimePicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)73     public TimePicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
74         super(context, attrs, defStyleAttr, defStyleRes);
75 
76         final TypedArray a = context.obtainStyledAttributes(
77                 attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
78         final int mode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
79         a.recycle();
80 
81         switch (mode) {
82             case MODE_CLOCK:
83                 mDelegate = new TimePickerClockDelegate(
84                         this, context, attrs, defStyleAttr, defStyleRes);
85                 break;
86             case MODE_SPINNER:
87             default:
88                 mDelegate = new TimePickerSpinnerDelegate(
89                         this, context, attrs, defStyleAttr, defStyleRes);
90                 break;
91         }
92     }
93 
94     /**
95      * Sets the currently selected hour using 24-hour time.
96      *
97      * @param hour the hour to set, in the range (0-23)
98      * @see #getHour()
99      */
setHour(int hour)100     public void setHour(int hour) {
101         mDelegate.setCurrentHour(hour);
102     }
103 
104     /**
105      * Returns the currently selected hour using 24-hour time.
106      *
107      * @return the currently selected hour, in the range (0-23)
108      * @see #setHour(int)
109      */
getHour()110     public int getHour() {
111         return mDelegate.getCurrentHour();
112     }
113 
114     /**
115      * Sets the currently selected minute..
116      *
117      * @param minute the minute to set, in the range (0-59)
118      * @see #getMinute()
119      */
setMinute(int minute)120     public void setMinute(int minute) {
121         mDelegate.setCurrentMinute(minute);
122     }
123 
124     /**
125      * Returns the currently selected minute.
126      *
127      * @return the currently selected minute, in the range (0-59)
128      * @see #setMinute(int)
129      */
getMinute()130     public int getMinute() {
131         return mDelegate.getCurrentMinute();
132     }
133 
134     /**
135      * Sets the current hour.
136      *
137      * @deprecated Use {@link #setHour(int)}
138      */
139     @Deprecated
setCurrentHour(@onNull Integer currentHour)140     public void setCurrentHour(@NonNull Integer currentHour) {
141         setHour(currentHour);
142     }
143 
144     /**
145      * @return the current hour in the range (0-23)
146      * @deprecated Use {@link #getHour()}
147      */
148     @NonNull
149     @Deprecated
getCurrentHour()150     public Integer getCurrentHour() {
151         return mDelegate.getCurrentHour();
152     }
153 
154     /**
155      * Set the current minute (0-59).
156      *
157      * @deprecated Use {@link #setMinute(int)}
158      */
159     @Deprecated
setCurrentMinute(@onNull Integer currentMinute)160     public void setCurrentMinute(@NonNull Integer currentMinute) {
161         mDelegate.setCurrentMinute(currentMinute);
162     }
163 
164     /**
165      * @return the current minute
166      * @deprecated Use {@link #getMinute()}
167      */
168     @NonNull
169     @Deprecated
getCurrentMinute()170     public Integer getCurrentMinute() {
171         return mDelegate.getCurrentMinute();
172     }
173 
174     /**
175      * Sets whether this widget displays time in 24-hour mode or 12-hour mode
176      * with an AM/PM picker.
177      *
178      * @param is24HourView {@code true} to display in 24-hour mode,
179      *                     {@code false} for 12-hour mode with AM/PM
180      * @see #is24HourView()
181      */
setIs24HourView(@onNull Boolean is24HourView)182     public void setIs24HourView(@NonNull Boolean is24HourView) {
183         if (is24HourView == null) {
184             return;
185         }
186 
187         mDelegate.setIs24HourView(is24HourView);
188     }
189 
190     /**
191      * @return {@code true} if this widget displays time in 24-hour mode,
192      *         {@code false} otherwise}
193      * @see #setIs24HourView(Boolean)
194      */
is24HourView()195     public boolean is24HourView() {
196         return mDelegate.is24HourView();
197     }
198 
199     /**
200      * Set the callback that indicates the time has been adjusted by the user.
201      *
202      * @param onTimeChangedListener the callback, should not be null.
203      */
setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener)204     public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) {
205         mDelegate.setOnTimeChangedListener(onTimeChangedListener);
206     }
207 
208     /**
209      * Sets the callback that indicates the current time is valid.
210      *
211      * @param callback the callback, may be null
212      * @hide
213      */
setValidationCallback(@ullable ValidationCallback callback)214     public void setValidationCallback(@Nullable ValidationCallback callback) {
215         mDelegate.setValidationCallback(callback);
216     }
217 
218     @Override
setEnabled(boolean enabled)219     public void setEnabled(boolean enabled) {
220         super.setEnabled(enabled);
221         mDelegate.setEnabled(enabled);
222     }
223 
224     @Override
isEnabled()225     public boolean isEnabled() {
226         return mDelegate.isEnabled();
227     }
228 
229     @Override
getBaseline()230     public int getBaseline() {
231         return mDelegate.getBaseline();
232     }
233 
234     @Override
onConfigurationChanged(Configuration newConfig)235     protected void onConfigurationChanged(Configuration newConfig) {
236         super.onConfigurationChanged(newConfig);
237         mDelegate.onConfigurationChanged(newConfig);
238     }
239 
240     @Override
onSaveInstanceState()241     protected Parcelable onSaveInstanceState() {
242         Parcelable superState = super.onSaveInstanceState();
243         return mDelegate.onSaveInstanceState(superState);
244     }
245 
246     @Override
onRestoreInstanceState(Parcelable state)247     protected void onRestoreInstanceState(Parcelable state) {
248         BaseSavedState ss = (BaseSavedState) state;
249         super.onRestoreInstanceState(ss.getSuperState());
250         mDelegate.onRestoreInstanceState(ss);
251     }
252 
253     @Override
getAccessibilityClassName()254     public CharSequence getAccessibilityClassName() {
255         return TimePicker.class.getName();
256     }
257 
258     /** @hide */
259     @Override
dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event)260     public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
261         return mDelegate.dispatchPopulateAccessibilityEvent(event);
262     }
263 
264     /**
265      * A delegate interface that defined the public API of the TimePicker. Allows different
266      * TimePicker implementations. This would need to be implemented by the TimePicker delegates
267      * for the real behavior.
268      */
269     interface TimePickerDelegate {
setCurrentHour(int currentHour)270         void setCurrentHour(int currentHour);
getCurrentHour()271         int getCurrentHour();
272 
setCurrentMinute(int currentMinute)273         void setCurrentMinute(int currentMinute);
getCurrentMinute()274         int getCurrentMinute();
275 
setIs24HourView(boolean is24HourView)276         void setIs24HourView(boolean is24HourView);
is24HourView()277         boolean is24HourView();
278 
setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener)279         void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener);
setValidationCallback(ValidationCallback callback)280         void setValidationCallback(ValidationCallback callback);
281 
setEnabled(boolean enabled)282         void setEnabled(boolean enabled);
isEnabled()283         boolean isEnabled();
284 
getBaseline()285         int getBaseline();
286 
onConfigurationChanged(Configuration newConfig)287         void onConfigurationChanged(Configuration newConfig);
288 
onSaveInstanceState(Parcelable superState)289         Parcelable onSaveInstanceState(Parcelable superState);
onRestoreInstanceState(Parcelable state)290         void onRestoreInstanceState(Parcelable state);
291 
dispatchPopulateAccessibilityEvent(AccessibilityEvent event)292         boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event);
onPopulateAccessibilityEvent(AccessibilityEvent event)293         void onPopulateAccessibilityEvent(AccessibilityEvent event);
294     }
295 
296     /**
297      * A callback interface for updating input validity when the TimePicker
298      * when included into a Dialog.
299      *
300      * @hide
301      */
302     public static interface ValidationCallback {
onValidationChanged(boolean valid)303         void onValidationChanged(boolean valid);
304     }
305 
306     /**
307      * An abstract class which can be used as a start for TimePicker implementations
308      */
309     abstract static class AbstractTimePickerDelegate implements TimePickerDelegate {
310         // The delegator
311         protected TimePicker mDelegator;
312 
313         // The context
314         protected Context mContext;
315 
316         // The current locale
317         protected Locale mCurrentLocale;
318 
319         // Callbacks
320         protected OnTimeChangedListener mOnTimeChangedListener;
321         protected ValidationCallback mValidationCallback;
322 
AbstractTimePickerDelegate(TimePicker delegator, Context context)323         public AbstractTimePickerDelegate(TimePicker delegator, Context context) {
324             mDelegator = delegator;
325             mContext = context;
326 
327             // initialization based on locale
328             setCurrentLocale(Locale.getDefault());
329         }
330 
setCurrentLocale(Locale locale)331         public void setCurrentLocale(Locale locale) {
332             if (locale.equals(mCurrentLocale)) {
333                 return;
334             }
335             mCurrentLocale = locale;
336         }
337 
338         @Override
setValidationCallback(ValidationCallback callback)339         public void setValidationCallback(ValidationCallback callback) {
340             mValidationCallback = callback;
341         }
342 
onValidationChanged(boolean valid)343         protected void onValidationChanged(boolean valid) {
344             if (mValidationCallback != null) {
345                 mValidationCallback.onValidationChanged(valid);
346             }
347         }
348     }
349 }
350