Home | History | Annotate | Download | only in picker
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 package org.chromium.ui.picker;
      6 
      7 import android.app.AlertDialog;
      8 import android.content.Context;
      9 import android.content.DialogInterface;
     10 import android.content.DialogInterface.OnClickListener;
     11 import android.view.LayoutInflater;
     12 import android.view.View;
     13 import android.widget.NumberPicker;
     14 
     15 import org.chromium.ui.R;
     16 
     17 import java.util.ArrayList;
     18 
     19 /**
     20  * A time picker dialog with upto 5 number pickers left to right:
     21  *  hour, minute, second, milli, AM/PM.
     22  *
     23  * If is24hourFormat is true then AM/PM picker is not displayed and
     24  * hour range is 0..23. Otherwise hour range is 1..12.
     25  * The milli picker is not displayed if step >= SECOND_IN_MILLIS
     26  * The second picker is not displayed if step >= MINUTE_IN_MILLIS.
     27  */
     28 public class MultiFieldTimePickerDialog
     29         extends AlertDialog implements OnClickListener {
     30 
     31     private final NumberPicker mHourSpinner;
     32     private final NumberPicker mMinuteSpinner;
     33     private final NumberPicker mSecSpinner;
     34     private final NumberPicker mMilliSpinner;
     35     private final NumberPicker mAmPmSpinner;
     36     private final OnMultiFieldTimeSetListener mListener;
     37     private final int mStep;
     38     private final int mBaseMilli;
     39     private final boolean mIs24hourFormat;
     40 
     41     public interface OnMultiFieldTimeSetListener {
     42         void onTimeSet(int hourOfDay, int minute, int second, int milli);
     43     }
     44 
     45     private static final int SECOND_IN_MILLIS = 1000;
     46     private static final int MINUTE_IN_MILLIS = 60 * SECOND_IN_MILLIS;
     47     private static final int HOUR_IN_MILLIS = 60 * MINUTE_IN_MILLIS;
     48 
     49     public MultiFieldTimePickerDialog(
     50             Context context,
     51             int theme,
     52             int hour, int minute, int second, int milli,
     53             int min, int max, int step, boolean is24hourFormat,
     54             OnMultiFieldTimeSetListener listener) {
     55         super(context, theme);
     56         mListener = listener;
     57         mStep = step;
     58         mIs24hourFormat = is24hourFormat;
     59 
     60         if (min >= max) {
     61             min = 0;
     62             max = 24 * HOUR_IN_MILLIS - 1;
     63         }
     64         if (step < 0 || step >= 24 * HOUR_IN_MILLIS) {
     65             step = MINUTE_IN_MILLIS;
     66         }
     67 
     68         LayoutInflater inflater =
     69                 (LayoutInflater) context.getSystemService(
     70                         Context.LAYOUT_INFLATER_SERVICE);
     71         View view = inflater.inflate(R.layout.multi_field_time_picker_dialog, null);
     72         setView(view);
     73 
     74         mHourSpinner = (NumberPicker) view.findViewById(R.id.hour);
     75         mMinuteSpinner = (NumberPicker) view.findViewById(R.id.minute);
     76         mSecSpinner = (NumberPicker) view.findViewById(R.id.second);
     77         mMilliSpinner = (NumberPicker) view.findViewById(R.id.milli);
     78         mAmPmSpinner = (NumberPicker) view.findViewById(R.id.ampm);
     79 
     80         int minHour = min / HOUR_IN_MILLIS;
     81         int maxHour = max / HOUR_IN_MILLIS;
     82         min -= minHour * HOUR_IN_MILLIS;
     83         max -= maxHour * HOUR_IN_MILLIS;
     84 
     85         if (minHour == maxHour) {
     86             mHourSpinner.setEnabled(false);
     87             hour = minHour;
     88         }
     89 
     90         if (is24hourFormat) {
     91             mAmPmSpinner.setVisibility(View.GONE);
     92         } else {
     93             int minAmPm = minHour / 12;
     94             int maxAmPm = maxHour / 12;
     95             int amPm = hour / 12;
     96             mAmPmSpinner.setMinValue(minAmPm);
     97             mAmPmSpinner.setMaxValue(maxAmPm);
     98             mAmPmSpinner.setDisplayedValues(new String[] {
     99                     context.getString(R.string.time_picker_dialog_am),
    100                     context.getString(R.string.time_picker_dialog_pm)
    101             });
    102 
    103             hour %= 12;
    104             if (hour == 0) {
    105                 hour = 12;
    106             }
    107             if (minAmPm == maxAmPm) {
    108                 mAmPmSpinner.setEnabled(false);
    109                 amPm = minAmPm;
    110 
    111                 minHour %= 12;
    112                 maxHour %= 12;
    113                 if (minHour == 0 && maxHour == 0) {
    114                     minHour = 12;
    115                     maxHour = 12;
    116                 } else if (minHour == 0) {
    117                     minHour = maxHour;
    118                     maxHour = 12;
    119                 } else if (maxHour == 0) {
    120                     maxHour = 12;
    121                 }
    122             } else {
    123                 minHour = 1;
    124                 maxHour = 12;
    125             }
    126             mAmPmSpinner.setValue(amPm);
    127         }
    128 
    129         if (minHour == maxHour) {
    130             mHourSpinner.setEnabled(false);
    131         }
    132         mHourSpinner.setMinValue(minHour);
    133         mHourSpinner.setMaxValue(maxHour);
    134         mHourSpinner.setValue(hour);
    135 
    136         NumberFormatter twoDigitPaddingFormatter = new NumberFormatter("%02d");
    137 
    138         int minMinute = min / MINUTE_IN_MILLIS;
    139         int maxMinute = max / MINUTE_IN_MILLIS;
    140         min -= minMinute * MINUTE_IN_MILLIS;
    141         max -= maxMinute * MINUTE_IN_MILLIS;
    142 
    143         if (minHour == maxHour) {
    144             mMinuteSpinner.setMinValue(minMinute);
    145             mMinuteSpinner.setMaxValue(maxMinute);
    146             if (minMinute == maxMinute) {
    147                 // Set this otherwise the box is empty until you stroke it.
    148                 mMinuteSpinner.setDisplayedValues(
    149                     new String[] { twoDigitPaddingFormatter.format(minMinute) });
    150                 mMinuteSpinner.setEnabled(false);
    151                 minute = minMinute;
    152             }
    153         } else {
    154             mMinuteSpinner.setMinValue(0);
    155             mMinuteSpinner.setMaxValue(59);
    156         }
    157 
    158         if (step >= HOUR_IN_MILLIS) {
    159             mMinuteSpinner.setEnabled(false);
    160         }
    161 
    162         mMinuteSpinner.setValue(minute);
    163         mMinuteSpinner.setFormatter(twoDigitPaddingFormatter);
    164 
    165         if (step >= MINUTE_IN_MILLIS) {
    166             // Remove the ':' in front of the second spinner as well.
    167             view.findViewById(R.id.second_colon).setVisibility(View.GONE);
    168             mSecSpinner.setVisibility(View.GONE);
    169         }
    170 
    171         int minSecond = min / SECOND_IN_MILLIS;
    172         int maxSecond = max / SECOND_IN_MILLIS;
    173         min -= minSecond * SECOND_IN_MILLIS;
    174         max -= maxSecond * SECOND_IN_MILLIS;
    175 
    176         if (minHour == maxHour && minMinute == maxMinute) {
    177             mSecSpinner.setMinValue(minSecond);
    178             mSecSpinner.setMaxValue(maxSecond);
    179             if (minSecond == maxSecond) {
    180                 // Set this otherwise the box is empty until you stroke it.
    181                 mSecSpinner.setDisplayedValues(
    182                     new String[] { twoDigitPaddingFormatter.format(minSecond) });
    183                 mSecSpinner.setEnabled(false);
    184                 second = minSecond;
    185             }
    186         } else {
    187             mSecSpinner.setMinValue(0);
    188             mSecSpinner.setMaxValue(59);
    189         }
    190 
    191         mSecSpinner.setValue(second);
    192         mSecSpinner.setFormatter(twoDigitPaddingFormatter);
    193 
    194         if (step >= SECOND_IN_MILLIS) {
    195             // Remove the '.' in front of the milli spinner as well.
    196             view.findViewById(R.id.second_dot).setVisibility(View.GONE);
    197             mMilliSpinner.setVisibility(View.GONE);
    198         }
    199 
    200         // Round to the nearest step.
    201         milli = ((milli + step / 2) / step) * step;
    202         if (step == 1 || step == 10 || step == 100) {
    203             if (minHour == maxHour && minMinute == maxMinute &&
    204                 minSecond == maxSecond) {
    205                 mMilliSpinner.setMinValue(min / step);
    206                 mMilliSpinner.setMaxValue(max / step);
    207 
    208                 if (min == max) {
    209                     mMilliSpinner.setEnabled(false);
    210                     milli = min;
    211                 }
    212             } else {
    213                 mMilliSpinner.setMinValue(0);
    214                 mMilliSpinner.setMaxValue(999 / step);
    215             }
    216 
    217             if (step == 1) {
    218                 mMilliSpinner.setFormatter(new NumberFormatter("%03d"));
    219             } else if (step == 10) {
    220                 mMilliSpinner.setFormatter(new NumberFormatter("%02d"));
    221             } else if (step == 100) {
    222                 mMilliSpinner.setFormatter(new NumberFormatter("%d"));
    223             }
    224             mMilliSpinner.setValue(milli / step);
    225             mBaseMilli = 0;
    226         } else if (step < SECOND_IN_MILLIS) {
    227             // Non-decimal step value.
    228             ArrayList<String> strValue = new ArrayList<String>();
    229             for (int i = min; i < max; i += step) {
    230                 strValue.add(String.format("%03d", i));
    231             }
    232             mMilliSpinner.setMinValue(0);
    233             mMilliSpinner.setMaxValue(strValue.size() - 1);
    234             mMilliSpinner.setValue((milli - min) / step);
    235             mMilliSpinner.setDisplayedValues(
    236                 strValue.toArray(new String[strValue.size()]));
    237             mBaseMilli = min;
    238         } else {
    239             mBaseMilli = 0;
    240         }
    241     }
    242 
    243     @Override
    244     public void onClick(DialogInterface dialog, int which) {
    245         notifyDateSet();
    246     }
    247 
    248     private void notifyDateSet() {
    249         int hour = mHourSpinner.getValue();
    250         int minute = mMinuteSpinner.getValue();
    251         int sec = mSecSpinner.getValue();
    252         int milli = mMilliSpinner.getValue() * mStep + mBaseMilli;
    253         if (!mIs24hourFormat) {
    254             int ampm = mAmPmSpinner.getValue();
    255             if (hour == 12) {
    256                 hour = 0;
    257             }
    258             hour += ampm * 12;
    259         }
    260         mListener.onTimeSet(hour, minute, sec, milli);
    261     }
    262 
    263     private static class NumberFormatter implements NumberPicker.Formatter {
    264         private final String mFormat;
    265 
    266         NumberFormatter(String format) {
    267             mFormat = format;
    268         }
    269 
    270         @Override
    271         public String format(int value) {
    272             return String.format(mFormat, value);
    273         }
    274     }
    275 }
    276