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.app;
18 
19 import android.annotation.TestApi;
20 import android.compat.annotation.UnsupportedAppUsage;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.content.DialogInterface.OnClickListener;
24 import android.os.Bundle;
25 import android.util.TypedValue;
26 import android.view.LayoutInflater;
27 import android.view.View;
28 import android.widget.TimePicker;
29 import android.widget.TimePicker.OnTimeChangedListener;
30 
31 import com.android.internal.R;
32 
33 /**
34  * A dialog that prompts the user for the time of day using a
35  * {@link TimePicker}.
36  *
37  * <p>
38  * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
39  * guide.
40  */
41 public class TimePickerDialog extends AlertDialog implements OnClickListener,
42         OnTimeChangedListener {
43     private static final String HOUR = "hour";
44     private static final String MINUTE = "minute";
45     private static final String IS_24_HOUR = "is24hour";
46 
47     @UnsupportedAppUsage
48     private final TimePicker mTimePicker;
49     private final OnTimeSetListener mTimeSetListener;
50 
51     private final int mInitialHourOfDay;
52     private final int mInitialMinute;
53     private final boolean mIs24HourView;
54 
55     /**
56      * The callback interface used to indicate the user is done filling in
57      * the time (e.g. they clicked on the 'OK' button).
58      */
59     public interface OnTimeSetListener {
60         /**
61          * Called when the user is done setting a new time and the dialog has
62          * closed.
63          *
64          * @param view the view associated with this listener
65          * @param hourOfDay the hour that was set
66          * @param minute the minute that was set
67          */
onTimeSet(TimePicker view, int hourOfDay, int minute)68         void onTimeSet(TimePicker view, int hourOfDay, int minute);
69     }
70 
71     /**
72      * Creates a new time picker dialog.
73      *
74      * @param context the parent context
75      * @param listener the listener to call when the time is set
76      * @param hourOfDay the initial hour
77      * @param minute the initial minute
78      * @param is24HourView whether this is a 24 hour view or AM/PM
79      */
TimePickerDialog(Context context, OnTimeSetListener listener, int hourOfDay, int minute, boolean is24HourView)80     public TimePickerDialog(Context context, OnTimeSetListener listener, int hourOfDay, int minute,
81             boolean is24HourView) {
82         this(context, 0, listener, hourOfDay, minute, is24HourView);
83     }
84 
resolveDialogTheme(Context context, int resId)85     static int resolveDialogTheme(Context context, int resId) {
86         if (resId == 0) {
87             final TypedValue outValue = new TypedValue();
88             context.getTheme().resolveAttribute(R.attr.timePickerDialogTheme, outValue, true);
89             return outValue.resourceId;
90         } else {
91             return resId;
92         }
93     }
94 
95     /**
96      * Creates a new time picker dialog with the specified theme.
97      * <p>
98      * The theme is overlaid on top of the theme of the parent {@code context}.
99      * If {@code themeResId} is 0, the dialog will be inflated using the theme
100      * specified by the
101      * {@link android.R.attr#timePickerDialogTheme android:timePickerDialogTheme}
102      * attribute on the parent {@code context}'s theme.
103      *
104      * @param context the parent context
105      * @param themeResId the resource ID of the theme to apply to this dialog
106      * @param listener the listener to call when the time is set
107      * @param hourOfDay the initial hour
108      * @param minute the initial minute
109      * @param is24HourView Whether this is a 24 hour view, or AM/PM.
110      */
TimePickerDialog(Context context, int themeResId, OnTimeSetListener listener, int hourOfDay, int minute, boolean is24HourView)111     public TimePickerDialog(Context context, int themeResId, OnTimeSetListener listener,
112             int hourOfDay, int minute, boolean is24HourView) {
113         super(context, resolveDialogTheme(context, themeResId));
114 
115         mTimeSetListener = listener;
116         mInitialHourOfDay = hourOfDay;
117         mInitialMinute = minute;
118         mIs24HourView = is24HourView;
119 
120         final Context themeContext = getContext();
121         final LayoutInflater inflater = LayoutInflater.from(themeContext);
122         final View view = inflater.inflate(R.layout.time_picker_dialog, null);
123         setView(view);
124         setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
125         setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
126         setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
127 
128         mTimePicker = (TimePicker) view.findViewById(R.id.timePicker);
129         mTimePicker.setIs24HourView(mIs24HourView);
130         mTimePicker.setCurrentHour(mInitialHourOfDay);
131         mTimePicker.setCurrentMinute(mInitialMinute);
132         mTimePicker.setOnTimeChangedListener(this);
133     }
134 
135     /**
136      * @return the time picker displayed in the dialog
137      * @hide For testing only.
138      */
139     @TestApi
getTimePicker()140     public TimePicker getTimePicker() {
141         return mTimePicker;
142     }
143 
144     @Override
onTimeChanged(TimePicker view, int hourOfDay, int minute)145     public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
146         /* do nothing */
147     }
148 
149     @Override
show()150     public void show() {
151         super.show();
152         getButton(BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
153             @Override
154             public void onClick(View view) {
155                 if (mTimePicker.validateInput()) {
156                     TimePickerDialog.this.onClick(TimePickerDialog.this, BUTTON_POSITIVE);
157                     // Clearing focus forces the dialog to commit any pending
158                     // changes, e.g. typed text in a NumberPicker.
159                     mTimePicker.clearFocus();
160                     dismiss();
161                 }
162             }
163         });
164     }
165 
166     @Override
onClick(DialogInterface dialog, int which)167     public void onClick(DialogInterface dialog, int which) {
168         switch (which) {
169             case BUTTON_POSITIVE:
170                 // Note this skips input validation and just uses the last valid time and hour
171                 // entry. This will only be invoked programmatically. User clicks on BUTTON_POSITIVE
172                 // are handled in show().
173                 if (mTimeSetListener != null) {
174                     mTimeSetListener.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
175                             mTimePicker.getCurrentMinute());
176                 }
177                 break;
178             case BUTTON_NEGATIVE:
179                 cancel();
180                 break;
181         }
182     }
183 
184     /**
185      * Sets the current time.
186      *
187      * @param hourOfDay The current hour within the day.
188      * @param minuteOfHour The current minute within the hour.
189      */
updateTime(int hourOfDay, int minuteOfHour)190     public void updateTime(int hourOfDay, int minuteOfHour) {
191         mTimePicker.setCurrentHour(hourOfDay);
192         mTimePicker.setCurrentMinute(minuteOfHour);
193     }
194 
195     @Override
onSaveInstanceState()196     public Bundle onSaveInstanceState() {
197         final Bundle state = super.onSaveInstanceState();
198         state.putInt(HOUR, mTimePicker.getCurrentHour());
199         state.putInt(MINUTE, mTimePicker.getCurrentMinute());
200         state.putBoolean(IS_24_HOUR, mTimePicker.is24HourView());
201         return state;
202     }
203 
204     @Override
onRestoreInstanceState(Bundle savedInstanceState)205     public void onRestoreInstanceState(Bundle savedInstanceState) {
206         super.onRestoreInstanceState(savedInstanceState);
207         final int hour = savedInstanceState.getInt(HOUR);
208         final int minute = savedInstanceState.getInt(MINUTE);
209         mTimePicker.setIs24HourView(savedInstanceState.getBoolean(IS_24_HOUR));
210         mTimePicker.setCurrentHour(hour);
211         mTimePicker.setCurrentMinute(minute);
212     }
213 }
214