Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
michael@0 | 1 | /* |
michael@0 | 2 | * Copyright (C) 2007 The Android Open Source Project |
michael@0 | 3 | * |
michael@0 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
michael@0 | 5 | * you may not use this file except in compliance with the License. |
michael@0 | 6 | * You may obtain a copy of the License at |
michael@0 | 7 | * |
michael@0 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
michael@0 | 9 | * |
michael@0 | 10 | * Unless required by applicable law or agreed to in writing, software |
michael@0 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
michael@0 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
michael@0 | 13 | * See the License for the specific language governing permissions and |
michael@0 | 14 | * limitations under the License. |
michael@0 | 15 | */ |
michael@0 | 16 | |
michael@0 | 17 | package org.mozilla.gecko.widget; |
michael@0 | 18 | |
michael@0 | 19 | import org.mozilla.gecko.R; |
michael@0 | 20 | |
michael@0 | 21 | import android.content.Context; |
michael@0 | 22 | import android.os.Build; |
michael@0 | 23 | import android.text.format.DateFormat; |
michael@0 | 24 | import android.text.format.DateUtils; |
michael@0 | 25 | import android.util.DisplayMetrics; |
michael@0 | 26 | import android.util.Log; |
michael@0 | 27 | import android.view.Display; |
michael@0 | 28 | import android.view.LayoutInflater; |
michael@0 | 29 | import android.view.WindowManager; |
michael@0 | 30 | import android.view.accessibility.AccessibilityEvent; |
michael@0 | 31 | import android.view.inputmethod.InputMethodManager; |
michael@0 | 32 | import android.widget.CalendarView; |
michael@0 | 33 | import android.widget.EditText; |
michael@0 | 34 | import android.widget.FrameLayout; |
michael@0 | 35 | import android.widget.LinearLayout; |
michael@0 | 36 | import android.widget.NumberPicker; |
michael@0 | 37 | |
michael@0 | 38 | import java.text.SimpleDateFormat; |
michael@0 | 39 | import java.util.Arrays; |
michael@0 | 40 | import java.util.Calendar; |
michael@0 | 41 | import java.util.Locale; |
michael@0 | 42 | |
michael@0 | 43 | public class DateTimePicker extends FrameLayout { |
michael@0 | 44 | |
michael@0 | 45 | private static final boolean DEBUG = true; |
michael@0 | 46 | private static final String LOGTAG = "GeckoDateTimePicker"; |
michael@0 | 47 | private static final String DATE_FORMAT = "MM/dd/yyyy"; |
michael@0 | 48 | private static final int DEFAULT_START_YEAR = 1; |
michael@0 | 49 | private static final int DEFAULT_END_YEAR = 9999; |
michael@0 | 50 | // Minimal screen width (in inches) for which we can show the calendar; |
michael@0 | 51 | private static final int SCREEN_SIZE_THRESHOLD = 5; |
michael@0 | 52 | private boolean mYearEnabled = true; |
michael@0 | 53 | private boolean mMonthEnabled = true; |
michael@0 | 54 | private boolean mWeekEnabled = false; |
michael@0 | 55 | private boolean mDayEnabled = true; |
michael@0 | 56 | private boolean mHourEnabled = true; |
michael@0 | 57 | private boolean mMinuteEnabled = true; |
michael@0 | 58 | private boolean mCalendarEnabled = false; |
michael@0 | 59 | private boolean mIs12HourMode; |
michael@0 | 60 | // Size of the screen in inches; |
michael@0 | 61 | private int mScreenWidth; |
michael@0 | 62 | private int mScreenHeight; |
michael@0 | 63 | private OnValueChangeListener mOnChangeListener; |
michael@0 | 64 | private final LinearLayout mPickers; |
michael@0 | 65 | private final LinearLayout mDateSpinners; |
michael@0 | 66 | private final LinearLayout mTimeSpinners; |
michael@0 | 67 | private final LinearLayout mSpinners; |
michael@0 | 68 | private final NumberPicker mDaySpinner; |
michael@0 | 69 | private final NumberPicker mMonthSpinner; |
michael@0 | 70 | private final NumberPicker mWeekSpinner; |
michael@0 | 71 | private final NumberPicker mYearSpinner; |
michael@0 | 72 | private final NumberPicker mHourSpinner; |
michael@0 | 73 | private final NumberPicker mMinuteSpinner; |
michael@0 | 74 | private final NumberPicker mAMPMSpinner; |
michael@0 | 75 | private final CalendarView mCalendar; |
michael@0 | 76 | private final EditText mDaySpinnerInput; |
michael@0 | 77 | private final EditText mMonthSpinnerInput; |
michael@0 | 78 | private final EditText mWeekSpinnerInput; |
michael@0 | 79 | private final EditText mYearSpinnerInput; |
michael@0 | 80 | private final EditText mHourSpinnerInput; |
michael@0 | 81 | private final EditText mMinuteSpinnerInput; |
michael@0 | 82 | private final EditText mAMPMSpinnerInput; |
michael@0 | 83 | private Locale mCurrentLocale; |
michael@0 | 84 | private String[] mShortMonths; |
michael@0 | 85 | private String[] mShortAMPMs; |
michael@0 | 86 | private int mNumberOfMonths; |
michael@0 | 87 | private Calendar mTempDate; |
michael@0 | 88 | private Calendar mMinDate; |
michael@0 | 89 | private Calendar mMaxDate; |
michael@0 | 90 | private Calendar mCurrentDate; |
michael@0 | 91 | private PickersState mState; |
michael@0 | 92 | |
michael@0 | 93 | public static enum PickersState { DATE, MONTH, WEEK, TIME, DATETIME }; |
michael@0 | 94 | |
michael@0 | 95 | public class OnValueChangeListener implements NumberPicker.OnValueChangeListener { |
michael@0 | 96 | @Override |
michael@0 | 97 | public void onValueChange(NumberPicker picker, int oldVal, int newVal) { |
michael@0 | 98 | updateInputState(); |
michael@0 | 99 | mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis()); |
michael@0 | 100 | boolean newBehavior = (Build.VERSION.SDK_INT > 10); |
michael@0 | 101 | if (newBehavior) { |
michael@0 | 102 | if (DEBUG) Log.d(LOGTAG, "Sdk version > 10, using new behavior"); |
michael@0 | 103 | //The native date picker widget on these sdks increment |
michael@0 | 104 | //the next field when one field reach the maximum |
michael@0 | 105 | if (picker == mDaySpinner && mDayEnabled) { |
michael@0 | 106 | int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH); |
michael@0 | 107 | int old = mTempDate.get(Calendar.DAY_OF_MONTH); |
michael@0 | 108 | setTempDate(Calendar.DAY_OF_MONTH, old, newVal, 1, maxDayOfMonth); |
michael@0 | 109 | } else if (picker == mMonthSpinner && mMonthEnabled) { |
michael@0 | 110 | int old = mTempDate.get(Calendar.MONTH); |
michael@0 | 111 | setTempDate(Calendar.MONTH, old, newVal, Calendar.JANUARY, Calendar.DECEMBER); |
michael@0 | 112 | } else if (picker == mWeekSpinner) { |
michael@0 | 113 | int old = mTempDate.get(Calendar.WEEK_OF_YEAR); |
michael@0 | 114 | int maxWeekOfYear = mTempDate.getActualMaximum(Calendar.WEEK_OF_YEAR); |
michael@0 | 115 | setTempDate(Calendar.WEEK_OF_YEAR, old, newVal, 0, maxWeekOfYear); |
michael@0 | 116 | } else if (picker == mYearSpinner && mYearEnabled) { |
michael@0 | 117 | int month = mTempDate.get(Calendar.MONTH); |
michael@0 | 118 | mTempDate.set(Calendar.YEAR,newVal); |
michael@0 | 119 | // Changing the year shouldn't change the month. (in case of non-leap year a Feb 29) |
michael@0 | 120 | // change the day instead; |
michael@0 | 121 | if (month != mTempDate.get(Calendar.MONTH)){ |
michael@0 | 122 | mTempDate.set(Calendar.MONTH, month); |
michael@0 | 123 | mTempDate.set(Calendar.DAY_OF_MONTH, |
michael@0 | 124 | mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH)); |
michael@0 | 125 | } |
michael@0 | 126 | } else if (picker == mHourSpinner && mHourEnabled) { |
michael@0 | 127 | if (mIs12HourMode) { |
michael@0 | 128 | setTempDate(Calendar.HOUR, oldVal, newVal, 1, 12); |
michael@0 | 129 | } else { |
michael@0 | 130 | setTempDate(Calendar.HOUR_OF_DAY, oldVal, newVal, 0, 23); |
michael@0 | 131 | } |
michael@0 | 132 | } else if (picker == mMinuteSpinner && mMinuteEnabled) { |
michael@0 | 133 | setTempDate(Calendar.MINUTE, oldVal, newVal, 0, 59); |
michael@0 | 134 | } else if (picker == mAMPMSpinner && mHourEnabled) { |
michael@0 | 135 | mTempDate.set(Calendar.AM_PM,newVal); |
michael@0 | 136 | } else { |
michael@0 | 137 | throw new IllegalArgumentException(); |
michael@0 | 138 | } |
michael@0 | 139 | } else { |
michael@0 | 140 | if (DEBUG) Log.d(LOGTAG,"Sdk version < 10, using old behavior"); |
michael@0 | 141 | if (picker == mDaySpinner && mDayEnabled){ |
michael@0 | 142 | mTempDate.set(Calendar.DAY_OF_MONTH, newVal); |
michael@0 | 143 | } else if (picker == mMonthSpinner && mMonthEnabled){ |
michael@0 | 144 | mTempDate.set(Calendar.MONTH, newVal); |
michael@0 | 145 | if (mTempDate.get(Calendar.MONTH) == newVal+1){ |
michael@0 | 146 | mTempDate.set(Calendar.MONTH, newVal); |
michael@0 | 147 | mTempDate.set(Calendar.DAY_OF_MONTH, |
michael@0 | 148 | mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH)); |
michael@0 | 149 | } |
michael@0 | 150 | } else if (picker == mWeekSpinner){ |
michael@0 | 151 | mTempDate.set(Calendar.WEEK_OF_YEAR, newVal); |
michael@0 | 152 | } else if (picker == mYearSpinner && mYearEnabled){ |
michael@0 | 153 | int month = mTempDate.get(Calendar.MONTH); |
michael@0 | 154 | mTempDate.set(Calendar.YEAR, newVal); |
michael@0 | 155 | if (month != mTempDate.get(Calendar.MONTH)) { |
michael@0 | 156 | mTempDate.set(Calendar.MONTH, month); |
michael@0 | 157 | mTempDate.set(Calendar.DAY_OF_MONTH, |
michael@0 | 158 | mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH)); |
michael@0 | 159 | } |
michael@0 | 160 | } else if (picker == mHourSpinner && mHourEnabled){ |
michael@0 | 161 | if (mIs12HourMode) { |
michael@0 | 162 | mTempDate.set(Calendar.HOUR, newVal); |
michael@0 | 163 | } else { |
michael@0 | 164 | mTempDate.set(Calendar.HOUR_OF_DAY, newVal); |
michael@0 | 165 | } |
michael@0 | 166 | } else if (picker == mMinuteSpinner && mMinuteEnabled){ |
michael@0 | 167 | mTempDate.set(Calendar.MINUTE, newVal); |
michael@0 | 168 | } else if (picker == mAMPMSpinner && mHourEnabled) { |
michael@0 | 169 | mTempDate.set(Calendar.AM_PM, newVal); |
michael@0 | 170 | } else { |
michael@0 | 171 | throw new IllegalArgumentException(); |
michael@0 | 172 | } |
michael@0 | 173 | } |
michael@0 | 174 | setDate(mTempDate); |
michael@0 | 175 | if (mDayEnabled) { |
michael@0 | 176 | mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH)); |
michael@0 | 177 | } |
michael@0 | 178 | if(mWeekEnabled) { |
michael@0 | 179 | mWeekSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.WEEK_OF_YEAR)); |
michael@0 | 180 | } |
michael@0 | 181 | updateCalendar(); |
michael@0 | 182 | updateSpinners(); |
michael@0 | 183 | notifyDateChanged(); |
michael@0 | 184 | } |
michael@0 | 185 | |
michael@0 | 186 | private void setTempDate(int field, int oldVal, int newVal, int min, int max) { |
michael@0 | 187 | if (oldVal == max && newVal == min ) { |
michael@0 | 188 | mTempDate.add(field, 1); |
michael@0 | 189 | } else if (oldVal == min && newVal == max) { |
michael@0 | 190 | mTempDate.add(field, -1); |
michael@0 | 191 | } else { |
michael@0 | 192 | mTempDate.add(field, newVal - oldVal); |
michael@0 | 193 | } |
michael@0 | 194 | } |
michael@0 | 195 | } |
michael@0 | 196 | |
michael@0 | 197 | private static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = new NumberPicker.Formatter() { |
michael@0 | 198 | final StringBuilder mBuilder = new StringBuilder(); |
michael@0 | 199 | |
michael@0 | 200 | final java.util.Formatter mFmt = new java.util.Formatter(mBuilder, java.util.Locale.US); |
michael@0 | 201 | |
michael@0 | 202 | final Object[] mArgs = new Object[1]; |
michael@0 | 203 | |
michael@0 | 204 | @Override |
michael@0 | 205 | public String format(int value) { |
michael@0 | 206 | mArgs[0] = value; |
michael@0 | 207 | mBuilder.delete(0, mBuilder.length()); |
michael@0 | 208 | mFmt.format("%02d", mArgs); |
michael@0 | 209 | return mFmt.toString(); |
michael@0 | 210 | } |
michael@0 | 211 | }; |
michael@0 | 212 | |
michael@0 | 213 | private void displayPickers() { |
michael@0 | 214 | setWeekShown(false); |
michael@0 | 215 | set12HourShown(mIs12HourMode); |
michael@0 | 216 | if (mState == PickersState.DATETIME) { |
michael@0 | 217 | return; |
michael@0 | 218 | } |
michael@0 | 219 | setHourShown(false); |
michael@0 | 220 | setMinuteShown(false); |
michael@0 | 221 | if (mState == PickersState.WEEK) { |
michael@0 | 222 | setDayShown(false); |
michael@0 | 223 | setMonthShown(false); |
michael@0 | 224 | setWeekShown(true); |
michael@0 | 225 | } else if (mState == PickersState.MONTH) { |
michael@0 | 226 | setDayShown(false); |
michael@0 | 227 | } |
michael@0 | 228 | } |
michael@0 | 229 | |
michael@0 | 230 | public DateTimePicker(Context context) { |
michael@0 | 231 | this(context, "", "", PickersState.DATE); |
michael@0 | 232 | } |
michael@0 | 233 | |
michael@0 | 234 | public DateTimePicker(Context context, String dateFormat, String dateTimeValue, PickersState state) { |
michael@0 | 235 | super(context); |
michael@0 | 236 | if (Build.VERSION.SDK_INT < 11) { |
michael@0 | 237 | throw new UnsupportedOperationException("Custom DateTimePicker is only available for SDK > 10"); |
michael@0 | 238 | } |
michael@0 | 239 | setCurrentLocale(Locale.getDefault()); |
michael@0 | 240 | mMinDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1); |
michael@0 | 241 | mMaxDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31); |
michael@0 | 242 | mState = state; |
michael@0 | 243 | LayoutInflater inflater = LayoutInflater.from(context); |
michael@0 | 244 | inflater.inflate(R.layout.datetime_picker, this, true); |
michael@0 | 245 | |
michael@0 | 246 | mOnChangeListener = new OnValueChangeListener(); |
michael@0 | 247 | |
michael@0 | 248 | mDateSpinners = (LinearLayout)findViewById(R.id.date_spinners); |
michael@0 | 249 | mTimeSpinners = (LinearLayout)findViewById(R.id.time_spinners); |
michael@0 | 250 | mSpinners = (LinearLayout)findViewById(R.id.spinners); |
michael@0 | 251 | mPickers = (LinearLayout)findViewById(R.id.datetime_picker); |
michael@0 | 252 | |
michael@0 | 253 | // We will display differently according to the screen size width. |
michael@0 | 254 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); |
michael@0 | 255 | Display display = wm.getDefaultDisplay(); |
michael@0 | 256 | DisplayMetrics dm = new DisplayMetrics(); |
michael@0 | 257 | display.getMetrics(dm); |
michael@0 | 258 | mScreenWidth = display.getWidth() / dm.densityDpi; |
michael@0 | 259 | mScreenHeight = display.getHeight() / dm.densityDpi; |
michael@0 | 260 | if (DEBUG) Log.d(LOGTAG, "screen width: " + mScreenWidth + " screen height: " + mScreenHeight); |
michael@0 | 261 | |
michael@0 | 262 | // If we're displaying a date, the screen is wide enought (and if we're using a sdk where the calendar view exists) |
michael@0 | 263 | // then display a calendar. |
michael@0 | 264 | if ((mState == PickersState.DATE || mState == PickersState.DATETIME) && |
michael@0 | 265 | Build.VERSION.SDK_INT > 10 && mScreenWidth >= SCREEN_SIZE_THRESHOLD) { |
michael@0 | 266 | if (DEBUG) Log.d(LOGTAG,"SDK > 10 and screen wide enough, displaying calendar"); |
michael@0 | 267 | mCalendar = new CalendarView(context); |
michael@0 | 268 | mCalendar.setVisibility(GONE); |
michael@0 | 269 | |
michael@0 | 270 | LayoutParams layoutParams = new LayoutParams(250,280); |
michael@0 | 271 | mCalendar.setLayoutParams(layoutParams); |
michael@0 | 272 | mCalendar.setFocusable(true); |
michael@0 | 273 | mCalendar.setFocusableInTouchMode(true); |
michael@0 | 274 | mCalendar.setMaxDate(mMaxDate.getTimeInMillis()); |
michael@0 | 275 | mCalendar.setMinDate(mMinDate.getTimeInMillis()); |
michael@0 | 276 | |
michael@0 | 277 | mCalendar.setOnDateChangeListener(new CalendarView.OnDateChangeListener() { |
michael@0 | 278 | @Override |
michael@0 | 279 | public void onSelectedDayChange( |
michael@0 | 280 | CalendarView view, int year, int month, int monthDay) { |
michael@0 | 281 | mTempDate.set(year, month, monthDay); |
michael@0 | 282 | setDate(mTempDate); |
michael@0 | 283 | notifyDateChanged(); |
michael@0 | 284 | } |
michael@0 | 285 | }); |
michael@0 | 286 | |
michael@0 | 287 | mPickers.addView(mCalendar); |
michael@0 | 288 | } else { |
michael@0 | 289 | // If the screen is more wide than high, we are displaying daye and time spinners, |
michael@0 | 290 | // and if there is no calendar displayed, |
michael@0 | 291 | // we should display the fields in one row. |
michael@0 | 292 | if (mScreenWidth > mScreenHeight && mState == PickersState.DATETIME) { |
michael@0 | 293 | mSpinners.setOrientation(LinearLayout.HORIZONTAL); |
michael@0 | 294 | } |
michael@0 | 295 | mCalendar = null; |
michael@0 | 296 | } |
michael@0 | 297 | |
michael@0 | 298 | // Find the initial date from the constructor arguments. |
michael@0 | 299 | try { |
michael@0 | 300 | if (!dateTimeValue.equals("")) { |
michael@0 | 301 | mTempDate.setTime(new SimpleDateFormat(dateFormat).parse(dateTimeValue)); |
michael@0 | 302 | } else { |
michael@0 | 303 | mTempDate.setTimeInMillis(System.currentTimeMillis()); |
michael@0 | 304 | } |
michael@0 | 305 | } catch (Exception ex) { |
michael@0 | 306 | Log.e(LOGTAG, "Error parsing format string: " + ex); |
michael@0 | 307 | mTempDate.setTimeInMillis(System.currentTimeMillis()); |
michael@0 | 308 | } |
michael@0 | 309 | |
michael@0 | 310 | // Initialize all spinners. |
michael@0 | 311 | mDaySpinner = setupSpinner(R.id.day, 1, |
michael@0 | 312 | mTempDate.get(Calendar.DAY_OF_MONTH)); |
michael@0 | 313 | mDaySpinner.setFormatter(TWO_DIGIT_FORMATTER); |
michael@0 | 314 | mDaySpinnerInput = (EditText) mDaySpinner.getChildAt(1); |
michael@0 | 315 | |
michael@0 | 316 | mMonthSpinner = setupSpinner(R.id.month, 1, |
michael@0 | 317 | mTempDate.get(Calendar.MONTH)); |
michael@0 | 318 | mMonthSpinner.setFormatter(TWO_DIGIT_FORMATTER); |
michael@0 | 319 | mMonthSpinner.setDisplayedValues(mShortMonths); |
michael@0 | 320 | mMonthSpinnerInput = (EditText) mMonthSpinner.getChildAt(1); |
michael@0 | 321 | |
michael@0 | 322 | mWeekSpinner = setupSpinner(R.id.week, 1, |
michael@0 | 323 | mTempDate.get(Calendar.WEEK_OF_YEAR)); |
michael@0 | 324 | mWeekSpinner.setFormatter(TWO_DIGIT_FORMATTER); |
michael@0 | 325 | mWeekSpinnerInput = (EditText) mWeekSpinner.getChildAt(1); |
michael@0 | 326 | |
michael@0 | 327 | mYearSpinner = setupSpinner(R.id.year, DEFAULT_START_YEAR, |
michael@0 | 328 | DEFAULT_END_YEAR); |
michael@0 | 329 | mYearSpinnerInput = (EditText) mYearSpinner.getChildAt(1); |
michael@0 | 330 | |
michael@0 | 331 | mAMPMSpinner = setupSpinner(R.id.ampm, 0, 1); |
michael@0 | 332 | mAMPMSpinner.setFormatter(TWO_DIGIT_FORMATTER); |
michael@0 | 333 | |
michael@0 | 334 | if (mIs12HourMode) { |
michael@0 | 335 | mHourSpinner = setupSpinner(R.id.hour, 1, 12); |
michael@0 | 336 | mAMPMSpinnerInput = (EditText) mAMPMSpinner.getChildAt(1); |
michael@0 | 337 | mAMPMSpinner.setDisplayedValues(mShortAMPMs); |
michael@0 | 338 | } else { |
michael@0 | 339 | mHourSpinner = setupSpinner(R.id.hour, 0, 23); |
michael@0 | 340 | mAMPMSpinnerInput = null; |
michael@0 | 341 | } |
michael@0 | 342 | |
michael@0 | 343 | mHourSpinner.setFormatter(TWO_DIGIT_FORMATTER); |
michael@0 | 344 | mHourSpinnerInput = (EditText) mHourSpinner.getChildAt(1); |
michael@0 | 345 | |
michael@0 | 346 | mMinuteSpinner = setupSpinner(R.id.minute, 0, 59); |
michael@0 | 347 | mMinuteSpinner.setFormatter(TWO_DIGIT_FORMATTER); |
michael@0 | 348 | mMinuteSpinnerInput = (EditText) mMinuteSpinner.getChildAt(1); |
michael@0 | 349 | |
michael@0 | 350 | // The order in which the spinners are displayed are locale-dependent |
michael@0 | 351 | reorderDateSpinners(); |
michael@0 | 352 | // Set the date to the initial date. Since this date can come from the user, |
michael@0 | 353 | // it can fire an exception (out-of-bound date) |
michael@0 | 354 | try { |
michael@0 | 355 | updateDate(mTempDate); |
michael@0 | 356 | } catch (Exception ex) { } |
michael@0 | 357 | |
michael@0 | 358 | // Display only the pickers needed for the current state. |
michael@0 | 359 | displayPickers(); |
michael@0 | 360 | } |
michael@0 | 361 | |
michael@0 | 362 | public NumberPicker setupSpinner(int id, int min, int max) { |
michael@0 | 363 | NumberPicker mSpinner = (NumberPicker) findViewById(id); |
michael@0 | 364 | mSpinner.setMinValue(min); |
michael@0 | 365 | mSpinner.setMaxValue(max); |
michael@0 | 366 | mSpinner.setOnValueChangedListener(mOnChangeListener); |
michael@0 | 367 | mSpinner.setOnLongPressUpdateInterval(100); |
michael@0 | 368 | return mSpinner; |
michael@0 | 369 | } |
michael@0 | 370 | |
michael@0 | 371 | public long getTimeInMillis(){ |
michael@0 | 372 | return mCurrentDate.getTimeInMillis(); |
michael@0 | 373 | } |
michael@0 | 374 | |
michael@0 | 375 | private void reorderDateSpinners() { |
michael@0 | 376 | mDateSpinners.removeAllViews(); |
michael@0 | 377 | char[] order = DateFormat.getDateFormatOrder(getContext()); |
michael@0 | 378 | final int spinnerCount = order.length; |
michael@0 | 379 | for (int i = 0; i < spinnerCount; i++) { |
michael@0 | 380 | switch (order[i]) { |
michael@0 | 381 | case DateFormat.DATE: |
michael@0 | 382 | mDateSpinners.addView(mDaySpinner); |
michael@0 | 383 | break; |
michael@0 | 384 | case DateFormat.MONTH: |
michael@0 | 385 | mDateSpinners.addView(mMonthSpinner); |
michael@0 | 386 | break; |
michael@0 | 387 | case DateFormat.YEAR: |
michael@0 | 388 | mDateSpinners.addView(mYearSpinner); |
michael@0 | 389 | break; |
michael@0 | 390 | default: |
michael@0 | 391 | throw new IllegalArgumentException(); |
michael@0 | 392 | } |
michael@0 | 393 | } |
michael@0 | 394 | mDateSpinners.addView(mWeekSpinner); |
michael@0 | 395 | } |
michael@0 | 396 | |
michael@0 | 397 | private void setDate(Calendar calendar){ |
michael@0 | 398 | mCurrentDate = mTempDate; |
michael@0 | 399 | if (mCurrentDate.before(mMinDate)) { |
michael@0 | 400 | mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis()); |
michael@0 | 401 | } else if (mCurrentDate.after(mMaxDate)) { |
michael@0 | 402 | mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis()); |
michael@0 | 403 | } |
michael@0 | 404 | } |
michael@0 | 405 | |
michael@0 | 406 | private void updateInputState() { |
michael@0 | 407 | InputMethodManager inputMethodManager = (InputMethodManager) |
michael@0 | 408 | getContext().getSystemService(Context.INPUT_METHOD_SERVICE); |
michael@0 | 409 | if (mYearEnabled && inputMethodManager.isActive(mYearSpinnerInput)) { |
michael@0 | 410 | mYearSpinnerInput.clearFocus(); |
michael@0 | 411 | inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); |
michael@0 | 412 | } else if (mMonthEnabled && inputMethodManager.isActive(mMonthSpinnerInput)) { |
michael@0 | 413 | mMonthSpinnerInput.clearFocus(); |
michael@0 | 414 | inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); |
michael@0 | 415 | } else if (mDayEnabled && inputMethodManager.isActive(mDaySpinnerInput)) { |
michael@0 | 416 | mDaySpinnerInput.clearFocus(); |
michael@0 | 417 | inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); |
michael@0 | 418 | } else if (mHourEnabled && inputMethodManager.isActive(mHourSpinnerInput)) { |
michael@0 | 419 | mHourSpinnerInput.clearFocus(); |
michael@0 | 420 | inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); |
michael@0 | 421 | } else if (mMinuteEnabled && inputMethodManager.isActive(mMinuteSpinnerInput)) { |
michael@0 | 422 | mMinuteSpinnerInput.clearFocus(); |
michael@0 | 423 | inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); |
michael@0 | 424 | } |
michael@0 | 425 | } |
michael@0 | 426 | |
michael@0 | 427 | private void updateSpinners() { |
michael@0 | 428 | if (mDayEnabled) { |
michael@0 | 429 | if (mCurrentDate.equals(mMinDate)) { |
michael@0 | 430 | mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH)); |
michael@0 | 431 | mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH)); |
michael@0 | 432 | } else if (mCurrentDate.equals(mMaxDate)) { |
michael@0 | 433 | mDaySpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.DAY_OF_MONTH)); |
michael@0 | 434 | mDaySpinner.setMaxValue(mCurrentDate.get(Calendar.DAY_OF_MONTH)); |
michael@0 | 435 | } else { |
michael@0 | 436 | mDaySpinner.setMinValue(1); |
michael@0 | 437 | mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH)); |
michael@0 | 438 | } |
michael@0 | 439 | mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH)); |
michael@0 | 440 | } |
michael@0 | 441 | |
michael@0 | 442 | if (mWeekEnabled) { |
michael@0 | 443 | mWeekSpinner.setMinValue(1); |
michael@0 | 444 | mWeekSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.WEEK_OF_YEAR)); |
michael@0 | 445 | mWeekSpinner.setValue(mCurrentDate.get(Calendar.WEEK_OF_YEAR)); |
michael@0 | 446 | } |
michael@0 | 447 | |
michael@0 | 448 | if (mMonthEnabled) { |
michael@0 | 449 | mMonthSpinner.setDisplayedValues(null); |
michael@0 | 450 | if (mCurrentDate.equals(mMinDate)) { |
michael@0 | 451 | mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH)); |
michael@0 | 452 | mMonthSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.MONTH)); |
michael@0 | 453 | } else if (mCurrentDate.equals(mMaxDate)) { |
michael@0 | 454 | mMonthSpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.MONTH)); |
michael@0 | 455 | mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH)); |
michael@0 | 456 | } else { |
michael@0 | 457 | mMonthSpinner.setMinValue(Calendar.JANUARY); |
michael@0 | 458 | mMonthSpinner.setMaxValue(Calendar.DECEMBER); |
michael@0 | 459 | } |
michael@0 | 460 | |
michael@0 | 461 | String[] displayedValues = Arrays.copyOfRange(mShortMonths, |
michael@0 | 462 | mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1); |
michael@0 | 463 | mMonthSpinner.setDisplayedValues(displayedValues); |
michael@0 | 464 | mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH)); |
michael@0 | 465 | } |
michael@0 | 466 | |
michael@0 | 467 | if (mYearEnabled) { |
michael@0 | 468 | mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR)); |
michael@0 | 469 | mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR)); |
michael@0 | 470 | mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR)); |
michael@0 | 471 | } |
michael@0 | 472 | |
michael@0 | 473 | if (mHourEnabled) { |
michael@0 | 474 | if (mIs12HourMode) { |
michael@0 | 475 | mHourSpinner.setValue(mCurrentDate.get(Calendar.HOUR)); |
michael@0 | 476 | mAMPMSpinner.setValue(mCurrentDate.get(Calendar.AM_PM)); |
michael@0 | 477 | mAMPMSpinner.setDisplayedValues(mShortAMPMs); |
michael@0 | 478 | } else { |
michael@0 | 479 | mHourSpinner.setValue(mCurrentDate.get(Calendar.HOUR_OF_DAY)); |
michael@0 | 480 | } |
michael@0 | 481 | } |
michael@0 | 482 | if (mMinuteEnabled) { |
michael@0 | 483 | mMinuteSpinner.setValue(mCurrentDate.get(Calendar.MINUTE)); |
michael@0 | 484 | } |
michael@0 | 485 | } |
michael@0 | 486 | |
michael@0 | 487 | private void updateCalendar() { |
michael@0 | 488 | if (mCalendarEnabled){ |
michael@0 | 489 | mCalendar.setDate(mCurrentDate.getTimeInMillis(), false, false); |
michael@0 | 490 | } |
michael@0 | 491 | } |
michael@0 | 492 | |
michael@0 | 493 | private void notifyDateChanged() { |
michael@0 | 494 | sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); |
michael@0 | 495 | } |
michael@0 | 496 | |
michael@0 | 497 | public void toggleCalendar(boolean shown) { |
michael@0 | 498 | if ((mState != PickersState.DATE && mState != PickersState.DATETIME) || |
michael@0 | 499 | Build.VERSION.SDK_INT < 11 || mScreenWidth < SCREEN_SIZE_THRESHOLD) { |
michael@0 | 500 | if (DEBUG) Log.d(LOGTAG,"Cannot display calendar on this device, in this state" + |
michael@0 | 501 | ": screen width :"+mScreenWidth); |
michael@0 | 502 | return; |
michael@0 | 503 | } |
michael@0 | 504 | if (shown){ |
michael@0 | 505 | mCalendarEnabled = true; |
michael@0 | 506 | mCalendar.setVisibility(VISIBLE); |
michael@0 | 507 | setYearShown(false); |
michael@0 | 508 | setWeekShown(false); |
michael@0 | 509 | setMonthShown(false); |
michael@0 | 510 | setDayShown(false); |
michael@0 | 511 | } else { |
michael@0 | 512 | mCalendar.setVisibility(GONE); |
michael@0 | 513 | setYearShown(true); |
michael@0 | 514 | setMonthShown(true); |
michael@0 | 515 | setDayShown(true); |
michael@0 | 516 | mSpinners.setOrientation(LinearLayout.HORIZONTAL); |
michael@0 | 517 | mCalendarEnabled = false; |
michael@0 | 518 | } |
michael@0 | 519 | } |
michael@0 | 520 | |
michael@0 | 521 | private void setYearShown(boolean shown) { |
michael@0 | 522 | if (shown) { |
michael@0 | 523 | toggleCalendar(false); |
michael@0 | 524 | mYearSpinner.setVisibility(VISIBLE); |
michael@0 | 525 | mYearEnabled = true; |
michael@0 | 526 | } else { |
michael@0 | 527 | mYearSpinner.setVisibility(GONE); |
michael@0 | 528 | mYearEnabled = false; |
michael@0 | 529 | } |
michael@0 | 530 | } |
michael@0 | 531 | |
michael@0 | 532 | private void setWeekShown(boolean shown) { |
michael@0 | 533 | if (shown) { |
michael@0 | 534 | toggleCalendar(false); |
michael@0 | 535 | mWeekSpinner.setVisibility(VISIBLE); |
michael@0 | 536 | mWeekEnabled = true; |
michael@0 | 537 | } else { |
michael@0 | 538 | mWeekSpinner.setVisibility(GONE); |
michael@0 | 539 | mWeekEnabled = false; |
michael@0 | 540 | } |
michael@0 | 541 | } |
michael@0 | 542 | |
michael@0 | 543 | private void setMonthShown(boolean shown) { |
michael@0 | 544 | if (shown) { |
michael@0 | 545 | toggleCalendar(false); |
michael@0 | 546 | mMonthSpinner.setVisibility(VISIBLE); |
michael@0 | 547 | mMonthEnabled = true; |
michael@0 | 548 | } else { |
michael@0 | 549 | mMonthSpinner.setVisibility(GONE); |
michael@0 | 550 | mMonthEnabled = false; |
michael@0 | 551 | } |
michael@0 | 552 | } |
michael@0 | 553 | |
michael@0 | 554 | private void setDayShown(boolean shown) { |
michael@0 | 555 | if (shown) { |
michael@0 | 556 | toggleCalendar(false); |
michael@0 | 557 | mDaySpinner.setVisibility(VISIBLE); |
michael@0 | 558 | mDayEnabled = true; |
michael@0 | 559 | } else { |
michael@0 | 560 | mDaySpinner.setVisibility(GONE); |
michael@0 | 561 | mDayEnabled = false; |
michael@0 | 562 | } |
michael@0 | 563 | } |
michael@0 | 564 | |
michael@0 | 565 | private void set12HourShown(boolean shown) { |
michael@0 | 566 | if (shown) { |
michael@0 | 567 | mAMPMSpinner.setVisibility(VISIBLE); |
michael@0 | 568 | } else { |
michael@0 | 569 | mAMPMSpinner.setVisibility(GONE); |
michael@0 | 570 | } |
michael@0 | 571 | } |
michael@0 | 572 | |
michael@0 | 573 | private void setHourShown(boolean shown) { |
michael@0 | 574 | if (shown) { |
michael@0 | 575 | mHourSpinner.setVisibility(VISIBLE); |
michael@0 | 576 | mHourEnabled= true; |
michael@0 | 577 | } else { |
michael@0 | 578 | mHourSpinner.setVisibility(GONE); |
michael@0 | 579 | mAMPMSpinner.setVisibility(GONE); |
michael@0 | 580 | mTimeSpinners.setVisibility(GONE); |
michael@0 | 581 | mHourEnabled = false; |
michael@0 | 582 | } |
michael@0 | 583 | } |
michael@0 | 584 | |
michael@0 | 585 | private void setMinuteShown(boolean shown) { |
michael@0 | 586 | if (shown) { |
michael@0 | 587 | mMinuteSpinner.setVisibility(VISIBLE); |
michael@0 | 588 | mTimeSpinners.findViewById(R.id.mincolon).setVisibility(VISIBLE); |
michael@0 | 589 | mMinuteEnabled= true; |
michael@0 | 590 | } else { |
michael@0 | 591 | mMinuteSpinner.setVisibility(GONE); |
michael@0 | 592 | mTimeSpinners.findViewById(R.id.mincolon).setVisibility(GONE); |
michael@0 | 593 | mMinuteEnabled = false; |
michael@0 | 594 | } |
michael@0 | 595 | } |
michael@0 | 596 | |
michael@0 | 597 | private void setCurrentLocale(Locale locale) { |
michael@0 | 598 | if (locale.equals(mCurrentLocale)) { |
michael@0 | 599 | return; |
michael@0 | 600 | } |
michael@0 | 601 | |
michael@0 | 602 | mCurrentLocale = locale; |
michael@0 | 603 | mIs12HourMode = !DateFormat.is24HourFormat(getContext()); |
michael@0 | 604 | mTempDate = getCalendarForLocale(mTempDate, locale); |
michael@0 | 605 | mMinDate = getCalendarForLocale(mMinDate, locale); |
michael@0 | 606 | mMaxDate = getCalendarForLocale(mMaxDate, locale); |
michael@0 | 607 | mCurrentDate = getCalendarForLocale(mCurrentDate, locale); |
michael@0 | 608 | |
michael@0 | 609 | mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1; |
michael@0 | 610 | |
michael@0 | 611 | mShortAMPMs = new String[2]; |
michael@0 | 612 | mShortAMPMs[0] = DateUtils.getAMPMString(Calendar.AM); |
michael@0 | 613 | mShortAMPMs[1] = DateUtils.getAMPMString(Calendar.PM); |
michael@0 | 614 | |
michael@0 | 615 | mShortMonths = new String[mNumberOfMonths]; |
michael@0 | 616 | for (int i = 0; i < mNumberOfMonths; i++) { |
michael@0 | 617 | mShortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i, |
michael@0 | 618 | DateUtils.LENGTH_MEDIUM); |
michael@0 | 619 | } |
michael@0 | 620 | } |
michael@0 | 621 | |
michael@0 | 622 | private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) { |
michael@0 | 623 | if (oldCalendar == null) { |
michael@0 | 624 | return Calendar.getInstance(locale); |
michael@0 | 625 | } else { |
michael@0 | 626 | final long currentTimeMillis = oldCalendar.getTimeInMillis(); |
michael@0 | 627 | Calendar newCalendar = Calendar.getInstance(locale); |
michael@0 | 628 | newCalendar.setTimeInMillis(currentTimeMillis); |
michael@0 | 629 | return newCalendar; |
michael@0 | 630 | } |
michael@0 | 631 | } |
michael@0 | 632 | |
michael@0 | 633 | public void updateDate(Calendar calendar) { |
michael@0 | 634 | if (mCurrentDate.equals(calendar)) { |
michael@0 | 635 | return; |
michael@0 | 636 | } |
michael@0 | 637 | mCurrentDate.setTimeInMillis(calendar.getTimeInMillis()); |
michael@0 | 638 | if (mCurrentDate.before(mMinDate)) { |
michael@0 | 639 | mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis()); |
michael@0 | 640 | } else if (mCurrentDate.after(mMaxDate)) { |
michael@0 | 641 | mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis()); |
michael@0 | 642 | } |
michael@0 | 643 | updateSpinners(); |
michael@0 | 644 | notifyDateChanged(); |
michael@0 | 645 | } |
michael@0 | 646 | |
michael@0 | 647 | } |
michael@0 | 648 |