diff options
Diffstat (limited to 'android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/DatePicker.java')
-rw-r--r-- | android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/DatePicker.java | 559 |
1 files changed, 559 insertions, 0 deletions
diff --git a/android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/DatePicker.java b/android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/DatePicker.java new file mode 100644 index 0000000000..b0250917d0 --- /dev/null +++ b/android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/DatePicker.java @@ -0,0 +1,559 @@ + +package org.holoeverywhere.widget; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Locale; + +import org.holoeverywhere.LayoutInflater; +import org.holoeverywhere.R; +import org.holoeverywhere.internal.NumberPickerEditText; +import org.holoeverywhere.util.Arrays; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.TypedArray; +import android.os.Build.VERSION; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; +import android.text.format.DateFormat; +import android.text.format.DateUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.util.SparseArray; +import android.view.View; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; + +public class DatePicker extends FrameLayout { + private final class Callback implements NumberPicker.OnValueChangeListener, + CalendarView.OnDateChangeListener { + @Override + public void onSelectedDayChange(CalendarView view, int year, int month, + int monthDay) { + setDate(year, month, monthDay); + updateSpinners(); + notifyDateChanged(); + } + + @Override + public void onValueChange(NumberPicker picker, int oldVal, int newVal) { + updateInputState(); + tempDate.setTimeInMillis(currentDate.getTimeInMillis()); + if (picker == daySpinner) { + int maxDayOfMonth = tempDate + .getActualMaximum(Calendar.DAY_OF_MONTH); + if (oldVal == maxDayOfMonth && newVal == 1) { + tempDate.add(Calendar.DAY_OF_MONTH, 1); + } else if (oldVal == 1 && newVal == maxDayOfMonth) { + tempDate.add(Calendar.DAY_OF_MONTH, -1); + } else { + tempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal); + } + } else if (picker == monthSpinner) { + if (oldVal == 11 && newVal == 0) { + tempDate.add(Calendar.MONTH, 1); + } else if (oldVal == 0 && newVal == 11) { + tempDate.add(Calendar.MONTH, -1); + } else { + tempDate.add(Calendar.MONTH, newVal - oldVal); + } + } else if (picker == yearSpinner) { + tempDate.set(Calendar.YEAR, newVal); + } else { + return; + } + setDate(tempDate.get(Calendar.YEAR), tempDate.get(Calendar.MONTH), + tempDate.get(Calendar.DAY_OF_MONTH)); + updateSpinners(); + updateCalendarView(); + notifyDateChanged(); + } + + } + + public interface OnDateChangedListener { + void onDateChanged(DatePicker view, int year, int monthOfYear, + int dayOfMonth); + } + + private static class SavedState extends BaseSavedState { + @SuppressWarnings("all") + public static final Creator<SavedState> CREATOR = new Creator<SavedState>() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + + private final int year, month, day; + + private SavedState(Parcel in) { + super(in); + year = in.readInt(); + month = in.readInt(); + day = in.readInt(); + } + + private SavedState(Parcelable superState, int year, int month, int day) { + super(superState); + this.year = year; + this.month = month; + this.day = day; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(year); + dest.writeInt(month); + dest.writeInt(day); + } + } + + private static final String DATE_FORMAT = "MM/dd/yyyy"; + private static final String LOG_TAG = DatePicker.class.getSimpleName(); + + private static Calendar getCalendarForLocale(Calendar oldCalendar, + Locale locale) { + if (oldCalendar == null) { + return Calendar.getInstance(locale); + } else { + final long currentTimeMillis = oldCalendar.getTimeInMillis(); + Calendar newCalendar = Calendar.getInstance(locale); + newCalendar.setTimeInMillis(currentTimeMillis); + return newCalendar; + } + } + + private static void setContentDescription(View parent, int childId, + int textId) { + if (parent == null) { + return; + } + View child = parent.findViewById(childId); + if (child != null) { + child.setContentDescription(parent.getContext().getText(textId)); + } + } + + private final Callback callback = new Callback(); + private final java.text.DateFormat dateFormat = new SimpleDateFormat( + DatePicker.DATE_FORMAT); + private final NumberPicker daySpinner, monthSpinner, yearSpinner; + private final InputMethodManager inputMethodManager; + private Locale locale; + private final CalendarView mCalendarView; + private int numberOfMonths; + private OnDateChangedListener onDateChangedListener; + private String[] shortMonths; + private final LinearLayout spinners; + private Calendar tempDate, minDate, maxDate, currentDate; + + public DatePicker(Context context) { + this(context, null); + } + + public DatePicker(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.datePickerStyle); + } + + public DatePicker(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.DatePicker, defStyle, R.style.Holo_DatePicker); + boolean spinnersShown = a.getBoolean( + R.styleable.DatePicker_spinnersShown, true); + boolean calendarViewShown = a.getBoolean( + R.styleable.DatePicker_calendarViewShown, true); + boolean forceShownState = a.getBoolean( + R.styleable.DatePicker_forceShownState, false); + int startYear = a.getInt(R.styleable.DatePicker_startYear, 1900); + int endYear = a.getInt(R.styleable.DatePicker_endYear, 2100); + String minDate = a.getString(R.styleable.DatePicker_minDate); + String maxDate = a.getString(R.styleable.DatePicker_maxDate); + int layoutResourceId = a.getResourceId(R.styleable.DatePicker_layout, + R.layout.date_picker_holo); + a.recycle(); + inputMethodManager = (InputMethodManager) context + .getSystemService(Context.INPUT_METHOD_SERVICE); + setLocale(Locale.getDefault()); + LayoutInflater.inflate(context, layoutResourceId, this, true); + spinners = (LinearLayout) findViewById(R.id.pickers); + mCalendarView = (CalendarView) findViewById(R.id.calendar_view); + daySpinner = (NumberPicker) findViewById(R.id.day); + monthSpinner = (NumberPicker) findViewById(R.id.month); + yearSpinner = (NumberPicker) findViewById(R.id.year); + if (((AccessibilityManager) getContext().getSystemService( + Context.ACCESSIBILITY_SERVICE)).isEnabled()) { + setContentDescriptions(); + } + mCalendarView.setOnDateChangeListener(callback); + daySpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); + daySpinner.setOnLongPressUpdateInterval(100); + daySpinner.setOnValueChangedListener(callback); + monthSpinner.setMinValue(0); + monthSpinner.setMaxValue(numberOfMonths - 1); + monthSpinner.setDisplayedValues(shortMonths); + monthSpinner.setOnLongPressUpdateInterval(200); + monthSpinner.setOnValueChangedListener(callback); + yearSpinner.setOnLongPressUpdateInterval(100); + yearSpinner.setOnValueChangedListener(callback); + if (spinnersShown || calendarViewShown || forceShownState) { + setSpinnersShown(spinnersShown); + setCalendarViewShown(calendarViewShown); + } else { + setSpinnersShown(true); + setCalendarViewShown(false); + } + tempDate.clear(); + if (TextUtils.isEmpty(minDate) || !parseDate(minDate, tempDate)) { + tempDate.set(startYear, 0, 1); + } + setMinDate(tempDate.getTimeInMillis()); + tempDate.clear(); + if (TextUtils.isEmpty(maxDate) || !parseDate(maxDate, tempDate)) { + tempDate.set(endYear, 11, 31); + } + setMaxDate(tempDate.getTimeInMillis()); + currentDate.setTimeInMillis(System.currentTimeMillis()); + init(currentDate.get(Calendar.YEAR), currentDate.get(Calendar.MONTH), + currentDate.get(Calendar.DAY_OF_MONTH), null); + reorderSpinners(); + } + + private void checkInputState(NumberPicker... spinners) { + for (NumberPicker spinner : spinners) { + NumberPickerEditText input = spinner.getInputField(); + if (inputMethodManager.isActive(input)) { + input.clearFocus(); + inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); + } + } + } + + @SuppressLint("NewApi") + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + onPopulateAccessibilityEvent(event); + return true; + } + + @Override + protected void dispatchRestoreInstanceState( + SparseArray<Parcelable> container) { + dispatchThawSelfOnly(container); + } + + public CalendarView getCalendarView() { + return mCalendarView; + } + + public boolean getCalendarViewShown() { + return mCalendarView.isShown(); + } + + public int getDayOfMonth() { + return currentDate.get(Calendar.DAY_OF_MONTH); + } + + public long getMaxDate() { + return mCalendarView.getMaxDate(); + } + + public long getMinDate() { + return mCalendarView.getMinDate(); + } + + public int getMonth() { + return currentDate.get(Calendar.MONTH); + } + + public OnDateChangedListener getOnDateChangedListener() { + return onDateChangedListener; + } + + public boolean getSpinnersShown() { + return spinners.isShown(); + } + + public int getYear() { + return currentDate.get(Calendar.YEAR); + } + + public void init(int year, int monthOfYear, int dayOfMonth, + OnDateChangedListener onDateChangedListener) { + setOnDateChangedListener(onDateChangedListener); + setDate(year, monthOfYear, dayOfMonth); + updateSpinners(); + updateCalendarView(); + } + + private boolean isNewDate(int year, int month, int dayOfMonth) { + return currentDate.get(Calendar.YEAR) != year + || currentDate.get(Calendar.MONTH) != dayOfMonth + || currentDate.get(Calendar.DAY_OF_MONTH) != month; + } + + private void notifyDateChanged() { + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + if (onDateChangedListener != null) { + onDateChangedListener.onDateChanged(this, getYear(), getMonth(), + getDayOfMonth()); + } + } + + @Override + @SuppressLint("NewApi") + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + setLocale(newConfig.locale); + } + + @SuppressLint("NewApi") + @Override + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + if (VERSION.SDK_INT >= 14) { + super.onPopulateAccessibilityEvent(event); + } + final int flags = DateUtils.FORMAT_SHOW_DATE + | DateUtils.FORMAT_SHOW_YEAR; + String selectedDateUtterance = DateUtils.formatDateTime(getContext(), + currentDate.getTimeInMillis(), flags); + event.getText().add(selectedDateUtterance); + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + setDate(ss.year, ss.month, ss.day); + updateSpinners(); + updateCalendarView(); + } + + @Override + protected Parcelable onSaveInstanceState() { + return new SavedState(super.onSaveInstanceState(), getYear(), + getMonth(), getDayOfMonth()); + } + + private boolean parseDate(String date, Calendar outDate) { + try { + outDate.setTime(dateFormat.parse(date)); + return true; + } catch (ParseException e) { + Log.w(DatePicker.LOG_TAG, "Date: " + date + " not in format: " + + DatePicker.DATE_FORMAT); + return false; + } + } + + private void pushSpinner(NumberPicker spinner, int spinnerCount, int i) { + if (spinner.getParent() != null + && spinner.getParent() instanceof ViewGroup) { + ViewGroup parent = (ViewGroup) spinner.getParent(); + if (parent.getChildAt(i) != spinner) { + parent.removeView(spinner); + parent.addView(spinner); + setImeOptions(spinner, spinnerCount, i); + } + } + } + + private void reorderSpinners() { + char[] order = DateFormat.getDateFormatOrder(getContext()); + final int spinnerCount = order.length; + for (int i = 0; i < spinnerCount; i++) { + switch (order[i]) { + case DateFormat.DATE: + pushSpinner(daySpinner, spinnerCount, i); + break; + case DateFormat.MONTH: + pushSpinner(monthSpinner, spinnerCount, i); + break; + case DateFormat.YEAR: + pushSpinner(yearSpinner, spinnerCount, i); + break; + } + } + } + + public void setCalendarViewShown(boolean shown) { + mCalendarView.setVisibility(shown ? View.VISIBLE : View.GONE); + } + + private void setContentDescriptions() { + DatePicker.setContentDescription(daySpinner, R.id.increment, + R.string.date_picker_increment_day_button); + DatePicker.setContentDescription(daySpinner, R.id.decrement, + R.string.date_picker_decrement_day_button); + DatePicker.setContentDescription(monthSpinner, R.id.increment, + R.string.date_picker_increment_month_button); + DatePicker.setContentDescription(monthSpinner, R.id.decrement, + R.string.date_picker_decrement_month_button); + DatePicker.setContentDescription(yearSpinner, R.id.increment, + R.string.date_picker_increment_year_button); + DatePicker.setContentDescription(yearSpinner, R.id.decrement, + R.string.date_picker_decrement_year_button); + } + + private void setDate(int year, int month, int dayOfMonth) { + currentDate.set(year, month, dayOfMonth); + if (currentDate.before(minDate)) { + currentDate.setTimeInMillis(minDate.getTimeInMillis()); + } else if (currentDate.after(maxDate)) { + currentDate.setTimeInMillis(maxDate.getTimeInMillis()); + } + } + + @Override + public void setEnabled(boolean enabled) { + if (isEnabled() == enabled) { + return; + } + super.setEnabled(enabled); + daySpinner.setEnabled(enabled); + monthSpinner.setEnabled(enabled); + yearSpinner.setEnabled(enabled); + mCalendarView.setEnabled(enabled); + } + + private void setImeOptions(NumberPicker spinner, int spinnerCount, + int spinnerIndex) { + final int imeOptions; + if (spinnerIndex < spinnerCount - 1) { + imeOptions = EditorInfo.IME_ACTION_NEXT; + } else { + imeOptions = EditorInfo.IME_ACTION_DONE; + } + spinner.getInputField().setImeOptions(imeOptions); + } + + public void setLocale(Locale locale) { + if (locale == null || locale.equals(this.locale)) { + return; + } + this.locale = locale; + tempDate = DatePicker.getCalendarForLocale(tempDate, locale); + minDate = DatePicker.getCalendarForLocale(minDate, locale); + maxDate = DatePicker.getCalendarForLocale(maxDate, locale); + currentDate = DatePicker.getCalendarForLocale(currentDate, locale); + numberOfMonths = tempDate.getActualMaximum(Calendar.MONTH) + 1; + shortMonths = new String[numberOfMonths]; + for (int i = 0; i < numberOfMonths; i++) { + shortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i, + DateUtils.LENGTH_MEDIUM); + } + } + + public void setMaxDate(long maxDateL) { + tempDate.setTimeInMillis(maxDateL); + if (tempDate.get(Calendar.YEAR) == maxDate.get(Calendar.YEAR) + && tempDate.get(Calendar.DAY_OF_YEAR) == maxDate + .get(Calendar.DAY_OF_YEAR)) { + return; + } + maxDate.setTimeInMillis(maxDateL); + mCalendarView.setMaxDate(maxDateL); + if (currentDate.after(maxDate)) { + currentDate.setTimeInMillis(maxDate.getTimeInMillis()); + updateCalendarView(); + } + updateSpinners(); + } + + public void setMinDate(long minDateL) { + tempDate.setTimeInMillis(minDateL); + if (tempDate.get(Calendar.YEAR) == minDate.get(Calendar.YEAR) + && tempDate.get(Calendar.DAY_OF_YEAR) == minDate + .get(Calendar.DAY_OF_YEAR)) { + return; + } + minDate.setTimeInMillis(minDateL); + mCalendarView.setMinDate(minDateL); + if (currentDate.before(minDate)) { + currentDate.setTimeInMillis(minDate.getTimeInMillis()); + updateCalendarView(); + } + updateSpinners(); + } + + public void setOnDateChangedListener( + OnDateChangedListener onDateChangedListener) { + this.onDateChangedListener = onDateChangedListener; + } + + public void setSpinnersShown(boolean shown) { + spinners.setVisibility(shown ? View.VISIBLE : View.GONE); + } + + private void updateCalendarView() { + mCalendarView.setDate(currentDate.getTimeInMillis(), false, false); + } + + public void updateDate(int year, int month, int dayOfMonth) { + if (!isNewDate(year, month, dayOfMonth)) { + return; + } + setDate(year, month, dayOfMonth); + updateSpinners(); + updateCalendarView(); + notifyDateChanged(); + } + + private void updateInputState() { + if (inputMethodManager != null) { + checkInputState(yearSpinner, monthSpinner, daySpinner); + } + } + + private void updateSpinners() { + monthSpinner.setDisplayedValues(null); + if (currentDate.equals(minDate)) { + daySpinner.setMinValue(currentDate.get(Calendar.DAY_OF_MONTH)); + daySpinner.setMaxValue(currentDate + .getActualMaximum(Calendar.DAY_OF_MONTH)); + daySpinner.setWrapSelectorWheel(false); + monthSpinner.setMinValue(currentDate.get(Calendar.MONTH)); + monthSpinner.setMaxValue(currentDate + .getActualMaximum(Calendar.MONTH)); + monthSpinner.setWrapSelectorWheel(false); + } else if (currentDate.equals(maxDate)) { + daySpinner.setMinValue(currentDate + .getActualMinimum(Calendar.DAY_OF_MONTH)); + daySpinner.setMaxValue(currentDate.get(Calendar.DAY_OF_MONTH)); + daySpinner.setWrapSelectorWheel(false); + monthSpinner.setMinValue(currentDate + .getActualMinimum(Calendar.MONTH)); + monthSpinner.setMaxValue(currentDate.get(Calendar.MONTH)); + monthSpinner.setWrapSelectorWheel(false); + } else { + daySpinner.setMinValue(1); + daySpinner.setMaxValue(currentDate + .getActualMaximum(Calendar.DAY_OF_MONTH)); + daySpinner.setWrapSelectorWheel(true); + monthSpinner.setMinValue(0); + monthSpinner.setMaxValue(11); + monthSpinner.setWrapSelectorWheel(true); + } + String[] displayedValues = Arrays.copyOfRange(shortMonths, + monthSpinner.getMinValue(), monthSpinner.getMaxValue() + 1); + monthSpinner.setDisplayedValues(displayedValues); + yearSpinner.setMinValue(minDate.get(Calendar.YEAR)); + yearSpinner.setMaxValue(maxDate.get(Calendar.YEAR)); + yearSpinner.setWrapSelectorWheel(false); + yearSpinner.setValue(currentDate.get(Calendar.YEAR)); + monthSpinner.setValue(currentDate.get(Calendar.MONTH)); + daySpinner.setValue(currentDate.get(Calendar.DAY_OF_MONTH)); + } +} |