• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 com.android.deskclock;
18 
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.util.AttributeSet;
24 import android.view.View;
25 import android.widget.Button;
26 import android.widget.TextView;
27 
28 import java.text.DateFormatSymbols;
29 
30 
31 public class TimePicker extends TimerSetupView implements Button.OnClickListener{
32 
33     private TextView mAmPmLabel;
34     private String[] mAmpm;
35     private final String mNoAmPmLabel;
36     private int mAmPmState;
37     private Button mSetButton;
38     private final boolean mIs24HoursMode = Alarms.get24HourMode(mContext);
39 
40     private static final int AMPM_NOT_SELECTED = 0;
41     private static final int PM_SELECTED = 1;
42     private static final int AM_SELECTED = 2;
43     private static final int HOURS24_MODE = 3;
44 
45     private static final String TIME_PICKER_SAVED_BUFFER_POINTER =
46             "timer_picker_saved_buffer_pointer";
47     private static final String TIME_PICKER_SAVED_INPUT = "timer_picker_saved_input";
48     private static final String TIME_PICKER_SAVED_AMPM = "timer_picker_saved_ampm";
49 
TimePicker(Context context)50     public TimePicker(Context context) {
51         this(context, null);
52     }
53 
TimePicker(Context context, AttributeSet attrs)54     public TimePicker(Context context, AttributeSet attrs) {
55         super(context, attrs);
56         mInputSize = 4;
57         mNoAmPmLabel = context.getResources().getString(R.string.time_picker_ampm_label);
58     }
59 
60     @Override
getLayoutId()61     protected int getLayoutId() {
62         return R.layout.time_picker_view;
63     }
64 
65     @Override
onFinishInflate()66     protected void onFinishInflate() {
67         super.onFinishInflate();
68         Resources res = mContext.getResources();
69         mAmpm = new DateFormatSymbols().getAmPmStrings();
70 
71         if (mIs24HoursMode) {
72             mLeft.setText(res.getString(R.string.time_picker_00_label));
73             mRight.setText(res.getString(R.string.time_picker_30_label));
74         } else {
75             mLeft.setText(mAmpm[0]);
76             mRight.setText(mAmpm[1]);
77         }
78         mLeft.setOnClickListener(this);
79         mRight.setOnClickListener(this);
80         mAmPmLabel = (TextView)findViewById(R.id.ampm_label);
81         mAmPmState = AMPM_NOT_SELECTED;
82         updateKeypad();
83     }
84 
85 
86     @Override
onClick(View v)87     public void onClick(View v) {
88         doOnClick(v);
89     }
90 
91     @Override
doOnClick(View v)92     protected void doOnClick(View v) {
93         Integer val = (Integer) v.getTag(R.id.numbers_key);
94         // A number was pressed
95         if (val != null) {
96             addClickedNumber(val);
97         } else if (v == mDelete) {
98             // Pressing delete when AM or PM is selected, clears the AM/PM
99             // selection
100             if (!mIs24HoursMode && mAmPmState != AMPM_NOT_SELECTED) {
101                 mAmPmState = AMPM_NOT_SELECTED;
102             } else if (mInputPointer >= 0) {
103                 for (int i = 0; i < mInputPointer; i++) {
104                     mInput[i] = mInput[i + 1];
105                 }
106                 mInput[mInputPointer] = 0;
107                 mInputPointer--;
108             }
109         } else if (v == mLeft) {
110             onLeftClicked();
111         } else if (v == mRight) {
112             onRightClicked();
113         }
114         updateKeypad();
115     }
116 
117     @Override
onLongClick(View v)118     public boolean onLongClick(View v) {
119         if (v == mDelete) {
120             mAmPmState = AMPM_NOT_SELECTED;
121             reset();
122             updateKeypad();
123             return true;
124         }
125         return false;
126     }
127 
updateKeypad()128     private void updateKeypad() {
129         // Update state of keypad
130         // Set the correct AM/PM state
131         showAmPm();
132         // Update the time
133         updateLeftRightButtons();
134         updateTime();
135         // enable/disable numeric keys according to the numbers entered already
136         updateNumericKeys();
137         // enable/disable the "set" key
138         enableSetButton();
139         // Update the backspace button
140         updateDeleteButton();
141 
142     }
143 
144     // Update the time displayed in the picker:
145     // Special cases:
146     // 1. show "-" for digits not entered yet.
147     // 2. hide the hours digits when it is not relevant
148     @Override
updateTime()149     protected void updateTime() {
150         // Put "-" in digits that was not entered by passing -1
151         // Hide digit by passing -2 (for highest hours digit only);
152 
153         int  hours1 = -1;
154         int time = getEnteredTime();
155         // If the user entered 2 to 9 or 13 to 15 , there is no need for a 4th digit (AM/PM mode)
156         // If the user entered 3 to 9 or 24 to 25 , there is no need for a 4th digit (24 hours mode)
157         if (mInputPointer > -1) {
158             // Test to see if the highest digit is 2 to 9 for AM/PM or 3 to 9 for 24 hours mode
159             if (mInputPointer >= 0) {
160                 int digit = mInput[mInputPointer];
161                 if ((mIs24HoursMode && digit >= 3 && digit <= 9) ||
162                         (!mIs24HoursMode && digit >= 2 && digit <= 9)) {
163                     hours1 = -2;
164                 }
165             }
166             // Test to see if the 2 highest digits are 13 to 15 for AM/PM or 24 to 25 for 24 hours
167             // mode
168             if (mInputPointer > 0 && mInputPointer < 3 && hours1 != -2) {
169                 int digits = mInput[mInputPointer] * 10 + mInput[mInputPointer - 1];
170                 if ((mIs24HoursMode && digits >= 24 && digits <= 25) ||
171                         (!mIs24HoursMode && digits >= 13 && digits <= 15)) {
172                     hours1 = -2;
173                 }
174             }
175             // If we have a digit show it
176             if (mInputPointer == 3) {
177                 hours1 = mInput[3];
178             }
179         } else {
180             hours1 = -1;
181         }
182         int hours2 = (mInputPointer < 2) ? -1 :  mInput[2];
183         int minutes1 = (mInputPointer < 1) ? -1 :  mInput[1];
184         int minutes2 = (mInputPointer < 0) ? -1 :  mInput[0];
185         mEnteredTime.setTime(hours1, hours2, minutes1, minutes2, -1);
186     }
187 
showAmPm()188     private void showAmPm() {
189         if (!mIs24HoursMode) {
190             switch(mAmPmState) {
191                 case AMPM_NOT_SELECTED:
192                     mAmPmLabel.setText(mNoAmPmLabel);
193                     break;
194                 case AM_SELECTED:
195                     mAmPmLabel.setText(mAmpm[0]);
196                     break;
197                 case PM_SELECTED:
198                     mAmPmLabel.setText(mAmpm[1]);
199                     break;
200                 default:
201                     break;
202             }
203         } else {
204             mAmPmLabel.setVisibility(View.INVISIBLE);
205             mAmPmState = HOURS24_MODE;
206         }
207     }
208 
addClickedNumber(int val)209     private void addClickedNumber(int val) {
210         if (mInputPointer < mInputSize - 1) {
211             for (int i = mInputPointer; i >= 0; i--) {
212                 mInput[i + 1] = mInput[i];
213             }
214             mInputPointer++;
215             mInput[0] = val;
216         }
217     }
218 
219     // Clicking on the bottom left button will add "00" to the time
220     // In AM/PM mode is will also set the time to AM.
onLeftClicked()221     private void onLeftClicked() {
222         int time = getEnteredTime();
223         if (!mIs24HoursMode) {
224             if (canAddDigits()) {
225                 addClickedNumber(0);
226                 addClickedNumber(0);
227             }
228             mAmPmState = AM_SELECTED;
229         } else if (canAddDigits()) {
230                 addClickedNumber(0);
231                 addClickedNumber(0);
232         }
233     }
234 
235     // Clicking on the bottom right button will add "00" to the time in AM/PM
236     // mode and "30" is 24 hours mode.
237     // In AM/PM mode is will also set the time to PM.
onRightClicked()238     private void onRightClicked() {
239         int time = getEnteredTime();
240         if (!mIs24HoursMode) {
241             if (canAddDigits()) {
242                 addClickedNumber(0);
243                 addClickedNumber(0);
244             }
245             mAmPmState = PM_SELECTED;
246         } else {
247             if (canAddDigits()) {
248                 addClickedNumber(3);
249                 addClickedNumber(0);
250             }
251         }
252     }
253 
254     // Checks if the user allowed to click on the left or right button that enters "00" or "30"
canAddDigits()255     private boolean canAddDigits() {
256         int time = getEnteredTime();
257         // For AM/PM mode , can add "00" if an hour between 1 and 12 was entered
258         if (!mIs24HoursMode) {
259             return (time >= 1 && time <= 12);
260         }
261         // For 24 hours mode , can add "00"/"30" if an hour between 0 and 23 was entered
262         return (time >= 0 && time <= 23 && mInputPointer > -1 && mInputPointer < 2);
263     }
264 
265 
266     // Enable/disable keys in the numeric key pad according to the data entered
updateNumericKeys()267     private void updateNumericKeys() {
268         int time = getEnteredTime();
269         if (mIs24HoursMode) {
270             if (mInputPointer >= 3) {
271                 setKeyRange(-1);
272             } else if (time == 0) {
273                 if (mInputPointer == -1 || mInputPointer == 0 || mInputPointer == 2) {
274                     setKeyRange(9);
275                 } else if (mInputPointer == 1) {
276                     setKeyRange(5);
277                 } else {
278                     setKeyRange(-1);
279                 }
280             } else if (time == 1) {
281                 if (mInputPointer == 0 || mInputPointer == 2) {
282                     setKeyRange(9);
283                 } else  if (mInputPointer == 1) {
284                     setKeyRange(5);
285                 } else {
286                     setKeyRange(-1);
287                 }
288             } else if (time == 2) {
289                 if (mInputPointer == 2|| mInputPointer == 1) {
290                     setKeyRange(9);
291                 } else  if (mInputPointer == 0) {
292                     setKeyRange(3);
293                 } else {
294                     setKeyRange(-1);
295                 }
296             } else if (time <= 5) {
297                 setKeyRange(9);
298             } else if (time <= 9) {
299                 setKeyRange(5);
300             } else if (time >= 10 && time <= 15) {
301                 setKeyRange(9);
302             } else if (time >= 16 && time <= 19) {
303                 setKeyRange(5);
304             } else if (time >= 20 && time <= 25) {
305                 setKeyRange(9);
306             } else if (time >= 26 && time <= 29) {
307                 setKeyRange(-1);
308             } else if (time >= 30 && time <= 35) {
309                 setKeyRange(9);
310             } else if (time >= 36 && time <= 39) {
311                 setKeyRange(-1);
312             } else if (time >= 40 && time <= 45) {
313                 setKeyRange(9);
314             } else if (time >= 46 && time <= 49) {
315                 setKeyRange(-1);
316             } else if (time >= 50 && time <= 55) {
317                 setKeyRange(9);
318             } else if (time >= 56 && time <= 59) {
319                 setKeyRange(-1);
320             } else if (time >= 60 && time <= 65) {
321                 setKeyRange(9);
322             } else if (time >= 70 && time <= 75) {
323                 setKeyRange(9);
324             } else if (time >= 80 && time <= 85) {
325                 setKeyRange(9);
326             } else if (time >= 90 && time <= 95) {
327                 setKeyRange(9);
328             } else if (time >= 100 && time <= 105) {
329                 setKeyRange(9);
330             } else if (time >= 106 && time <= 109) {
331                 setKeyRange(-1);
332             } else if (time >= 110 && time <= 115) {
333                 setKeyRange(9);
334             } else if (time >= 116 && time <= 119) {
335                 setKeyRange(-1);
336             } else if (time >= 120 && time <= 125) {
337                 setKeyRange(9);
338             } else if (time >= 126 && time <= 129) {
339                 setKeyRange(-1);
340             } else if (time >= 130 && time <= 135) {
341                 setKeyRange(9);
342             } else if (time >= 136 && time <= 139) {
343                 setKeyRange(-1);
344             } else if (time >= 140 && time <= 145) {
345                 setKeyRange(9);
346             } else if (time >= 146 && time <= 149) {
347                 setKeyRange(-1);
348             } else if (time >= 150 && time <= 155) {
349                 setKeyRange(9);
350             } else if (time >= 156 && time <= 159) {
351                 setKeyRange(-1);
352             } else if (time >= 160 && time <= 165) {
353                 setKeyRange(9);
354             } else if (time >= 166 && time <= 169) {
355                 setKeyRange(-1);
356             } else if (time >= 170 && time <= 175) {
357                 setKeyRange(9);
358             } else if (time >= 176 && time <= 179) {
359                 setKeyRange(-1);
360             } else if (time >= 180 && time <= 185) {
361                 setKeyRange(9);
362             } else if (time >= 186 && time <= 189) {
363                 setKeyRange(-1);
364             } else if (time >= 190 && time <= 195) {
365                 setKeyRange(9);
366             } else if (time >= 196 && time <= 199) {
367                 setKeyRange(-1);
368             } else if (time >= 200 && time <= 205) {
369                 setKeyRange(9);
370             } else if (time >= 206 && time <= 209) {
371                 setKeyRange(-1);
372             } else if (time >= 210 && time <= 215) {
373                 setKeyRange(9);
374             } else if (time >= 216 && time <= 219) {
375                 setKeyRange(-1);
376             } else if (time >= 220 && time <= 225) {
377                 setKeyRange(9);
378             } else if (time >= 226 && time <= 229) {
379                 setKeyRange(-1);
380             } else if (time >= 230 && time <= 235) {
381                 setKeyRange(9);
382             } else if (time >= 236) {
383                 setKeyRange(-1);
384             }
385         } else {
386             // Selecting AM/PM disabled the keypad
387             if (mAmPmState != AMPM_NOT_SELECTED) {
388                 setKeyRange(-1);
389             } else if (time == 0) {
390                 setKeyRange(9);
391                 // If 0 was entered as the first digit in AM/PM mode, do not allow a second 0
392         //        if (mInputPointer == 0) {
393                     mNumbers[0].setEnabled(false);
394           //      }
395             } else if (time <= 9) {
396                 setKeyRange(5);
397             } else if (time <= 95) {
398                 setKeyRange(9);
399             } else if (time >= 100 && time <= 105) {
400                 setKeyRange(9);
401             } else if (time >= 106 && time <= 109) {
402                 setKeyRange(-1);
403             } else if (time >= 110 && time <= 115) {
404                 setKeyRange(9);
405             } else if (time >= 116 && time <= 119) {
406                 setKeyRange(-1);
407             } else if (time >= 120 && time <= 125) {
408                 setKeyRange(9);
409             } else if (time >= 126) {
410                 setKeyRange(-1);
411             }
412         }
413     }
414 
415     // Returns the time already entered in decimal representation. if time is H1 H2 : M1 M2
416     // the value retured is H1*1000+H2*100+M1*10+M2
getEnteredTime()417     private int getEnteredTime() {
418         return  mInput[3] * 1000 + mInput[2] * 100 + mInput[1] * 10 + mInput[0];
419     }
420 
421     // enables a range of numeric keys from zero to maxKey. The rest of the keys will be disabled
setKeyRange(int maxKey)422     private void setKeyRange(int maxKey) {
423         for (int i = 0; i < mNumbers.length; i++) {
424             mNumbers[i].setEnabled(i <= maxKey);
425         }
426     }
427 
updateLeftRightButtons()428     private void updateLeftRightButtons() {
429         int time = getEnteredTime();
430         if (mIs24HoursMode) {
431             boolean enable = canAddDigits();
432             mLeft.setEnabled(enable);
433             mRight.setEnabled(enable);
434         } else {
435             // You can use the AM/PM if time entered is 0 to 12 or it is 3 digits or more
436             if ((time > 12 && time < 100) || time == 0 || mAmPmState != AMPM_NOT_SELECTED) {
437                 mLeft.setEnabled(false);
438                 mRight.setEnabled(false);
439             } else {
440                 mLeft.setEnabled(true);
441                 mRight.setEnabled(true);
442             }
443         }
444     }
445 
446     // Enable/disable the set key
enableSetButton()447     private void enableSetButton() {
448         if (mSetButton == null) {
449             return;
450         }
451 
452         // Nothing entered - disable
453         if (mInputPointer == -1) {
454             mSetButton.setEnabled(false);
455             return;
456         }
457         // If the user entered 3 digits or more but not 060 to 095
458         // it is a legal time and the set key should be enabled.
459         if (mIs24HoursMode) {
460             int time = getEnteredTime();
461             mSetButton.setEnabled(mInputPointer >= 2 && (time < 60 || time > 95));
462         } else {
463             // If AM/PM mode , enable the set button if AM/PM was selected
464             mSetButton.setEnabled(mAmPmState != AMPM_NOT_SELECTED);
465         }
466     }
467 
setSetButton(Button b)468     public void setSetButton(Button b) {
469         mSetButton = b;
470         enableSetButton();
471     }
472 
getHours()473     public int getHours() {
474         int hours = mInput[3] * 10 + mInput[2];
475         if (hours == 12) {
476             switch (mAmPmState) {
477                 case PM_SELECTED:
478                     return 12;
479                 case AM_SELECTED:
480                     return 0;
481                 case HOURS24_MODE:
482                     return hours;
483                 default:
484                     break;
485             }
486         }
487         return hours + (mAmPmState == PM_SELECTED ? 12 : 0);
488     }
getMinutes()489     public int getMinutes() {
490         return mInput[1] * 10 + mInput[0];
491     }
492 
493     @Override
onSaveInstanceState()494     public Parcelable onSaveInstanceState () {
495         final Parcelable parcel = super.onSaveInstanceState();
496         final SavedState state = new SavedState(parcel);
497         state.mInput = mInput;
498         state.mAmPmState = mAmPmState;
499         state.mInputPointer = mInputPointer;
500         return state;
501     }
502 
503     @Override
onRestoreInstanceState(Parcelable state)504     protected void onRestoreInstanceState (Parcelable state) {
505         if (!(state instanceof SavedState)) {
506             super.onRestoreInstanceState(state);
507             return;
508         }
509 
510         final SavedState savedState = (SavedState) state;
511         super.onRestoreInstanceState(savedState.getSuperState());
512 
513         mInputPointer = savedState.mInputPointer;
514         mInput = savedState.mInput;
515         if (mInput == null) {
516             mInput = new int[mInputSize];
517             mInputPointer = -1;
518         }
519         mAmPmState = savedState.mAmPmState;
520         updateKeypad();
521     }
522 
523     private static class SavedState extends BaseSavedState {
524         int mInputPointer;
525         int[] mInput;
526         int mAmPmState;
527 
SavedState(Parcelable superState)528         public SavedState(Parcelable superState) {
529             super(superState);
530         }
531 
SavedState(Parcel in)532         private SavedState(Parcel in) {
533             super(in);
534             mInputPointer = in.readInt();
535             in.readIntArray(mInput);
536             mAmPmState = in.readInt();
537         }
538 
539         @Override
writeToParcel(Parcel dest, int flags)540         public void writeToParcel(Parcel dest, int flags) {
541             super.writeToParcel(dest, flags);
542             dest.writeInt(mInputPointer);
543             dest.writeIntArray(mInput);
544             dest.writeInt(mAmPmState);
545         }
546 
547         public static final Parcelable.Creator<SavedState> CREATOR
548                 = new Parcelable.Creator<SavedState>() {
549             public SavedState createFromParcel(Parcel in) {
550                 return new SavedState(in);
551             }
552 
553             public SavedState[] newArray(int size) {
554                 return new SavedState[size];
555             }
556         };
557     }
558 }
559