/* * 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 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 com.android.internal.R; import com.android.internal.widget.NumberPicker; 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}. */ @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 Button mAmPmButton; private final String mAmText; private final String mPmText; // 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(); } }); // 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 mAmPmButton = (Button) findViewById(R.id.amPm); // 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)); mIsAm = (mCurrentHour < 12); /* Get the localized am/pm strings and use them in the spinner */ DateFormatSymbols dfs = new DateFormatSymbols(); String[] dfsAmPm = dfs.getAmPmStrings(); mAmText = dfsAmPm[Calendar.AM]; mPmText = dfsAmPm[Calendar.PM]; mAmPmButton.setText(mIsAm ? mAmText : mPmText); mAmPmButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { 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; mAmPmButton.setText(mIsAm ? mAmText : mPmText); onTimeChanged(); } }); if (!isEnabled()) { setEnabled(false); } } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); mMinutePicker.setEnabled(enabled); mHourPicker.setEnabled(enabled); mAmPmButton.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; mAmPmButton.setText(mIsAm ? mAmText : mPmText); onTimeChanged(); } private void configurePickerRanges() { if (mIs24HourView) { mHourPicker.setRange(0, 23); mHourPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); mAmPmButton.setVisibility(View.GONE); } else { mHourPicker.setRange(1, 12); mHourPicker.setFormatter(null); mAmPmButton.setVisibility(View.VISIBLE); } } private void onTimeChanged() { mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute()); } /** * Set the state of the spinners appropriate to the current minute. */ private void updateMinuteDisplay() { mMinutePicker.setCurrent(mCurrentMinute); mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute()); } }