| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.deskclock; |
| |
| import android.content.Context; |
| import android.content.res.Resources; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| import android.util.AttributeSet; |
| import android.view.View; |
| import android.widget.Button; |
| import android.widget.TextView; |
| |
| import java.text.DateFormatSymbols; |
| |
| |
| public class TimePicker extends TimerSetupView implements Button.OnClickListener{ |
| |
| private TextView mAmPmLabel; |
| private String[] mAmpm; |
| private final String mNoAmPmLabel; |
| private int mAmPmState; |
| private Button mSetButton; |
| private final boolean mIs24HoursMode = Alarms.get24HourMode(mContext); |
| |
| private static final int AMPM_NOT_SELECTED = 0; |
| private static final int PM_SELECTED = 1; |
| private static final int AM_SELECTED = 2; |
| private static final int HOURS24_MODE = 3; |
| |
| private static final String TIME_PICKER_SAVED_BUFFER_POINTER = |
| "timer_picker_saved_buffer_pointer"; |
| private static final String TIME_PICKER_SAVED_INPUT = "timer_picker_saved_input"; |
| private static final String TIME_PICKER_SAVED_AMPM = "timer_picker_saved_ampm"; |
| |
| public TimePicker(Context context) { |
| this(context, null); |
| } |
| |
| public TimePicker(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| mInputSize = 4; |
| mNoAmPmLabel = context.getResources().getString(R.string.time_picker_ampm_label); |
| } |
| |
| @Override |
| protected int getLayoutId() { |
| return R.layout.time_picker_view; |
| } |
| |
| @Override |
| protected void onFinishInflate() { |
| super.onFinishInflate(); |
| Resources res = mContext.getResources(); |
| mAmpm = new DateFormatSymbols().getAmPmStrings(); |
| |
| if (mIs24HoursMode) { |
| mLeft.setText(res.getString(R.string.time_picker_00_label)); |
| mRight.setText(res.getString(R.string.time_picker_30_label)); |
| } else { |
| mLeft.setText(mAmpm[0]); |
| mRight.setText(mAmpm[1]); |
| } |
| mLeft.setOnClickListener(this); |
| mRight.setOnClickListener(this); |
| mAmPmLabel = (TextView)findViewById(R.id.ampm_label); |
| mAmPmState = AMPM_NOT_SELECTED; |
| updateKeypad(); |
| } |
| |
| |
| @Override |
| public void onClick(View v) { |
| doOnClick(v); |
| } |
| |
| @Override |
| protected void doOnClick(View v) { |
| Integer val = (Integer) v.getTag(R.id.numbers_key); |
| // A number was pressed |
| if (val != null) { |
| addClickedNumber(val); |
| } else if (v == mDelete) { |
| // Pressing delete when AM or PM is selected, clears the AM/PM |
| // selection |
| if (!mIs24HoursMode && mAmPmState != AMPM_NOT_SELECTED) { |
| mAmPmState = AMPM_NOT_SELECTED; |
| } else if (mInputPointer >= 0) { |
| for (int i = 0; i < mInputPointer; i++) { |
| mInput[i] = mInput[i + 1]; |
| } |
| mInput[mInputPointer] = 0; |
| mInputPointer--; |
| } |
| } else if (v == mLeft) { |
| onLeftClicked(); |
| } else if (v == mRight) { |
| onRightClicked(); |
| } |
| updateKeypad(); |
| } |
| |
| @Override |
| public boolean onLongClick(View v) { |
| if (v == mDelete) { |
| mAmPmState = AMPM_NOT_SELECTED; |
| reset(); |
| updateKeypad(); |
| return true; |
| } |
| return false; |
| } |
| |
| private void updateKeypad() { |
| // Update state of keypad |
| // Set the correct AM/PM state |
| showAmPm(); |
| // Update the time |
| updateLeftRightButtons(); |
| updateTime(); |
| // enable/disable numeric keys according to the numbers entered already |
| updateNumericKeys(); |
| // enable/disable the "set" key |
| enableSetButton(); |
| // Update the backspace button |
| updateDeleteButton(); |
| |
| } |
| |
| // Update the time displayed in the picker: |
| // Special cases: |
| // 1. show "-" for digits not entered yet. |
| // 2. hide the hours digits when it is not relevant |
| @Override |
| protected void updateTime() { |
| // Put "-" in digits that was not entered by passing -1 |
| // Hide digit by passing -2 (for highest hours digit only); |
| |
| int hours1 = -1; |
| int time = getEnteredTime(); |
| // If the user entered 2 to 9 or 13 to 15 , there is no need for a 4th digit (AM/PM mode) |
| // If the user entered 3 to 9 or 24 to 25 , there is no need for a 4th digit (24 hours mode) |
| if (mInputPointer > -1) { |
| // Test to see if the highest digit is 2 to 9 for AM/PM or 3 to 9 for 24 hours mode |
| if (mInputPointer >= 0) { |
| int digit = mInput[mInputPointer]; |
| if ((mIs24HoursMode && digit >= 3 && digit <= 9) || |
| (!mIs24HoursMode && digit >= 2 && digit <= 9)) { |
| hours1 = -2; |
| } |
| } |
| // Test to see if the 2 highest digits are 13 to 15 for AM/PM or 24 to 25 for 24 hours |
| // mode |
| if (mInputPointer > 0 && mInputPointer < 3 && hours1 != -2) { |
| int digits = mInput[mInputPointer] * 10 + mInput[mInputPointer - 1]; |
| if ((mIs24HoursMode && digits >= 24 && digits <= 25) || |
| (!mIs24HoursMode && digits >= 13 && digits <= 15)) { |
| hours1 = -2; |
| } |
| } |
| // If we have a digit show it |
| if (mInputPointer == 3) { |
| hours1 = mInput[3]; |
| } |
| } else { |
| hours1 = -1; |
| } |
| int hours2 = (mInputPointer < 2) ? -1 : mInput[2]; |
| int minutes1 = (mInputPointer < 1) ? -1 : mInput[1]; |
| int minutes2 = (mInputPointer < 0) ? -1 : mInput[0]; |
| mEnteredTime.setTime(hours1, hours2, minutes1, minutes2, -1); |
| } |
| |
| private void showAmPm() { |
| if (!mIs24HoursMode) { |
| switch(mAmPmState) { |
| case AMPM_NOT_SELECTED: |
| mAmPmLabel.setText(mNoAmPmLabel); |
| break; |
| case AM_SELECTED: |
| mAmPmLabel.setText(mAmpm[0]); |
| break; |
| case PM_SELECTED: |
| mAmPmLabel.setText(mAmpm[1]); |
| break; |
| default: |
| break; |
| } |
| } else { |
| mAmPmLabel.setVisibility(View.INVISIBLE); |
| mAmPmState = HOURS24_MODE; |
| } |
| } |
| |
| private void addClickedNumber(int val) { |
| if (mInputPointer < mInputSize - 1) { |
| for (int i = mInputPointer; i >= 0; i--) { |
| mInput[i + 1] = mInput[i]; |
| } |
| mInputPointer++; |
| mInput[0] = val; |
| } |
| } |
| |
| // Clicking on the bottom left button will add "00" to the time |
| // In AM/PM mode is will also set the time to AM. |
| private void onLeftClicked() { |
| int time = getEnteredTime(); |
| if (!mIs24HoursMode) { |
| if (canAddDigits()) { |
| addClickedNumber(0); |
| addClickedNumber(0); |
| } |
| mAmPmState = AM_SELECTED; |
| } else if (canAddDigits()) { |
| addClickedNumber(0); |
| addClickedNumber(0); |
| } |
| } |
| |
| // Clicking on the bottom right button will add "00" to the time in AM/PM |
| // mode and "30" is 24 hours mode. |
| // In AM/PM mode is will also set the time to PM. |
| private void onRightClicked() { |
| int time = getEnteredTime(); |
| if (!mIs24HoursMode) { |
| if (canAddDigits()) { |
| addClickedNumber(0); |
| addClickedNumber(0); |
| } |
| mAmPmState = PM_SELECTED; |
| } else { |
| if (canAddDigits()) { |
| addClickedNumber(3); |
| addClickedNumber(0); |
| } |
| } |
| } |
| |
| // Checks if the user allowed to click on the left or right button that enters "00" or "30" |
| private boolean canAddDigits() { |
| int time = getEnteredTime(); |
| // For AM/PM mode , can add "00" if an hour between 1 and 12 was entered |
| if (!mIs24HoursMode) { |
| return (time >= 1 && time <= 12); |
| } |
| // For 24 hours mode , can add "00"/"30" if an hour between 0 and 23 was entered |
| return (time >= 0 && time <= 23 && mInputPointer > -1 && mInputPointer < 2); |
| } |
| |
| |
| // Enable/disable keys in the numeric key pad according to the data entered |
| private void updateNumericKeys() { |
| int time = getEnteredTime(); |
| if (mIs24HoursMode) { |
| if (mInputPointer >= 3) { |
| setKeyRange(-1); |
| } else if (time == 0) { |
| if (mInputPointer == -1 || mInputPointer == 0 || mInputPointer == 2) { |
| setKeyRange(9); |
| } else if (mInputPointer == 1) { |
| setKeyRange(5); |
| } else { |
| setKeyRange(-1); |
| } |
| } else if (time == 1) { |
| if (mInputPointer == 0 || mInputPointer == 2) { |
| setKeyRange(9); |
| } else if (mInputPointer == 1) { |
| setKeyRange(5); |
| } else { |
| setKeyRange(-1); |
| } |
| } else if (time == 2) { |
| if (mInputPointer == 2|| mInputPointer == 1) { |
| setKeyRange(9); |
| } else if (mInputPointer == 0) { |
| setKeyRange(3); |
| } else { |
| setKeyRange(-1); |
| } |
| } else if (time <= 5) { |
| setKeyRange(9); |
| } else if (time <= 9) { |
| setKeyRange(5); |
| } else if (time >= 10 && time <= 15) { |
| setKeyRange(9); |
| } else if (time >= 16 && time <= 19) { |
| setKeyRange(5); |
| } else if (time >= 20 && time <= 25) { |
| setKeyRange(9); |
| } else if (time >= 26 && time <= 29) { |
| setKeyRange(-1); |
| } else if (time >= 30 && time <= 35) { |
| setKeyRange(9); |
| } else if (time >= 36 && time <= 39) { |
| setKeyRange(-1); |
| } else if (time >= 40 && time <= 45) { |
| setKeyRange(9); |
| } else if (time >= 46 && time <= 49) { |
| setKeyRange(-1); |
| } else if (time >= 50 && time <= 55) { |
| setKeyRange(9); |
| } else if (time >= 56 && time <= 59) { |
| setKeyRange(-1); |
| } else if (time >= 60 && time <= 65) { |
| setKeyRange(9); |
| } else if (time >= 70 && time <= 75) { |
| setKeyRange(9); |
| } else if (time >= 80 && time <= 85) { |
| setKeyRange(9); |
| } else if (time >= 90 && time <= 95) { |
| setKeyRange(9); |
| } else if (time >= 100 && time <= 105) { |
| setKeyRange(9); |
| } else if (time >= 106 && time <= 109) { |
| setKeyRange(-1); |
| } else if (time >= 110 && time <= 115) { |
| setKeyRange(9); |
| } else if (time >= 116 && time <= 119) { |
| setKeyRange(-1); |
| } else if (time >= 120 && time <= 125) { |
| setKeyRange(9); |
| } else if (time >= 126 && time <= 129) { |
| setKeyRange(-1); |
| } else if (time >= 130 && time <= 135) { |
| setKeyRange(9); |
| } else if (time >= 136 && time <= 139) { |
| setKeyRange(-1); |
| } else if (time >= 140 && time <= 145) { |
| setKeyRange(9); |
| } else if (time >= 146 && time <= 149) { |
| setKeyRange(-1); |
| } else if (time >= 150 && time <= 155) { |
| setKeyRange(9); |
| } else if (time >= 156 && time <= 159) { |
| setKeyRange(-1); |
| } else if (time >= 160 && time <= 165) { |
| setKeyRange(9); |
| } else if (time >= 166 && time <= 169) { |
| setKeyRange(-1); |
| } else if (time >= 170 && time <= 175) { |
| setKeyRange(9); |
| } else if (time >= 176 && time <= 179) { |
| setKeyRange(-1); |
| } else if (time >= 180 && time <= 185) { |
| setKeyRange(9); |
| } else if (time >= 186 && time <= 189) { |
| setKeyRange(-1); |
| } else if (time >= 190 && time <= 195) { |
| setKeyRange(9); |
| } else if (time >= 196 && time <= 199) { |
| setKeyRange(-1); |
| } else if (time >= 200 && time <= 205) { |
| setKeyRange(9); |
| } else if (time >= 206 && time <= 209) { |
| setKeyRange(-1); |
| } else if (time >= 210 && time <= 215) { |
| setKeyRange(9); |
| } else if (time >= 216 && time <= 219) { |
| setKeyRange(-1); |
| } else if (time >= 220 && time <= 225) { |
| setKeyRange(9); |
| } else if (time >= 226 && time <= 229) { |
| setKeyRange(-1); |
| } else if (time >= 230 && time <= 235) { |
| setKeyRange(9); |
| } else if (time >= 236) { |
| setKeyRange(-1); |
| } |
| } else { |
| // Selecting AM/PM disabled the keypad |
| if (mAmPmState != AMPM_NOT_SELECTED) { |
| setKeyRange(-1); |
| } else if (time == 0) { |
| setKeyRange(9); |
| // If 0 was entered as the first digit in AM/PM mode, do not allow a second 0 |
| // if (mInputPointer == 0) { |
| mNumbers[0].setEnabled(false); |
| // } |
| } else if (time <= 9) { |
| setKeyRange(5); |
| } else if (time <= 95) { |
| setKeyRange(9); |
| } else if (time >= 100 && time <= 105) { |
| setKeyRange(9); |
| } else if (time >= 106 && time <= 109) { |
| setKeyRange(-1); |
| } else if (time >= 110 && time <= 115) { |
| setKeyRange(9); |
| } else if (time >= 116 && time <= 119) { |
| setKeyRange(-1); |
| } else if (time >= 120 && time <= 125) { |
| setKeyRange(9); |
| } else if (time >= 126) { |
| setKeyRange(-1); |
| } |
| } |
| } |
| |
| // Returns the time already entered in decimal representation. if time is H1 H2 : M1 M2 |
| // the value retured is H1*1000+H2*100+M1*10+M2 |
| private int getEnteredTime() { |
| return mInput[3] * 1000 + mInput[2] * 100 + mInput[1] * 10 + mInput[0]; |
| } |
| |
| // enables a range of numeric keys from zero to maxKey. The rest of the keys will be disabled |
| private void setKeyRange(int maxKey) { |
| for (int i = 0; i < mNumbers.length; i++) { |
| mNumbers[i].setEnabled(i <= maxKey); |
| } |
| } |
| |
| private void updateLeftRightButtons() { |
| int time = getEnteredTime(); |
| if (mIs24HoursMode) { |
| boolean enable = canAddDigits(); |
| mLeft.setEnabled(enable); |
| mRight.setEnabled(enable); |
| } else { |
| // You can use the AM/PM if time entered is 0 to 12 or it is 3 digits or more |
| if ((time > 12 && time < 100) || time == 0 || mAmPmState != AMPM_NOT_SELECTED) { |
| mLeft.setEnabled(false); |
| mRight.setEnabled(false); |
| } else { |
| mLeft.setEnabled(true); |
| mRight.setEnabled(true); |
| } |
| } |
| } |
| |
| // Enable/disable the set key |
| private void enableSetButton() { |
| if (mSetButton == null) { |
| return; |
| } |
| |
| // Nothing entered - disable |
| if (mInputPointer == -1) { |
| mSetButton.setEnabled(false); |
| return; |
| } |
| // If the user entered 3 digits or more but not 060 to 095 |
| // it is a legal time and the set key should be enabled. |
| if (mIs24HoursMode) { |
| int time = getEnteredTime(); |
| mSetButton.setEnabled(mInputPointer >= 2 && (time < 60 || time > 95)); |
| } else { |
| // If AM/PM mode , enable the set button if AM/PM was selected |
| mSetButton.setEnabled(mAmPmState != AMPM_NOT_SELECTED); |
| } |
| } |
| |
| public void setSetButton(Button b) { |
| mSetButton = b; |
| enableSetButton(); |
| } |
| |
| public int getHours() { |
| int hours = mInput[3] * 10 + mInput[2]; |
| if (hours == 12) { |
| switch (mAmPmState) { |
| case PM_SELECTED: |
| return 12; |
| case AM_SELECTED: |
| return 0; |
| case HOURS24_MODE: |
| return hours; |
| default: |
| break; |
| } |
| } |
| return hours + (mAmPmState == PM_SELECTED ? 12 : 0); |
| } |
| public int getMinutes() { |
| return mInput[1] * 10 + mInput[0]; |
| } |
| |
| @Override |
| public Parcelable onSaveInstanceState () { |
| final Parcelable parcel = super.onSaveInstanceState(); |
| final SavedState state = new SavedState(parcel); |
| state.mInput = mInput; |
| state.mAmPmState = mAmPmState; |
| state.mInputPointer = mInputPointer; |
| return state; |
| } |
| |
| @Override |
| protected void onRestoreInstanceState (Parcelable state) { |
| if (!(state instanceof SavedState)) { |
| super.onRestoreInstanceState(state); |
| return; |
| } |
| |
| final SavedState savedState = (SavedState) state; |
| super.onRestoreInstanceState(savedState.getSuperState()); |
| |
| mInputPointer = savedState.mInputPointer; |
| mInput = savedState.mInput; |
| if (mInput == null) { |
| mInput = new int[mInputSize]; |
| mInputPointer = -1; |
| } |
| mAmPmState = savedState.mAmPmState; |
| updateKeypad(); |
| } |
| |
| private static class SavedState extends BaseSavedState { |
| int mInputPointer; |
| int[] mInput; |
| int mAmPmState; |
| |
| public SavedState(Parcelable superState) { |
| super(superState); |
| } |
| |
| private SavedState(Parcel in) { |
| super(in); |
| mInputPointer = in.readInt(); |
| in.readIntArray(mInput); |
| mAmPmState = in.readInt(); |
| } |
| |
| @Override |
| public void writeToParcel(Parcel dest, int flags) { |
| super.writeToParcel(dest, flags); |
| dest.writeInt(mInputPointer); |
| dest.writeIntArray(mInput); |
| dest.writeInt(mAmPmState); |
| } |
| |
| public static final Parcelable.Creator<SavedState> CREATOR |
| = new Parcelable.Creator<SavedState>() { |
| public SavedState createFromParcel(Parcel in) { |
| return new SavedState(in); |
| } |
| |
| public SavedState[] newArray(int size) { |
| return new SavedState[size]; |
| } |
| }; |
| } |
| } |