12946445b560fde5e63df17f5a2db60c8349fe532Romain Guy/* 22946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * Copyright (C) 2012 The Android Open Source Project 32946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * 42946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 52946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * you may not use this file except in compliance with the License. 62946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * You may obtain a copy of the License at 72946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * 82946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * http://www.apache.org/licenses/LICENSE-2.0 92946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * 102946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * Unless required by applicable law or agreed to in writing, software 112946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * distributed under the License is distributed on an "AS IS" BASIS, 122946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * See the License for the specific language governing permissions and 142946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * limitations under the License. 152946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 162946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 172946445b560fde5e63df17f5a2db60c8349fe532Romain Guypackage com.android.test.hwui; 182946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 192946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.annotation.Widget; 202946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.content.Context; 212946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.content.res.TypedArray; 222946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.os.Parcel; 232946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.os.Parcelable; 242946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.text.format.DateFormat; 252946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.util.AttributeSet; 262946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.util.SparseArray; 272946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.view.ContextThemeWrapper; 282946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.view.LayoutInflater; 292946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.view.View; 302946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.widget.CheckBox; 312946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.widget.CompoundButton; 322946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.widget.FrameLayout; 332946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.widget.LinearLayout; 342946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport android.widget.NumberPicker; 352946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 362946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport java.text.DateFormatSymbols; 372946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport java.text.SimpleDateFormat; 382946445b560fde5e63df17f5a2db60c8349fe532Romain Guyimport java.util.Calendar; 392946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 402946445b560fde5e63df17f5a2db60c8349fe532Romain Guy/** 412946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * A view for selecting a month / year / day based on a calendar like layout. 422946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * 432946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date Picker 442946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * tutorial</a>.</p> 452946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * 462946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * For a dialog using this view, see {@link android.app.DatePickerDialog}. 472946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 482946445b560fde5e63df17f5a2db60c8349fe532Romain Guy@Widget 492946445b560fde5e63df17f5a2db60c8349fe532Romain Guypublic class DatePicker extends FrameLayout { 502946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 512946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private static final int DEFAULT_START_YEAR = 1900; 522946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private static final int DEFAULT_END_YEAR = 2100; 532946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 542946445b560fde5e63df17f5a2db60c8349fe532Romain Guy /* UI Components */ 552946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private final CheckBox mYearToggle; 562946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private final NumberPicker mDayPicker; 572946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private final NumberPicker mMonthPicker; 582946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private final NumberPicker mYearPicker; 592946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 602946445b560fde5e63df17f5a2db60c8349fe532Romain Guy /** 612946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * How we notify users the date has changed. 622946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 632946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private OnDateChangedListener mOnDateChangedListener; 642946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 652946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private int mDay; 662946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private int mMonth; 672946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private int mYear; 682946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private boolean mYearOptional = true; 692946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private boolean mHasYear; 702946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 712946445b560fde5e63df17f5a2db60c8349fe532Romain Guy /** 722946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * The callback used to indicate the user changes the date. 732946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 742946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public interface OnDateChangedListener { 752946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 762946445b560fde5e63df17f5a2db60c8349fe532Romain Guy /** 772946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * @param view The view associated with this listener. 782946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * @param year The year that was set. 792946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * @param monthOfYear The month that was set (0-11) for compatibility 802946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * with {@link java.util.Calendar}. 812946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * @param dayOfMonth The day of the month that was set. 822946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 832946445b560fde5e63df17f5a2db60c8349fe532Romain Guy void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth); 842946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 852946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 862946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public DatePicker(Context context) { 872946445b560fde5e63df17f5a2db60c8349fe532Romain Guy this(context, null); 882946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 892946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 902946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public DatePicker(Context context, AttributeSet attrs) { 912946445b560fde5e63df17f5a2db60c8349fe532Romain Guy this(context, attrs, 0); 922946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 932946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 942946445b560fde5e63df17f5a2db60c8349fe532Romain Guy @SuppressWarnings("deprecation") 952946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public DatePicker(Context context, AttributeSet attrs, int defStyle) { 962946445b560fde5e63df17f5a2db60c8349fe532Romain Guy super(context, attrs, defStyle); 972946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 982946445b560fde5e63df17f5a2db60c8349fe532Romain Guy ContextThemeWrapper themed = new ContextThemeWrapper(context, 992946445b560fde5e63df17f5a2db60c8349fe532Romain Guy com.android.internal.R.style.Theme_Holo_Light_Dialog_Alert); 1002946445b560fde5e63df17f5a2db60c8349fe532Romain Guy LayoutInflater inflater = (LayoutInflater) themed.getSystemService( 1012946445b560fde5e63df17f5a2db60c8349fe532Romain Guy Context.LAYOUT_INFLATER_SERVICE); 1022946445b560fde5e63df17f5a2db60c8349fe532Romain Guy inflater.inflate(R.layout.date_picker, this, true); 1032946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 1042946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mDayPicker = (NumberPicker) findViewById(R.id.day); 105d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio mDayPicker.setFormatter(NumberPicker.getTwoDigitFormatter()); 1062946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mDayPicker.setOnLongPressUpdateInterval(100); 1072946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mDayPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { 1082946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public void onValueChange(NumberPicker picker, int oldVal, int newVal) { 1092946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mDay = newVal; 1102946445b560fde5e63df17f5a2db60c8349fe532Romain Guy notifyDateChanged(); 1112946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 1122946445b560fde5e63df17f5a2db60c8349fe532Romain Guy }); 1132946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonthPicker = (NumberPicker) findViewById(R.id.month); 114d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio mMonthPicker.setFormatter(NumberPicker.getTwoDigitFormatter()); 1152946445b560fde5e63df17f5a2db60c8349fe532Romain Guy DateFormatSymbols dfs = new DateFormatSymbols(); 1162946445b560fde5e63df17f5a2db60c8349fe532Romain Guy String[] months = dfs.getShortMonths(); 1172946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 1182946445b560fde5e63df17f5a2db60c8349fe532Romain Guy /* 1192946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * If the user is in a locale where the month names are numeric, 1202946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * use just the number instead of the "month" character for 1212946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * consistency with the other fields. 1222946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 1232946445b560fde5e63df17f5a2db60c8349fe532Romain Guy if (months[0].startsWith("1")) { 1242946445b560fde5e63df17f5a2db60c8349fe532Romain Guy for (int i = 0; i < months.length; i++) { 1252946445b560fde5e63df17f5a2db60c8349fe532Romain Guy months[i] = String.valueOf(i + 1); 1262946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 1272946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonthPicker.setMinValue(1); 1282946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonthPicker.setMaxValue(12); 1292946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } else { 1302946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonthPicker.setMinValue(1); 1312946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonthPicker.setMaxValue(12); 1322946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonthPicker.setDisplayedValues(months); 1332946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 1342946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 1352946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonthPicker.setOnLongPressUpdateInterval(200); 1362946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonthPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { 1372946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public void onValueChange(NumberPicker picker, int oldVal, int newVal) { 1382946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 1392946445b560fde5e63df17f5a2db60c8349fe532Romain Guy /* We display the month 1-12 but store it 0-11 so always 1402946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * subtract by one to ensure our internal state is always 0-11 1412946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 1422946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonth = newVal - 1; 1432946445b560fde5e63df17f5a2db60c8349fe532Romain Guy // Adjust max day of the month 1442946445b560fde5e63df17f5a2db60c8349fe532Romain Guy adjustMaxDay(); 1452946445b560fde5e63df17f5a2db60c8349fe532Romain Guy notifyDateChanged(); 1462946445b560fde5e63df17f5a2db60c8349fe532Romain Guy updateDaySpinner(); 1472946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 1482946445b560fde5e63df17f5a2db60c8349fe532Romain Guy }); 1492946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearPicker = (NumberPicker) findViewById(R.id.year); 1502946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearPicker.setOnLongPressUpdateInterval(100); 1512946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { 1522946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public void onValueChange(NumberPicker picker, int oldVal, int newVal) { 1532946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYear = newVal; 1542946445b560fde5e63df17f5a2db60c8349fe532Romain Guy // Adjust max day for leap years if needed 1552946445b560fde5e63df17f5a2db60c8349fe532Romain Guy adjustMaxDay(); 1562946445b560fde5e63df17f5a2db60c8349fe532Romain Guy notifyDateChanged(); 1572946445b560fde5e63df17f5a2db60c8349fe532Romain Guy updateDaySpinner(); 1582946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 1592946445b560fde5e63df17f5a2db60c8349fe532Romain Guy }); 1602946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 1612946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearToggle = (CheckBox) findViewById(R.id.yearToggle); 1622946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearToggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 1632946445b560fde5e63df17f5a2db60c8349fe532Romain Guy @Override 1642946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 1652946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mHasYear = isChecked; 1662946445b560fde5e63df17f5a2db60c8349fe532Romain Guy adjustMaxDay(); 1672946445b560fde5e63df17f5a2db60c8349fe532Romain Guy notifyDateChanged(); 1682946445b560fde5e63df17f5a2db60c8349fe532Romain Guy updateSpinners(); 1692946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 1702946445b560fde5e63df17f5a2db60c8349fe532Romain Guy }); 1712946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 1722946445b560fde5e63df17f5a2db60c8349fe532Romain Guy // attributes 1732946445b560fde5e63df17f5a2db60c8349fe532Romain Guy TypedArray a = context.obtainStyledAttributes(attrs, 1742946445b560fde5e63df17f5a2db60c8349fe532Romain Guy com.android.internal.R.styleable.DatePicker); 1752946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 1762946445b560fde5e63df17f5a2db60c8349fe532Romain Guy int mStartYear = 1772946445b560fde5e63df17f5a2db60c8349fe532Romain Guy a.getInt(com.android.internal.R.styleable.DatePicker_startYear, DEFAULT_START_YEAR); 1782946445b560fde5e63df17f5a2db60c8349fe532Romain Guy int mEndYear = 1792946445b560fde5e63df17f5a2db60c8349fe532Romain Guy a.getInt(com.android.internal.R.styleable.DatePicker_endYear, DEFAULT_END_YEAR); 1802946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearPicker.setMinValue(mStartYear); 1812946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearPicker.setMaxValue(mEndYear); 1822946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 1832946445b560fde5e63df17f5a2db60c8349fe532Romain Guy a.recycle(); 1842946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 1852946445b560fde5e63df17f5a2db60c8349fe532Romain Guy // initialize to current date 1862946445b560fde5e63df17f5a2db60c8349fe532Romain Guy Calendar cal = Calendar.getInstance(); 1872946445b560fde5e63df17f5a2db60c8349fe532Romain Guy init(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), null); 1882946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 1892946445b560fde5e63df17f5a2db60c8349fe532Romain Guy // re-order the number pickers to match the current date format 1902946445b560fde5e63df17f5a2db60c8349fe532Romain Guy reorderPickers(months); 1912946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 1922946445b560fde5e63df17f5a2db60c8349fe532Romain Guy if (!isEnabled()) { 1932946445b560fde5e63df17f5a2db60c8349fe532Romain Guy setEnabled(false); 1942946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 1952946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 1962946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 1972946445b560fde5e63df17f5a2db60c8349fe532Romain Guy @Override 1982946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public void setEnabled(boolean enabled) { 1992946445b560fde5e63df17f5a2db60c8349fe532Romain Guy super.setEnabled(enabled); 2002946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mDayPicker.setEnabled(enabled); 2012946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonthPicker.setEnabled(enabled); 2022946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearPicker.setEnabled(enabled); 2032946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 2042946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2052946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private void reorderPickers(String[] months) { 2062946445b560fde5e63df17f5a2db60c8349fe532Romain Guy java.text.DateFormat format; 2072946445b560fde5e63df17f5a2db60c8349fe532Romain Guy String order; 2082946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2092946445b560fde5e63df17f5a2db60c8349fe532Romain Guy /* 2102946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * If the user is in a locale where the medium date format is 2112946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * still numeric (Japanese and Czech, for example), respect 2122946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * the date format order setting. Otherwise, use the order 2132946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * that the locale says is appropriate for a spelled-out date. 2142946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 2152946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2162946445b560fde5e63df17f5a2db60c8349fe532Romain Guy if (months[0].startsWith("1")) { 2172946445b560fde5e63df17f5a2db60c8349fe532Romain Guy format = DateFormat.getDateFormat(getContext()); 2182946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } else { 2192946445b560fde5e63df17f5a2db60c8349fe532Romain Guy format = DateFormat.getMediumDateFormat(getContext()); 2202946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 2212946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2222946445b560fde5e63df17f5a2db60c8349fe532Romain Guy if (format instanceof SimpleDateFormat) { 2232946445b560fde5e63df17f5a2db60c8349fe532Romain Guy order = ((SimpleDateFormat) format).toPattern(); 2242946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } else { 2252946445b560fde5e63df17f5a2db60c8349fe532Romain Guy // Shouldn't happen, but just in case. 2262946445b560fde5e63df17f5a2db60c8349fe532Romain Guy order = new String(DateFormat.getDateFormatOrder(getContext())); 2272946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 2282946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2292946445b560fde5e63df17f5a2db60c8349fe532Romain Guy /* Remove the 3 pickers from their parent and then add them back in the 2302946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * required order. 2312946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 2322946445b560fde5e63df17f5a2db60c8349fe532Romain Guy LinearLayout parent = (LinearLayout) findViewById(R.id.parent); 2332946445b560fde5e63df17f5a2db60c8349fe532Romain Guy parent.removeAllViews(); 2342946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2352946445b560fde5e63df17f5a2db60c8349fe532Romain Guy boolean quoted = false; 2362946445b560fde5e63df17f5a2db60c8349fe532Romain Guy boolean didDay = false, didMonth = false, didYear = false; 2372946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2382946445b560fde5e63df17f5a2db60c8349fe532Romain Guy for (int i = 0; i < order.length(); i++) { 2392946445b560fde5e63df17f5a2db60c8349fe532Romain Guy char c = order.charAt(i); 2402946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2412946445b560fde5e63df17f5a2db60c8349fe532Romain Guy if (c == '\'') { 2422946445b560fde5e63df17f5a2db60c8349fe532Romain Guy quoted = !quoted; 2432946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 2442946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2452946445b560fde5e63df17f5a2db60c8349fe532Romain Guy if (!quoted) { 2462946445b560fde5e63df17f5a2db60c8349fe532Romain Guy if (c == DateFormat.DATE && !didDay) { 2472946445b560fde5e63df17f5a2db60c8349fe532Romain Guy parent.addView(mDayPicker); 2482946445b560fde5e63df17f5a2db60c8349fe532Romain Guy didDay = true; 2492946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } else if ((c == DateFormat.MONTH || c == 'L') && !didMonth) { 2502946445b560fde5e63df17f5a2db60c8349fe532Romain Guy parent.addView(mMonthPicker); 2512946445b560fde5e63df17f5a2db60c8349fe532Romain Guy didMonth = true; 2522946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } else if (c == DateFormat.YEAR && !didYear) { 2532946445b560fde5e63df17f5a2db60c8349fe532Romain Guy parent.addView (mYearPicker); 2542946445b560fde5e63df17f5a2db60c8349fe532Romain Guy didYear = true; 2552946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 2562946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 2572946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 2582946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2592946445b560fde5e63df17f5a2db60c8349fe532Romain Guy // Shouldn't happen, but just in case. 2602946445b560fde5e63df17f5a2db60c8349fe532Romain Guy if (!didMonth) { 2612946445b560fde5e63df17f5a2db60c8349fe532Romain Guy parent.addView(mMonthPicker); 2622946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 2632946445b560fde5e63df17f5a2db60c8349fe532Romain Guy if (!didDay) { 2642946445b560fde5e63df17f5a2db60c8349fe532Romain Guy parent.addView(mDayPicker); 2652946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 2662946445b560fde5e63df17f5a2db60c8349fe532Romain Guy if (!didYear) { 2672946445b560fde5e63df17f5a2db60c8349fe532Romain Guy parent.addView(mYearPicker); 2682946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 2692946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 2702946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2712946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public void updateDate(int year, int monthOfYear, int dayOfMonth) { 2722946445b560fde5e63df17f5a2db60c8349fe532Romain Guy if (mYear != year || mMonth != monthOfYear || mDay != dayOfMonth) { 2732946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYear = (mYearOptional && year == 0) ? getCurrentYear() : year; 2742946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonth = monthOfYear; 2752946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mDay = dayOfMonth; 2762946445b560fde5e63df17f5a2db60c8349fe532Romain Guy updateSpinners(); 2772946445b560fde5e63df17f5a2db60c8349fe532Romain Guy reorderPickers(new DateFormatSymbols().getShortMonths()); 2782946445b560fde5e63df17f5a2db60c8349fe532Romain Guy notifyDateChanged(); 2792946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 2802946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 2812946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2822946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private static int getCurrentYear() { 2832946445b560fde5e63df17f5a2db60c8349fe532Romain Guy return Calendar.getInstance().get(Calendar.YEAR); 2842946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 2852946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2862946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private static class SavedState extends BaseSavedState { 2872946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2882946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private final int mYear; 2892946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private final int mMonth; 2902946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private final int mDay; 2912946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private final boolean mHasYear; 2922946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private final boolean mYearOptional; 2932946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 2942946445b560fde5e63df17f5a2db60c8349fe532Romain Guy /** 2952946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * Constructor called from {@link DatePicker#onSaveInstanceState()} 2962946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 2972946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private SavedState(Parcelable superState, int year, int month, int day, boolean hasYear, 2982946445b560fde5e63df17f5a2db60c8349fe532Romain Guy boolean yearOptional) { 2992946445b560fde5e63df17f5a2db60c8349fe532Romain Guy super(superState); 3002946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYear = year; 3012946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonth = month; 3022946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mDay = day; 3032946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mHasYear = hasYear; 3042946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearOptional = yearOptional; 3052946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 3062946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3072946445b560fde5e63df17f5a2db60c8349fe532Romain Guy /** 3082946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * Constructor called from {@link #CREATOR} 3092946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 3102946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private SavedState(Parcel in) { 3112946445b560fde5e63df17f5a2db60c8349fe532Romain Guy super(in); 3122946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYear = in.readInt(); 3132946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonth = in.readInt(); 3142946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mDay = in.readInt(); 3152946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mHasYear = in.readInt() != 0; 3162946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearOptional = in.readInt() != 0; 3172946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 3182946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3192946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public int getYear() { 3202946445b560fde5e63df17f5a2db60c8349fe532Romain Guy return mYear; 3212946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 3222946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3232946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public int getMonth() { 3242946445b560fde5e63df17f5a2db60c8349fe532Romain Guy return mMonth; 3252946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 3262946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3272946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public int getDay() { 3282946445b560fde5e63df17f5a2db60c8349fe532Romain Guy return mDay; 3292946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 3302946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3312946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public boolean hasYear() { 3322946445b560fde5e63df17f5a2db60c8349fe532Romain Guy return mHasYear; 3332946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 3342946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3352946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public boolean isYearOptional() { 3362946445b560fde5e63df17f5a2db60c8349fe532Romain Guy return mYearOptional; 3372946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 3382946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3392946445b560fde5e63df17f5a2db60c8349fe532Romain Guy @Override 3402946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public void writeToParcel(Parcel dest, int flags) { 3412946445b560fde5e63df17f5a2db60c8349fe532Romain Guy super.writeToParcel(dest, flags); 3422946445b560fde5e63df17f5a2db60c8349fe532Romain Guy dest.writeInt(mYear); 3432946445b560fde5e63df17f5a2db60c8349fe532Romain Guy dest.writeInt(mMonth); 3442946445b560fde5e63df17f5a2db60c8349fe532Romain Guy dest.writeInt(mDay); 3452946445b560fde5e63df17f5a2db60c8349fe532Romain Guy dest.writeInt(mHasYear ? 1 : 0); 3462946445b560fde5e63df17f5a2db60c8349fe532Romain Guy dest.writeInt(mYearOptional ? 1 : 0); 3472946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 3482946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3492946445b560fde5e63df17f5a2db60c8349fe532Romain Guy @SuppressWarnings("unused") 3502946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public static final Parcelable.Creator<SavedState> CREATOR = 3512946445b560fde5e63df17f5a2db60c8349fe532Romain Guy new Creator<SavedState>() { 3522946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3532946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public SavedState createFromParcel(Parcel in) { 3542946445b560fde5e63df17f5a2db60c8349fe532Romain Guy return new SavedState(in); 3552946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 3562946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3572946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public SavedState[] newArray(int size) { 3582946445b560fde5e63df17f5a2db60c8349fe532Romain Guy return new SavedState[size]; 3592946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 3602946445b560fde5e63df17f5a2db60c8349fe532Romain Guy }; 3612946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 3622946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3632946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3642946445b560fde5e63df17f5a2db60c8349fe532Romain Guy /** 3652946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * Override so we are in complete control of save / restore for this widget. 3662946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 3672946445b560fde5e63df17f5a2db60c8349fe532Romain Guy @Override 3682946445b560fde5e63df17f5a2db60c8349fe532Romain Guy protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 3692946445b560fde5e63df17f5a2db60c8349fe532Romain Guy dispatchThawSelfOnly(container); 3702946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 3712946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3722946445b560fde5e63df17f5a2db60c8349fe532Romain Guy @Override 3732946445b560fde5e63df17f5a2db60c8349fe532Romain Guy protected Parcelable onSaveInstanceState() { 3742946445b560fde5e63df17f5a2db60c8349fe532Romain Guy Parcelable superState = super.onSaveInstanceState(); 3752946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3762946445b560fde5e63df17f5a2db60c8349fe532Romain Guy return new SavedState(superState, mYear, mMonth, mDay, mHasYear, mYearOptional); 3772946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 3782946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3792946445b560fde5e63df17f5a2db60c8349fe532Romain Guy @Override 3802946445b560fde5e63df17f5a2db60c8349fe532Romain Guy protected void onRestoreInstanceState(Parcelable state) { 3812946445b560fde5e63df17f5a2db60c8349fe532Romain Guy SavedState ss = (SavedState) state; 3822946445b560fde5e63df17f5a2db60c8349fe532Romain Guy super.onRestoreInstanceState(ss.getSuperState()); 3832946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYear = ss.getYear(); 3842946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonth = ss.getMonth(); 3852946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mDay = ss.getDay(); 3862946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mHasYear = ss.hasYear(); 3872946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearOptional = ss.isYearOptional(); 3882946445b560fde5e63df17f5a2db60c8349fe532Romain Guy updateSpinners(); 3892946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 3902946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 3912946445b560fde5e63df17f5a2db60c8349fe532Romain Guy /** 3922946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * Initialize the state. 3932946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * @param year The initial year. 3942946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * @param monthOfYear The initial month. 3952946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * @param dayOfMonth The initial day of the month. 3962946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * @param onDateChangedListener How user is notified date is changed by user, can be null. 3972946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 3982946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public void init(int year, int monthOfYear, int dayOfMonth, 3992946445b560fde5e63df17f5a2db60c8349fe532Romain Guy OnDateChangedListener onDateChangedListener) { 4002946445b560fde5e63df17f5a2db60c8349fe532Romain Guy init(year, monthOfYear, dayOfMonth, false, onDateChangedListener); 4012946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 4022946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 4032946445b560fde5e63df17f5a2db60c8349fe532Romain Guy /** 4042946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * Initialize the state. 4052946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * @param year The initial year or 0 if no year has been specified 4062946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * @param monthOfYear The initial month. 4072946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * @param dayOfMonth The initial day of the month. 4082946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * @param yearOptional True if the user can toggle the year 4092946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * @param onDateChangedListener How user is notified date is changed by user, can be null. 4102946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 4112946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public void init(int year, int monthOfYear, int dayOfMonth, boolean yearOptional, 4122946445b560fde5e63df17f5a2db60c8349fe532Romain Guy OnDateChangedListener onDateChangedListener) { 4132946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYear = (yearOptional && year == 0) ? getCurrentYear() : year; 4142946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonth = monthOfYear; 4152946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mDay = dayOfMonth; 4162946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearOptional = yearOptional; 4172946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mHasYear = !yearOptional || (year != 0); 4182946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mOnDateChangedListener = onDateChangedListener; 4192946445b560fde5e63df17f5a2db60c8349fe532Romain Guy updateSpinners(); 4202946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 4212946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 4222946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private void updateSpinners() { 4232946445b560fde5e63df17f5a2db60c8349fe532Romain Guy updateDaySpinner(); 4242946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearToggle.setChecked(mHasYear); 4252946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearToggle.setVisibility(mYearOptional ? View.VISIBLE : View.GONE); 4262946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearPicker.setValue(mYear); 4272946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mYearPicker.setVisibility(mHasYear ? View.VISIBLE : View.GONE); 4282946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 4292946445b560fde5e63df17f5a2db60c8349fe532Romain Guy /* The month display uses 1-12 but our internal state stores it 4302946445b560fde5e63df17f5a2db60c8349fe532Romain Guy * 0-11 so add one when setting the display. 4312946445b560fde5e63df17f5a2db60c8349fe532Romain Guy */ 4322946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mMonthPicker.setValue(mMonth + 1); 4332946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 4342946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 4352946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private void updateDaySpinner() { 4362946445b560fde5e63df17f5a2db60c8349fe532Romain Guy Calendar cal = Calendar.getInstance(); 4372946445b560fde5e63df17f5a2db60c8349fe532Romain Guy // if year was not set, use 2000 as it was a leap year 4382946445b560fde5e63df17f5a2db60c8349fe532Romain Guy cal.set(mHasYear ? mYear : 2000, mMonth, 1); 4392946445b560fde5e63df17f5a2db60c8349fe532Romain Guy int max = cal.getActualMaximum(Calendar.DAY_OF_MONTH); 4402946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mDayPicker.setMinValue(1); 4412946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mDayPicker.setMaxValue(max); 4422946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mDayPicker.setValue(mDay); 4432946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 4442946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 4452946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public int getYear() { 4462946445b560fde5e63df17f5a2db60c8349fe532Romain Guy return (mYearOptional && !mHasYear) ? 0 : mYear; 4472946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 4482946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 4492946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public int getMonth() { 4502946445b560fde5e63df17f5a2db60c8349fe532Romain Guy return mMonth; 4512946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 4522946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 4532946445b560fde5e63df17f5a2db60c8349fe532Romain Guy public int getDayOfMonth() { 4542946445b560fde5e63df17f5a2db60c8349fe532Romain Guy return mDay; 4552946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 4562946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 4572946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private void adjustMaxDay(){ 4582946445b560fde5e63df17f5a2db60c8349fe532Romain Guy Calendar cal = Calendar.getInstance(); 4592946445b560fde5e63df17f5a2db60c8349fe532Romain Guy // if year was not set, use 2000 as it was a leap year 4602946445b560fde5e63df17f5a2db60c8349fe532Romain Guy cal.set(Calendar.YEAR, mHasYear ? mYear : 2000); 4612946445b560fde5e63df17f5a2db60c8349fe532Romain Guy cal.set(Calendar.MONTH, mMonth); 4622946445b560fde5e63df17f5a2db60c8349fe532Romain Guy int max = cal.getActualMaximum(Calendar.DAY_OF_MONTH); 4632946445b560fde5e63df17f5a2db60c8349fe532Romain Guy if (mDay > max) { 4642946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mDay = max; 4652946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 4662946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 4672946445b560fde5e63df17f5a2db60c8349fe532Romain Guy 4682946445b560fde5e63df17f5a2db60c8349fe532Romain Guy private void notifyDateChanged() { 4692946445b560fde5e63df17f5a2db60c8349fe532Romain Guy if (mOnDateChangedListener != null) { 4702946445b560fde5e63df17f5a2db60c8349fe532Romain Guy int year = (mYearOptional && !mHasYear) ? 0 : mYear; 4712946445b560fde5e63df17f5a2db60c8349fe532Romain Guy mOnDateChangedListener.onDateChanged(DatePicker.this, year, mMonth, mDay); 4722946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 4732946445b560fde5e63df17f5a2db60c8349fe532Romain Guy } 4742946445b560fde5e63df17f5a2db60c8349fe532Romain Guy} 475