Index: content/public/android/java/src/org/chromium/content/browser/input/WeekPicker.java |
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/WeekPicker.java b/content/public/android/java/src/org/chromium/content/browser/input/WeekPicker.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..cbcb3654074da85520840b233d98b60d92f93e36 |
--- /dev/null |
+++ b/content/public/android/java/src/org/chromium/content/browser/input/WeekPicker.java |
@@ -0,0 +1,330 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.content.browser.input; |
+ |
+import android.content.Context; |
+import android.content.res.Configuration; |
+import android.os.Parcel; |
+import android.os.Parcelable; |
+import android.text.format.DateUtils; |
+import android.util.AttributeSet; |
+import android.util.SparseArray; |
+import android.view.LayoutInflater; |
+import android.view.accessibility.AccessibilityEvent; |
+import android.widget.NumberPicker; |
+import android.widget.NumberPicker.OnValueChangeListener; |
+ |
+import java.text.DateFormatSymbols; |
+import java.util.Arrays; |
+import java.util.Calendar; |
+import java.util.Locale; |
+ |
+import org.chromium.content.R; |
+ |
+// This class is heavily based on android.widget.DatePicker. |
+public class WeekPicker extends BaseDatePicker { |
+ |
+ private final NumberPicker mWeekSpinner; |
+ |
+ private final NumberPicker mYearSpinner; |
+ |
+ private OnWeekChangedListener mWeekChangedListener; |
+ |
+ /** |
+ * The callback used to indicate the user changes\d the date. |
+ */ |
+ public interface OnWeekChangedListener { |
+ |
+ /** |
+ * Called upon a date change. |
+ * |
+ * @param view The view associated with this listener. |
+ * @param year The year that was set. |
+ * @param weekOfYear The week in year. |
+ */ |
+ void onWeekChanged(WeekPicker view, int year, int weekOfYear); |
+ } |
+ |
+ public WeekPicker(Context context) { |
+ this(context, null); |
+ } |
+ |
+ public WeekPicker(Context context, AttributeSet attrs) { |
+ this(context, attrs, android.R.attr.datePickerStyle); |
+ } |
+ |
+ public WeekPicker(Context context, AttributeSet attrs, int defStyle) { |
+ super(context, attrs, defStyle); |
+ |
+ LayoutInflater inflater = (LayoutInflater) context |
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
+ inflater.inflate(R.layout.week_picker, this, true); |
+ |
+ OnValueChangeListener onChangeListener = new OnValueChangeListener() { |
+ @Override |
+ public void onValueChange(NumberPicker picker, int oldVal, int newVal) { |
+ // take care of wrapping of weeks to update greater fields |
+ if (picker == mWeekSpinner) { |
+ Calendar tempDate = (Calendar) mCurrentDate.clone(); |
+ if (oldVal == mWeekSpinner.getMaxValue() |
+ && newVal == mWeekSpinner.getMinValue()) { |
+ tempDate.add(Calendar.WEEK_OF_YEAR, 1); |
+ } else if (oldVal == mWeekSpinner.getMinValue() |
+ && newVal == mWeekSpinner.getMaxValue()) { |
+ tempDate.add(Calendar.WEEK_OF_YEAR, -1); |
+ } else { |
+ tempDate.add(Calendar.WEEK_OF_YEAR, newVal - oldVal); |
+ } |
+ // now set the date to the adjusted one |
+ setDate(getISOWeekYearForDate(tempDate), |
+ getWeekForDate(tempDate)); |
+ } else if (picker == mYearSpinner) { |
+ setDate(newVal, getWeekForDate(mCurrentDate)); |
+ } else { |
+ throw new IllegalArgumentException(); |
+ } |
+ |
+ updateSpinners(); |
+ notifyDateChanged(); |
+ } |
+ }; |
+ |
+ // week |
+ mWeekSpinner = (NumberPicker) findViewById(R.id.week); |
+ mWeekSpinner.setOnLongPressUpdateInterval(200); |
+ mWeekSpinner.setOnValueChangedListener(onChangeListener); |
+ |
+ // year |
+ mYearSpinner = (NumberPicker) findViewById(R.id.year); |
+ mYearSpinner.setOnLongPressUpdateInterval(100); |
+ mYearSpinner.setOnValueChangedListener(onChangeListener); |
+ |
+ // initialize to current date |
+ mCurrentDate.setTimeInMillis(System.currentTimeMillis()); |
+ init(getISOWeekYearForDate(mCurrentDate), getWeekForDate(mCurrentDate), null); |
+ } |
+ |
+ @Override |
+ public void setEnabled(boolean enabled) { |
+ if (mIsEnabled == enabled) { |
+ return; |
+ } |
+ super.setEnabled(enabled); |
+ mWeekSpinner.setEnabled(enabled); |
+ mYearSpinner.setEnabled(enabled); |
+ } |
+ |
+ @Override |
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { |
+ onPopulateAccessibilityEvent(event); |
+ return true; |
+ } |
+ |
+ @Override |
+ public void onPopulateAccessibilityEvent(AccessibilityEvent event) { |
+ super.onPopulateAccessibilityEvent(event); |
+ |
+ final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR; |
+ String selectedDateUtterance = DateUtils.formatDateTime(getContext(), |
+ mCurrentDate.getTimeInMillis(), flags); |
+ event.getText().add(selectedDateUtterance); |
+ } |
+ |
+ @Override |
+ protected void onConfigurationChanged(Configuration newConfig) { |
+ super.onConfigurationChanged(newConfig); |
+ setCurrentLocale(newConfig.locale); |
+ } |
+ |
+ /** |
+ * Updates the current date. |
+ * |
+ * @param year The year. |
+ * @param week The week in year. |
+ */ |
+ public void updateWeek(int year, int week) { |
+ if (!isNewDate(year, week)) { |
+ return; |
+ } |
+ setDate(year, week); |
+ updateSpinners(); |
+ notifyDateChanged(); |
+ } |
+ |
+ // Override so we are in complete control of save / restore for this widget. |
+ @Override |
+ protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { |
+ dispatchThawSelfOnly(container); |
+ } |
+ |
+ @Override |
+ protected Parcelable onSaveInstanceState() { |
+ Parcelable superState = super.onSaveInstanceState(); |
+ return new SavedState(superState, getYear(), getWeek()); |
+ } |
+ |
+ @Override |
+ protected void onRestoreInstanceState(Parcelable state) { |
+ SavedState ss = (SavedState) state; |
+ super.onRestoreInstanceState(ss.getSuperState()); |
+ setDate(ss.mYear, ss.mWeek); |
+ updateSpinners(); |
+ } |
+ |
+ /** |
+ * Initialize the state. If the provided values designate an inconsistent |
+ * date the values are normalized before updating the spinners. |
+ * |
+ * @param year The initial week year. |
+ * @param weekOfYear The initial week in year. |
+ * @param onWeekChangedListener How user is notified date is changed by |
+ * user, can be null. |
+ */ |
+ public void init(int year, int weekOfYear, OnWeekChangedListener onWeekChangedListener) { |
+ setDate(year, weekOfYear); |
+ updateSpinners(); |
+ mWeekChangedListener = onWeekChangedListener; |
+ } |
+ |
+ private boolean isNewDate(int year, int week) { |
+ return (getYear() != year || getWeek() != week); |
+ } |
+ |
+ private Calendar createDateFromWeek(int year, int week) { |
+ Calendar date = getCalendarForLocale(null, mCurrentLocale); |
+ date.set(Calendar.YEAR, year); |
+ date.set(Calendar.WEEK_OF_YEAR, week); |
+ return date; |
+ } |
+ |
+ public static int getISOWeekYearForDate(Calendar date) { |
+ int year = date.get(Calendar.YEAR); |
+ int month = date.get(Calendar.MONTH); |
+ int week = date.get(Calendar.WEEK_OF_YEAR); |
+ if (month == 0 && week > 51) { |
+ year--; |
+ } else if (month == 11 && week == 1) { |
+ year++; |
+ } |
+ return year; |
+ } |
+ |
+ public static int getWeekForDate(Calendar date) { |
+ return date.get(Calendar.WEEK_OF_YEAR); |
+ } |
+ |
+ private void setDate(int year, int week) { |
+ mCurrentDate = createDateFromWeek(year, week); |
+ if (mCurrentDate.before(mMinDate)) { |
+ mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis()); |
+ } else if (mCurrentDate.after(mMaxDate)) { |
+ mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis()); |
+ } |
+ } |
+ |
+ private int getNumberOfWeeks() { |
+ // Create a date in the middle of the year, where the week year matches the year. |
+ Calendar date = createDateFromWeek(getYear(), 20); |
+ return date.getActualMaximum(Calendar.WEEK_OF_YEAR); |
+ } |
+ |
+ private void updateSpinners() { |
+ // set the spinner ranges respecting the min and max dates |
+ if (mCurrentDate.equals(mMinDate)) { |
+ mWeekSpinner.setMinValue(getWeekForDate(mCurrentDate)); |
+ mWeekSpinner.setMaxValue(getNumberOfWeeks()); |
+ mWeekSpinner.setWrapSelectorWheel(false); |
+ } else if (mCurrentDate.equals(mMaxDate)) { |
+ mWeekSpinner.setMinValue(getNumberOfWeeks()); |
+ mWeekSpinner.setMaxValue(getWeekForDate(mCurrentDate)); |
+ mWeekSpinner.setWrapSelectorWheel(false); |
+ } else { |
+ mWeekSpinner.setMinValue(1); |
+ mWeekSpinner.setMaxValue(getNumberOfWeeks()); |
+ mWeekSpinner.setWrapSelectorWheel(true); |
+ } |
+ |
+ // year spinner range does not change based on the current date |
+ mYearSpinner.setMinValue(getISOWeekYearForDate(mMinDate)); |
+ mYearSpinner.setMaxValue(getISOWeekYearForDate(mMaxDate)); |
+ mYearSpinner.setWrapSelectorWheel(false); |
+ |
+ // set the spinner values |
+ mYearSpinner.setValue(getISOWeekYearForDate(mCurrentDate)); |
+ mWeekSpinner.setValue(getWeekForDate(mCurrentDate)); |
+ } |
+ |
+ /** |
+ * @return The selected year. |
+ */ |
+ public int getYear() { |
+ return getISOWeekYearForDate(mCurrentDate); |
+ } |
+ |
+ /** |
+ * @return The selected week. |
+ */ |
+ public int getWeek() { |
+ return getWeekForDate(mCurrentDate); |
+ } |
+ |
+ /** |
+ * Notifies the listener, if such, for a change in the selected date. |
+ */ |
+ private void notifyDateChanged() { |
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); |
+ if (mWeekChangedListener != null) { |
+ mWeekChangedListener.onWeekChanged(this, getYear(), getWeek()); |
+ } |
+ } |
+ |
+ /** |
+ * Class for managing state storing/restoring. |
+ */ |
+ private static class SavedState extends BaseSavedState { |
+ |
+ private final int mYear; |
+ |
+ private final int mWeek; |
+ |
+ /** |
+ * Constructor called from {@link DatePicker#onSaveInstanceState()} |
+ */ |
+ private SavedState(Parcelable superState, int year, int week) { |
+ super(superState); |
+ mYear = year; |
+ mWeek = week; |
+ } |
+ |
+ /** |
+ * Constructor called from {@link #CREATOR} |
+ */ |
+ private SavedState(Parcel in) { |
+ super(in); |
+ mYear = in.readInt(); |
+ mWeek = in.readInt(); |
+ } |
+ |
+ @Override |
+ public void writeToParcel(Parcel dest, int flags) { |
+ super.writeToParcel(dest, flags); |
+ dest.writeInt(mYear); |
+ dest.writeInt(mWeek); |
+ } |
+ |
+ @SuppressWarnings("all") |
+ // suppress unused and hiding |
+ public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() { |
+ |
+ public SavedState createFromParcel(Parcel in) { |
+ return new SavedState(in); |
+ } |
+ |
+ public SavedState[] newArray(int size) { |
+ return new SavedState[size]; |
+ } |
+ }; |
+ } |
+} |