19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.widget;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.annotation.Widget;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
21f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganovimport android.content.res.Configuration;
224243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganovimport android.content.res.TypedArray;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable;
258a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganovimport android.text.format.DateUtils;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.LayoutInflater;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View;
298a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
308a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo;
31a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganovimport android.view.inputmethod.EditorInfo;
326304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganovimport android.view.inputmethod.InputMethodManager;
33cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganovimport android.widget.NumberPicker.OnValueChangeListener;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganovimport com.android.internal.R;
36a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.text.DateFormatSymbols;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Calendar;
39f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganovimport java.util.Locale;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
424243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov * A view for selecting the time of day, in either 24 hour or AM/PM mode. The
434243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov * hour, each minute digit, and AM/PM (if applicable) can be conrolled by
444243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov * vertical spinners. The hour can be entered by keyboard input. Entering in two
454243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov * digit hours can be accomplished by hitting two digits within a timeout of
464243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov * about a second (e.g. '1' then '2' to select 12). The minutes can be entered
474243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov * by entering single digits. Under AM/PM mode, the user can hit 'a', 'A", 'p'
484243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov * or 'P' to pick. For a dialog using this view, see
494243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov * {@link android.app.TimePickerDialog}.
504243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov *<p>
514c359b76f9a030f92a302ba74a528faa170bad4eScott Main * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
524c359b76f9a030f92a302ba74a528faa170bad4eScott Main * guide.
534243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov * </p>
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project@Widget
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class TimePicker extends FrameLayout {
57206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov
5825f84f323c607bbd9133432fd789ba29b2dcd4d4Svetoslav Ganov    private static final boolean DEFAULT_ENABLED_STATE = true;
5925f84f323c607bbd9133432fd789ba29b2dcd4d4Svetoslav Ganov
604243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov    private static final int HOURS_IN_HALF_DAY = 12;
614243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
634243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov     * A no-op callback used in the constructor to avoid null checks later in
644243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov     * the code.
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final OnTimeChangedListener NO_OP_CHANGE_LISTENER = new OnTimeChangedListener() {
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
704243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // state
724243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov    private boolean mIs24HourView;
734243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mIsAm;
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ui components
77e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final NumberPicker mHourSpinner;
784243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov
79e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final NumberPicker mMinuteSpinner;
804243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov
81e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov    private final NumberPicker mAmPmSpinner;
824243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov
836304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov    private final EditText mHourSpinnerInput;
846304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov
856304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov    private final EditText mMinuteSpinnerInput;
866304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov
876304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov    private final EditText mAmPmSpinnerInput;
886304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov
89206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov    private final TextView mDivider;
90206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov
914243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov    // Note that the legacy implementation of the TimePicker is
924243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov    // using a button for toggling between AM/PM while the new
934243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov    // version uses a NumberPicker spinner. Therefore the code
944243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov    // accommodates these two cases to be backwards compatible.
954243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov    private final Button mAmPmButton;
964243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov
97206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov    private final String[] mAmPmStrings;
98206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov
9925f84f323c607bbd9133432fd789ba29b2dcd4d4Svetoslav Ganov    private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
10051c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // callbacks
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private OnTimeChangedListener mOnTimeChangedListener;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1048a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov    private Calendar mTempCalendar;
1058a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov
106f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private Locale mCurrentLocale;
107f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The callback interface used to indicate the time has been adjusted.
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public interface OnTimeChangedListener {
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param view The view associated with this listener.
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param hourOfDay The current hour.
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param minute The current minute.
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void onTimeChanged(TimePicker view, int hourOfDay, int minute);
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public TimePicker(Context context) {
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(context, null);
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1244243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public TimePicker(Context context, AttributeSet attrs) {
1264243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        this(context, attrs, R.attr.timePickerStyle);
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public TimePicker(Context context, AttributeSet attrs, int defStyle) {
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super(context, attrs, defStyle);
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
132f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        // initialization based on locale
133f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        setCurrentLocale(Locale.getDefault());
134f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
1354243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        // process style attributes
1364243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        TypedArray attributesArray = context.obtainStyledAttributes(
1374243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                attrs, R.styleable.TimePicker, defStyle, 0);
1384243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        int layoutResourceId = attributesArray.getResourceId(
13953b948d3aec62e886bd10da664a07bdaab916b48Svetoslav Ganov                R.styleable.TimePicker_internalLayout, R.layout.time_picker);
1404243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        attributesArray.recycle();
1414243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov
1424243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        LayoutInflater inflater = (LayoutInflater) context.getSystemService(
1434243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                Context.LAYOUT_INFLATER_SERVICE);
1444243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        inflater.inflate(layoutResourceId, this, true);
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // hour
147e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mHourSpinner = (NumberPicker) findViewById(R.id.hour);
148cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov        mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
149e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
1506304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                updateInputState();
1514243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                if (!is24HourView()) {
152be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov                    if ((oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY)
153be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov                            || (oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1)) {
1544243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                        mIsAm = !mIsAm;
1554243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                        updateAmPmControl();
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                onTimeChanged();
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        });
1616304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input);
1626304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1644243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        // divider (only for the new widget style)
165206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov        mDivider = (TextView) findViewById(R.id.divider);
1664243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        if (mDivider != null) {
1674243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            mDivider.setText(R.string.time_picker_separator);
1684243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        }
169206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov
1704243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        // minute
171e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMinuteSpinner = (NumberPicker) findViewById(R.id.minute);
172e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMinuteSpinner.setMinValue(0);
173e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMinuteSpinner.setMaxValue(59);
174e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMinuteSpinner.setOnLongPressUpdateInterval(100);
175d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio        mMinuteSpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
176cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov        mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
177e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
1786304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                updateInputState();
1794243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                int minValue = mMinuteSpinner.getMinValue();
1804243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                int maxValue = mMinuteSpinner.getMaxValue();
1814243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                if (oldVal == maxValue && newVal == minValue) {
182be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov                    int newHour = mHourSpinner.getValue() + 1;
183be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov                    if (!is24HourView() && newHour == HOURS_IN_HALF_DAY) {
1844243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                        mIsAm = !mIsAm;
1854243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                        updateAmPmControl();
186206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov                    }
187be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov                    mHourSpinner.setValue(newHour);
1884243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                } else if (oldVal == minValue && newVal == maxValue) {
189be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov                    int newHour = mHourSpinner.getValue() - 1;
190be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov                    if (!is24HourView() && newHour == HOURS_IN_HALF_DAY - 1) {
1914243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                        mIsAm = !mIsAm;
1924243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                        updateAmPmControl();
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
194be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov                    mHourSpinner.setValue(newHour);
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                onTimeChanged();
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        });
1996304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input);
2006304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
201206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov
202206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov        /* Get the localized am/pm strings and use them in the spinner */
203206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov        mAmPmStrings = new DateFormatSymbols().getAmPmStrings();
204206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov
2054243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        // am/pm
2064243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        View amPmView = findViewById(R.id.amPm);
2074243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        if (amPmView instanceof Button) {
2084243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            mAmPmSpinner = null;
2096304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov            mAmPmSpinnerInput = null;
2104243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            mAmPmButton = (Button) amPmView;
2114243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            mAmPmButton.setOnClickListener(new OnClickListener() {
2124243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                public void onClick(View button) {
2134243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                    button.requestFocus();
2144243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                    mIsAm = !mIsAm;
2154243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                    updateAmPmControl();
216f821ce7522ad99dc30e59e0266165f5eba79b1e2SeongJae Park                    onTimeChanged();
2174243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                }
2184243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            });
2194243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        } else {
2204243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            mAmPmButton = null;
2214243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            mAmPmSpinner = (NumberPicker) amPmView;
2224243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            mAmPmSpinner.setMinValue(0);
2234243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            mAmPmSpinner.setMaxValue(1);
2244243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            mAmPmSpinner.setDisplayedValues(mAmPmStrings);
225cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov            mAmPmSpinner.setOnValueChangedListener(new OnValueChangeListener() {
2264243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
2276304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                    updateInputState();
2284243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                    picker.requestFocus();
2294243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                    mIsAm = !mIsAm;
2304243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                    updateAmPmControl();
231f821ce7522ad99dc30e59e0266165f5eba79b1e2SeongJae Park                    onTimeChanged();
2324243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                }
2334243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            });
2346304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov            mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input);
2356304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov            mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE);
2364243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        }
2374243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov
2384243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        // update controls to initial state
2394243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        updateHourControl();
2404243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        updateAmPmControl();
241206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov
242206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov        setOnTimeChangedListener(NO_OP_CHANGE_LISTENER);
243206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov
2444243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        // set to current time
2458a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        setCurrentHour(mTempCalendar.get(Calendar.HOUR_OF_DAY));
2468a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        setCurrentMinute(mTempCalendar.get(Calendar.MINUTE));
247206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!isEnabled()) {
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setEnabled(false);
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2513fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov
2523fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        // set the content descriptions
2532cdedffcfa5594f9d516fa235d5edf4d4f92c21dSvetoslav Ganov        setContentDescriptions();
2544213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov
2554213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov        // If not explicitly specified this view is important for accessibility.
2564213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov        if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
2574213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
2584213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov        }
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
26050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setEnabled(boolean enabled) {
26351c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        if (mIsEnabled == enabled) {
26451c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov            return;
26551c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        }
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.setEnabled(enabled);
267e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mMinuteSpinner.setEnabled(enabled);
2684243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        if (mDivider != null) {
2694243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            mDivider.setEnabled(enabled);
2704243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        }
271e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        mHourSpinner.setEnabled(enabled);
2724243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        if (mAmPmSpinner != null) {
2734243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            mAmPmSpinner.setEnabled(enabled);
2744243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        } else {
2754243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            mAmPmButton.setEnabled(enabled);
2764243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        }
27751c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        mIsEnabled = enabled;
27851c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov    }
27951c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov
28051c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov    @Override
28151c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov    public boolean isEnabled() {
28251c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov        return mIsEnabled;
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
285f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    @Override
286f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    protected void onConfigurationChanged(Configuration newConfig) {
287f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        super.onConfigurationChanged(newConfig);
288f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        setCurrentLocale(newConfig.locale);
289f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    }
290f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
291f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    /**
292f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     * Sets the current locale.
293f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     *
294f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     * @param locale The current locale.
295f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov     */
296f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    private void setCurrentLocale(Locale locale) {
297f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        if (locale.equals(mCurrentLocale)) {
298f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov            return;
299f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        }
300f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mCurrentLocale = locale;
301f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov        mTempCalendar = Calendar.getInstance(locale);
302f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov    }
303f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Used to save / restore state of time picker
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static class SavedState extends BaseSavedState {
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final int mHour;
3104243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final int mMinute;
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private SavedState(Parcelable superState, int hour, int minute) {
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(superState);
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHour = hour;
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMinute = minute;
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3184243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private SavedState(Parcel in) {
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(in);
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHour = in.readInt();
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMinute = in.readInt();
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getHour() {
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mHour;
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getMinute() {
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mMinute;
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void writeToParcel(Parcel dest, int flags) {
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.writeToParcel(dest, flags);
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.writeInt(mHour);
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.writeInt(mMinute);
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3406304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        @SuppressWarnings({"unused", "hiding"})
3414243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public SavedState createFromParcel(Parcel in) {
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return new SavedState(in);
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public SavedState[] newArray(int size) {
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return new SavedState[size];
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        };
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected Parcelable onSaveInstanceState() {
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Parcelable superState = super.onSaveInstanceState();
3554243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        return new SavedState(superState, getCurrentHour(), getCurrentMinute());
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onRestoreInstanceState(Parcelable state) {
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SavedState ss = (SavedState) state;
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onRestoreInstanceState(ss.getSuperState());
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setCurrentHour(ss.getHour());
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setCurrentMinute(ss.getMinute());
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the callback that indicates the time has been adjusted by the user.
3684243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov     *
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param onTimeChangedListener the callback, should not be null.
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) {
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mOnTimeChangedListener = onTimeChangedListener;
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3764243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov     * @return The current hour in the range (0-23).
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Integer getCurrentHour() {
3794243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        int currentHour = mHourSpinner.getValue();
380be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov        if (is24HourView()) {
3814243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            return currentHour;
382be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov        } else if (mIsAm) {
383be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov            return currentHour % HOURS_IN_HALF_DAY;
3844243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        } else {
385be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov            return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY;
3864243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        }
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the current hour.
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setCurrentHour(Integer currentHour) {
3934243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        // why was Integer used in the first place?
3944243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        if (currentHour == null || currentHour == getCurrentHour()) {
3954243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            return;
3964243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        }
3974243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        if (!is24HourView()) {
3984243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            // convert [0,23] ordinal to wall clock display
399be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov            if (currentHour >= HOURS_IN_HALF_DAY) {
4004243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                mIsAm = false;
401be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov                if (currentHour > HOURS_IN_HALF_DAY) {
402be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov                    currentHour = currentHour - HOURS_IN_HALF_DAY;
403be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov                }
4044243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            } else {
405be17a7f269479ed91b6fe8a80966d4605c805a0aSvetoslav Ganov                mIsAm = true;
4064243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                if (currentHour == 0) {
4074243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                    currentHour = HOURS_IN_HALF_DAY;
4084243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                }
4094243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            }
4104243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            updateAmPmControl();
4114243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        }
4124243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        mHourSpinner.setValue(currentHour);
4134243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        onTimeChanged();
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set whether in 24 hour or AM/PM mode.
4184243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov     *
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param is24HourView True = 24 hour mode. False = AM/PM.
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setIs24HourView(Boolean is24HourView) {
4224243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        if (mIs24HourView == is24HourView) {
4234243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            return;
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4254243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        mIs24HourView = is24HourView;
4264243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        // cache the current hour since spinner range changes
4274243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        int currentHour = getCurrentHour();
4284243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        updateHourControl();
4294243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        // set value after spinner range is updated
4304243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        setCurrentHour(currentHour);
4314243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        updateAmPmControl();
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if this is in 24 hour view else false.
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean is24HourView() {
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mIs24HourView;
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4404243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The current minute.
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Integer getCurrentMinute() {
4454243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        return mMinuteSpinner.getValue();
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the current minute (0-59).
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setCurrentMinute(Integer currentMinute) {
4524243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        if (currentMinute == getCurrentMinute()) {
4534243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            return;
4544243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        }
4554243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        mMinuteSpinner.setValue(currentMinute);
4564243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        onTimeChanged();
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getBaseline() {
461e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov        return mHourSpinner.getBaseline();
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4648a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov    @Override
4653fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
4663fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        onPopulateAccessibilityEvent(event);
4673fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        return true;
4683fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov    }
4693fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov
4703fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov    @Override
471736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
472736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov        super.onPopulateAccessibilityEvent(event);
473736c2756bf3c14ae9fef7255c119057f7a2be1edSvetoslav Ganov
4748a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        int flags = DateUtils.FORMAT_SHOW_TIME;
4758a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        if (mIs24HourView) {
4768a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov            flags |= DateUtils.FORMAT_24HOUR;
4778a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        } else {
4788a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov            flags |= DateUtils.FORMAT_12HOUR;
4798a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        }
4808a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        mTempCalendar.set(Calendar.HOUR_OF_DAY, getCurrentHour());
4818a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        mTempCalendar.set(Calendar.MINUTE, getCurrentMinute());
4828a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        String selectedDateUtterance = DateUtils.formatDateTime(mContext,
4838a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov                mTempCalendar.getTimeInMillis(), flags);
4848a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        event.getText().add(selectedDateUtterance);
4858a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov    }
4868a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov
4878a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
4888a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
4898a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityEvent(event);
4908a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        event.setClassName(TimePicker.class.getName());
4918a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
4928a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
4938a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    @Override
4948a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
4958a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        super.onInitializeAccessibilityNodeInfo(info);
4968a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov        info.setClassName(TimePicker.class.getName());
4978a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    }
4988a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov
4994243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov    private void updateHourControl() {
5004243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        if (is24HourView()) {
501e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mHourSpinner.setMinValue(0);
502e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mHourSpinner.setMaxValue(23);
503d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio            mHourSpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
505e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mHourSpinner.setMinValue(1);
506e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mHourSpinner.setMaxValue(12);
507e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov            mHourSpinner.setFormatter(null);
5084243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        }
5094243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov    }
5104243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov
5114243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov    private void updateAmPmControl() {
5124243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        if (is24HourView()) {
5134243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            if (mAmPmSpinner != null) {
5144243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                mAmPmSpinner.setVisibility(View.GONE);
5154243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            } else {
5164243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                mAmPmButton.setVisibility(View.GONE);
5174243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            }
5184243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov        } else {
5194243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            int index = mIsAm ? Calendar.AM : Calendar.PM;
5204243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            if (mAmPmSpinner != null) {
5214243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                mAmPmSpinner.setValue(index);
5224243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                mAmPmSpinner.setVisibility(View.VISIBLE);
5234243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            } else {
5244243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                mAmPmButton.setText(mAmPmStrings[index]);
5254243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov                mAmPmButton.setVisibility(View.VISIBLE);
5264243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov            }
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5288a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void onTimeChanged() {
5328a2a89588c3889b999a8fffa2d7c7a5c3ce25eb8Svetoslav Ganov        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
533206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov        if (mOnTimeChangedListener != null) {
534206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov            mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute());
535206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov        }
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5373fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov
5383fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov    private void setContentDescriptions() {
5393fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        // Minute
540d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        trySetContentDescription(mMinuteSpinner, R.id.increment,
541d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov                R.string.time_picker_increment_minute_button);
542d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        trySetContentDescription(mMinuteSpinner, R.id.decrement,
543d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov                R.string.time_picker_decrement_minute_button);
5443fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        // Hour
545d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        trySetContentDescription(mHourSpinner, R.id.increment,
546d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov                R.string.time_picker_increment_hour_button);
547d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        trySetContentDescription(mHourSpinner, R.id.decrement,
548d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov                R.string.time_picker_decrement_hour_button);
5493fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov        // AM/PM
55011c91328185c017e65930f137e69191ddef7e111Svetoslav Ganov        if (mAmPmSpinner != null) {
551d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov            trySetContentDescription(mAmPmSpinner, R.id.increment,
552d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov                    R.string.time_picker_increment_set_pm_button);
553d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov            trySetContentDescription(mAmPmSpinner, R.id.decrement,
554d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov                    R.string.time_picker_decrement_set_am_button);
555d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        }
556d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov    }
557d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov
558d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov    private void trySetContentDescription(View root, int viewId, int contDescResId) {
559d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        View target = root.findViewById(viewId);
560d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov        if (target != null) {
561d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov            target.setContentDescription(mContext.getString(contDescResId));
56211c91328185c017e65930f137e69191ddef7e111Svetoslav Ganov        }
5633fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov    }
5646304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov
5656304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov    private void updateInputState() {
5666304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        // Make sure that if the user changes the value and the IME is active
5676304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        // for one of the inputs if this widget, the IME is closed. If the user
5686304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        // changed the value via the IME and there is a next input the IME will
5696304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        // be shown, otherwise the user chose another means of changing the
5706304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        // value and having the IME up makes no sense.
5716304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
5726304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        if (inputMethodManager != null) {
5736304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov            if (inputMethodManager.isActive(mHourSpinnerInput)) {
5746304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                mHourSpinnerInput.clearFocus();
5756304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
5766304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov            } else if (inputMethodManager.isActive(mMinuteSpinnerInput)) {
5776304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                mMinuteSpinnerInput.clearFocus();
5786304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
5796304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov            } else if (inputMethodManager.isActive(mAmPmSpinnerInput)) {
5806304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                mAmPmSpinnerInput.clearFocus();
5816304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov                inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
5826304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov            }
5836304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov        }
5846304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov    }
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
586