mobile/android/base/widget/DateTimePicker.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

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

mercurial