blob: caed308a2be7e2be5842e1ceb299bd59cc619775 [file] [log] [blame]
/*
* 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 android.widget.NumberPicker;
import com.android.internal.R;
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());
}
}