| /* |
| * Copyright (C) 2007 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 android.widget; |
| |
| import com.android.internal.R; |
| |
| import android.annotation.Widget; |
| import android.content.Context; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| import android.util.AttributeSet; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.widget.NumberPicker.OnChangedListener; |
| |
| import java.text.DateFormatSymbols; |
| import java.util.Calendar; |
| |
| /** |
| * A view for selecting the time of day, in either 24 hour or AM/PM mode. |
| * |
| * The hour, each minute digit, and AM/PM (if applicable) can be conrolled by |
| * vertical spinners. |
| * |
| * The hour can be entered by keyboard input. Entering in two digit hours |
| * can be accomplished by hitting two digits within a timeout of about a |
| * second (e.g. '1' then '2' to select 12). |
| * |
| * The minutes can be entered by entering single digits. |
| * |
| * Under AM/PM mode, the user can hit 'a', 'A", 'p' or 'P' to pick. |
| * |
| * For a dialog using this view, see {@link android.app.TimePickerDialog}. |
| * |
| * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-timepicker.html">Time Picker |
| * tutorial</a>.</p> |
| */ |
| @Widget |
| public class TimePicker extends FrameLayout { |
| |
| /** |
| * A no-op callback used in the constructor to avoid null checks |
| * later in the code. |
| */ |
| private static final OnTimeChangedListener NO_OP_CHANGE_LISTENER = new OnTimeChangedListener() { |
| public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { |
| } |
| }; |
| |
| // state |
| private int mCurrentHour = 0; // 0-23 |
| private int mCurrentMinute = 0; // 0-59 |
| private Boolean mIs24HourView = false; |
| private boolean mIsAm; |
| |
| // ui components |
| private final NumberPicker mHourPicker; |
| private final NumberPicker mMinutePicker; |
| private final NumberPicker mAmPmPicker; |
| private final TextView mDivider; |
| |
| private final String[] mAmPmStrings; |
| |
| // callbacks |
| private OnTimeChangedListener mOnTimeChangedListener; |
| |
| /** |
| * The callback interface used to indicate the time has been adjusted. |
| */ |
| public interface OnTimeChangedListener { |
| |
| /** |
| * @param view The view associated with this listener. |
| * @param hourOfDay The current hour. |
| * @param minute The current minute. |
| */ |
| void onTimeChanged(TimePicker view, int hourOfDay, int minute); |
| } |
| |
| public TimePicker(Context context) { |
| this(context, null); |
| } |
| |
| public TimePicker(Context context, AttributeSet attrs) { |
| this(context, attrs, 0); |
| } |
| |
| public TimePicker(Context context, AttributeSet attrs, int defStyle) { |
| super(context, attrs, defStyle); |
| |
| LayoutInflater inflater = |
| (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
| inflater.inflate(R.layout.time_picker, |
| this, // we are the parent |
| true); |
| |
| // hour |
| mHourPicker = (NumberPicker) findViewById(R.id.hour); |
| mHourPicker.setOnChangeListener(new NumberPicker.OnChangedListener() { |
| public void onChanged(NumberPicker spinner, int oldVal, int newVal) { |
| mCurrentHour = newVal; |
| if (!mIs24HourView) { |
| // adjust from [1-12] to [0-11] internally, with the times |
| // written "12:xx" being the start of the half-day |
| if (mCurrentHour == 12) { |
| mCurrentHour = 0; |
| } |
| if (!mIsAm) { |
| // PM means 12 hours later than nominal |
| mCurrentHour += 12; |
| } |
| } |
| onTimeChanged(); |
| } |
| }); |
| |
| // divider |
| mDivider = (TextView) findViewById(R.id.divider); |
| mDivider.setText(R.string.time_picker_separator); |
| |
| // digits of minute |
| mMinutePicker = (NumberPicker) findViewById(R.id.minute); |
| mMinutePicker.setRange(0, 59); |
| mMinutePicker.setSpeed(100); |
| mMinutePicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); |
| mMinutePicker.setOnChangeListener(new NumberPicker.OnChangedListener() { |
| public void onChanged(NumberPicker spinner, int oldVal, int newVal) { |
| mCurrentMinute = newVal; |
| onTimeChanged(); |
| } |
| }); |
| |
| // am/pm |
| mAmPmPicker = (NumberPicker) findViewById(R.id.amPm); |
| mAmPmPicker.setOnChangeListener(new OnChangedListener() { |
| public void onChanged(NumberPicker picker, int oldVal, int newVal) { |
| picker.requestFocus(); |
| if (mIsAm) { |
| // Currently AM switching to PM |
| if (mCurrentHour < 12) { |
| mCurrentHour += 12; |
| } |
| } else { |
| // Currently PM switching to AM |
| if (mCurrentHour >= 12) { |
| mCurrentHour -= 12; |
| } |
| } |
| mIsAm = !mIsAm; |
| onTimeChanged(); |
| } |
| }); |
| |
| /* Get the localized am/pm strings and use them in the spinner */ |
| mAmPmStrings = new DateFormatSymbols().getAmPmStrings(); |
| |
| // now that the hour/minute picker objects have been initialized, set |
| // the hour range properly based on the 12/24 hour display mode. |
| configurePickerRanges(); |
| |
| // initialize to current time |
| Calendar cal = Calendar.getInstance(); |
| setOnTimeChangedListener(NO_OP_CHANGE_LISTENER); |
| |
| // by default we're not in 24 hour mode |
| setCurrentHour(cal.get(Calendar.HOUR_OF_DAY)); |
| setCurrentMinute(cal.get(Calendar.MINUTE)); |
| |
| if (!isEnabled()) { |
| setEnabled(false); |
| } |
| } |
| |
| @Override |
| public void setEnabled(boolean enabled) { |
| super.setEnabled(enabled); |
| mMinutePicker.setEnabled(enabled); |
| mHourPicker.setEnabled(enabled); |
| mAmPmPicker.setEnabled(enabled); |
| } |
| |
| /** |
| * Used to save / restore state of time picker |
| */ |
| private static class SavedState extends BaseSavedState { |
| |
| private final int mHour; |
| private final int mMinute; |
| |
| private SavedState(Parcelable superState, int hour, int minute) { |
| super(superState); |
| mHour = hour; |
| mMinute = minute; |
| } |
| |
| private SavedState(Parcel in) { |
| super(in); |
| mHour = in.readInt(); |
| mMinute = in.readInt(); |
| } |
| |
| public int getHour() { |
| return mHour; |
| } |
| |
| public int getMinute() { |
| return mMinute; |
| } |
| |
| @Override |
| public void writeToParcel(Parcel dest, int flags) { |
| super.writeToParcel(dest, flags); |
| dest.writeInt(mHour); |
| dest.writeInt(mMinute); |
| } |
| |
| public static final Parcelable.Creator<SavedState> CREATOR |
| = new Creator<SavedState>() { |
| public SavedState createFromParcel(Parcel in) { |
| return new SavedState(in); |
| } |
| |
| public SavedState[] newArray(int size) { |
| return new SavedState[size]; |
| } |
| }; |
| } |
| |
| @Override |
| protected Parcelable onSaveInstanceState() { |
| Parcelable superState = super.onSaveInstanceState(); |
| return new SavedState(superState, mCurrentHour, mCurrentMinute); |
| } |
| |
| @Override |
| protected void onRestoreInstanceState(Parcelable state) { |
| SavedState ss = (SavedState) state; |
| super.onRestoreInstanceState(ss.getSuperState()); |
| setCurrentHour(ss.getHour()); |
| setCurrentMinute(ss.getMinute()); |
| } |
| |
| /** |
| * Set the callback that indicates the time has been adjusted by the user. |
| * @param onTimeChangedListener the callback, should not be null. |
| */ |
| public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) { |
| mOnTimeChangedListener = onTimeChangedListener; |
| } |
| |
| /** |
| * @return The current hour (0-23). |
| */ |
| public Integer getCurrentHour() { |
| return mCurrentHour; |
| } |
| |
| /** |
| * Set the current hour. |
| */ |
| public void setCurrentHour(Integer currentHour) { |
| this.mCurrentHour = currentHour; |
| updateHourDisplay(); |
| } |
| |
| /** |
| * Set whether in 24 hour or AM/PM mode. |
| * @param is24HourView True = 24 hour mode. False = AM/PM. |
| */ |
| public void setIs24HourView(Boolean is24HourView) { |
| if (mIs24HourView != is24HourView) { |
| mIs24HourView = is24HourView; |
| configurePickerRanges(); |
| updateHourDisplay(); |
| } |
| } |
| |
| /** |
| * @return true if this is in 24 hour view else false. |
| */ |
| public boolean is24HourView() { |
| return mIs24HourView; |
| } |
| |
| /** |
| * @return The current minute. |
| */ |
| public Integer getCurrentMinute() { |
| return mCurrentMinute; |
| } |
| |
| /** |
| * Set the current minute (0-59). |
| */ |
| public void setCurrentMinute(Integer currentMinute) { |
| this.mCurrentMinute = currentMinute; |
| updateMinuteDisplay(); |
| } |
| |
| @Override |
| public int getBaseline() { |
| return mHourPicker.getBaseline(); |
| } |
| |
| /** |
| * Set the state of the spinners appropriate to the current hour. |
| */ |
| private void updateHourDisplay() { |
| int currentHour = mCurrentHour; |
| if (!mIs24HourView) { |
| // convert [0,23] ordinal to wall clock display |
| if (currentHour > 12) { |
| currentHour -= 12; |
| } else if (currentHour == 0) { |
| currentHour = 12; |
| } |
| } |
| mHourPicker.setCurrent(currentHour); |
| mIsAm = mCurrentHour < 12; |
| mAmPmPicker.setCurrent(mIsAm ? Calendar.AM : Calendar.PM); |
| onTimeChanged(); |
| } |
| |
| private void configurePickerRanges() { |
| if (mIs24HourView) { |
| mHourPicker.setRange(0, 23); |
| mHourPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); |
| mAmPmPicker.setVisibility(View.GONE); |
| } else { |
| mHourPicker.setRange(1, 12); |
| mHourPicker.setFormatter(null); |
| mAmPmPicker.setVisibility(View.VISIBLE); |
| mAmPmPicker.setRange(0, 1, mAmPmStrings); |
| } |
| } |
| |
| private void onTimeChanged() { |
| if (mOnTimeChangedListener != null) { |
| mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute()); |
| } |
| } |
| |
| /** |
| * Set the state of the spinners appropriate to the current minute. |
| */ |
| private void updateMinuteDisplay() { |
| mMinutePicker.setCurrent(mCurrentMinute); |
| onTimeChanged(); |
| } |
| } |