diff options
author | Alan Viverette <alanv@google.com> | 2015-03-23 13:13:25 -0700 |
---|---|---|
committer | Alan Viverette <alanv@google.com> | 2015-03-23 13:13:25 -0700 |
commit | 0ef59ac0e57e9b99d174d4a53f7d9639357743ac (patch) | |
tree | ab71b8c3506571d5ce39a27bd7bb7a3ed1e65a21 /core | |
parent | 2a16460c7c914729e9c256ce39d681524d53b7dc (diff) | |
download | frameworks_base-0ef59ac0e57e9b99d174d4a53f7d9639357743ac.zip frameworks_base-0ef59ac0e57e9b99d174d4a53f7d9639357743ac.tar.gz frameworks_base-0ef59ac0e57e9b99d174d4a53f7d9639357743ac.tar.bz2 |
Update DatePicker and CalendarView to latest Material spec
Bug: 19431364
Change-Id: If364a051a5208d170495de4182e46b32c7560e08
Diffstat (limited to 'core')
30 files changed, 1759 insertions, 1861 deletions
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java index 841b09d..7d8dff3 100644 --- a/core/java/android/content/res/ColorStateList.java +++ b/core/java/android/content/res/ColorStateList.java @@ -464,6 +464,33 @@ public class ColorStateList implements Parcelable { return mColors; } + /** + * Returns whether the specified state is referenced in any of the state + * specs contained within this ColorStateList. + * <p> + * Any reference, either positive or negative {ex. ~R.attr.state_enabled}, + * will cause this method to return {@code true}. Wildcards are not counted + * as references. + * + * @param state the state to search for + * @return {@code true} if the state if referenced, {@code false} otherwise + * @hide Use only as directed. For internal use only. + */ + public boolean hasState(int state) { + final int[][] stateSpecs = mStateSpecs; + final int specCount = stateSpecs.length; + for (int specIndex = 0; specIndex < specCount; specIndex++) { + final int[] states = stateSpecs[specIndex]; + final int stateCount = states.length; + for (int stateIndex = 0; stateIndex < stateCount; stateIndex++) { + if (states[stateIndex] == state || states[stateIndex] == ~state) { + return true; + } + } + } + return false; + } + @Override public String toString() { return "ColorStateList{" + diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java index 5bc16cb..2aaa356 100644 --- a/core/java/android/widget/CalendarView.java +++ b/core/java/android/widget/CalendarView.java @@ -18,6 +18,7 @@ package android.widget; import android.annotation.ColorInt; import android.annotation.DrawableRes; +import android.annotation.StyleRes; import android.annotation.Widget; import android.content.Context; import android.content.res.Configuration; @@ -31,6 +32,7 @@ import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; +import java.util.Date; import java.util.Locale; import java.util.TimeZone; @@ -118,7 +120,9 @@ public class CalendarView extends FrameLayout { * @param count The shown week count. * * @attr ref android.R.styleable#CalendarView_shownWeekCount + * @deprecated No longer used by Material-style CalendarView. */ + @Deprecated public void setShownWeekCount(int count) { mDelegate.setShownWeekCount(count); } @@ -129,7 +133,9 @@ public class CalendarView extends FrameLayout { * @return The shown week count. * * @attr ref android.R.styleable#CalendarView_shownWeekCount + * @deprecated No longer used by Material-style CalendarView. */ + @Deprecated public int getShownWeekCount() { return mDelegate.getShownWeekCount(); } @@ -140,7 +146,9 @@ public class CalendarView extends FrameLayout { * @param color The week background color. * * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor + * @deprecated No longer used by Material-style CalendarView. */ + @Deprecated public void setSelectedWeekBackgroundColor(@ColorInt int color) { mDelegate.setSelectedWeekBackgroundColor(color); } @@ -151,8 +159,10 @@ public class CalendarView extends FrameLayout { * @return The week background color. * * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor + * @deprecated No longer used by Material-style CalendarView. */ @ColorInt + @Deprecated public int getSelectedWeekBackgroundColor() { return mDelegate.getSelectedWeekBackgroundColor(); } @@ -163,7 +173,9 @@ public class CalendarView extends FrameLayout { * @param color The focused month date color. * * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor + * @deprecated No longer used by Material-style CalendarView. */ + @Deprecated public void setFocusedMonthDateColor(@ColorInt int color) { mDelegate.setFocusedMonthDateColor(color); } @@ -174,8 +186,10 @@ public class CalendarView extends FrameLayout { * @return The focused month date color. * * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor + * @deprecated No longer used by Material-style CalendarView. */ @ColorInt + @Deprecated public int getFocusedMonthDateColor() { return mDelegate.getFocusedMonthDateColor(); } @@ -186,7 +200,9 @@ public class CalendarView extends FrameLayout { * @param color A not focused month date color. * * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor + * @deprecated No longer used by Material-style CalendarView. */ + @Deprecated public void setUnfocusedMonthDateColor(@ColorInt int color) { mDelegate.setUnfocusedMonthDateColor(color); } @@ -197,8 +213,10 @@ public class CalendarView extends FrameLayout { * @return A not focused month date color. * * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor + * @deprecated No longer used by Material-style CalendarView. */ @ColorInt + @Deprecated public int getUnfocusedMonthDateColor() { return mDelegate.getUnfocusedMonthDateColor(); } @@ -209,7 +227,9 @@ public class CalendarView extends FrameLayout { * @param color The week number color. * * @attr ref android.R.styleable#CalendarView_weekNumberColor + * @deprecated No longer used by Material-style CalendarView. */ + @Deprecated public void setWeekNumberColor(@ColorInt int color) { mDelegate.setWeekNumberColor(color); } @@ -220,8 +240,10 @@ public class CalendarView extends FrameLayout { * @return The week number color. * * @attr ref android.R.styleable#CalendarView_weekNumberColor + * @deprecated No longer used by Material-style CalendarView. */ @ColorInt + @Deprecated public int getWeekNumberColor() { return mDelegate.getWeekNumberColor(); } @@ -232,7 +254,9 @@ public class CalendarView extends FrameLayout { * @param color The week separator color. * * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor + * @deprecated No longer used by Material-style CalendarView. */ + @Deprecated public void setWeekSeparatorLineColor(@ColorInt int color) { mDelegate.setWeekSeparatorLineColor(color); } @@ -243,8 +267,10 @@ public class CalendarView extends FrameLayout { * @return The week separator color. * * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor + * @deprecated No longer used by Material-style CalendarView. */ @ColorInt + @Deprecated public int getWeekSeparatorLineColor() { return mDelegate.getWeekSeparatorLineColor(); } @@ -256,7 +282,9 @@ public class CalendarView extends FrameLayout { * @param resourceId The vertical bar drawable resource id. * * @attr ref android.R.styleable#CalendarView_selectedDateVerticalBar + * @deprecated No longer used by Material-style CalendarView. */ + @Deprecated public void setSelectedDateVerticalBar(@DrawableRes int resourceId) { mDelegate.setSelectedDateVerticalBar(resourceId); } @@ -268,7 +296,9 @@ public class CalendarView extends FrameLayout { * @param drawable The vertical bar drawable. * * @attr ref android.R.styleable#CalendarView_selectedDateVerticalBar + * @deprecated No longer used by Material-style CalendarView. */ + @Deprecated public void setSelectedDateVerticalBar(Drawable drawable) { mDelegate.setSelectedDateVerticalBar(drawable); } @@ -278,7 +308,9 @@ public class CalendarView extends FrameLayout { * the end of the selected date. * * @return The vertical bar drawable. + * @deprecated No longer used by Material-style CalendarView. */ + @Deprecated public Drawable getSelectedDateVerticalBar() { return mDelegate.getSelectedDateVerticalBar(); } @@ -519,29 +551,36 @@ public class CalendarView extends FrameLayout { void setShownWeekCount(int count); int getShownWeekCount(); - void setSelectedWeekBackgroundColor(int color); + void setSelectedWeekBackgroundColor(@ColorInt int color); + @ColorInt int getSelectedWeekBackgroundColor(); - void setFocusedMonthDateColor(int color); + void setFocusedMonthDateColor(@ColorInt int color); + @ColorInt int getFocusedMonthDateColor(); - void setUnfocusedMonthDateColor(int color); + void setUnfocusedMonthDateColor(@ColorInt int color); + @ColorInt int getUnfocusedMonthDateColor(); - void setWeekNumberColor(int color); + void setWeekNumberColor(@ColorInt int color); + @ColorInt int getWeekNumberColor(); - void setWeekSeparatorLineColor(int color); + void setWeekSeparatorLineColor(@ColorInt int color); + @ColorInt int getWeekSeparatorLineColor(); - void setSelectedDateVerticalBar(int resourceId); + void setSelectedDateVerticalBar(@DrawableRes int resourceId); void setSelectedDateVerticalBar(Drawable drawable); Drawable getSelectedDateVerticalBar(); - void setWeekDayTextAppearance(int resourceId); + void setWeekDayTextAppearance(@StyleRes int resourceId); + @StyleRes int getWeekDayTextAppearance(); - void setDateTextAppearance(int resourceId); + void setDateTextAppearance(@StyleRes int resourceId); + @StyleRes int getDateTextAppearance(); void setMinDate(long minDate); @@ -569,18 +608,12 @@ public class CalendarView extends FrameLayout { * An abstract class which can be used as a start for CalendarView implementations */ abstract static class AbstractCalendarViewDelegate implements CalendarViewDelegate { - /** String for parsing dates. */ - private static final String DATE_FORMAT = "MM/dd/yyyy"; - /** The default minimal date. */ protected static final String DEFAULT_MIN_DATE = "01/01/1900"; /** The default maximal date. */ protected static final String DEFAULT_MAX_DATE = "01/01/2100"; - /** Date format for parsing dates. */ - protected static final DateFormat DATE_FORMATTER = new SimpleDateFormat(DATE_FORMAT); - protected CalendarView mDelegator; protected Context mContext; protected Locale mCurrentLocale; @@ -600,21 +633,131 @@ public class CalendarView extends FrameLayout { mCurrentLocale = locale; } - /** - * Parses the given <code>date</code> and in case of success sets - * the result to the <code>outDate</code>. - * - * @return True if the date was parsed. - */ - protected boolean parseDate(String date, Calendar outDate) { - try { - outDate.setTime(DATE_FORMATTER.parse(date)); - return true; - } catch (ParseException e) { - Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT); - return false; - } + @Override + public void setShownWeekCount(int count) { + // Deprecated. + } + + @Override + public int getShownWeekCount() { + // Deprecated. + return 0; + } + + @Override + public void setSelectedWeekBackgroundColor(@ColorInt int color) { + // Deprecated. + } + + @ColorInt + @Override + public int getSelectedWeekBackgroundColor() { + return 0; + } + + @Override + public void setFocusedMonthDateColor(@ColorInt int color) { + // Deprecated. + } + + @ColorInt + @Override + public int getFocusedMonthDateColor() { + return 0; + } + + @Override + public void setUnfocusedMonthDateColor(@ColorInt int color) { + // Deprecated. + } + + @ColorInt + @Override + public int getUnfocusedMonthDateColor() { + return 0; + } + + @Override + public void setWeekNumberColor(@ColorInt int color) { + // Deprecated. + } + + @ColorInt + @Override + public int getWeekNumberColor() { + // Deprecated. + return 0; + } + + @Override + public void setWeekSeparatorLineColor(@ColorInt int color) { + // Deprecated. + } + + @ColorInt + @Override + public int getWeekSeparatorLineColor() { + // Deprecated. + return 0; + } + + @Override + public void setSelectedDateVerticalBar(@DrawableRes int resId) { + // Deprecated. + } + + @Override + public void setSelectedDateVerticalBar(Drawable drawable) { + // Deprecated. + } + + @Override + public Drawable getSelectedDateVerticalBar() { + // Deprecated. + return null; + } + + @Override + public void setShowWeekNumber(boolean showWeekNumber) { + // Deprecated. + } + + @Override + public boolean getShowWeekNumber() { + // Deprecated. + return false; + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + // Nothing to do here, configuration changes are already propagated + // by ViewGroup. } } + /** String for parsing dates. */ + private static final String DATE_FORMAT = "MM/dd/yyyy"; + + /** Date format for parsing dates. */ + private static final DateFormat DATE_FORMATTER = new SimpleDateFormat(DATE_FORMAT); + + /** + * Utility method for the date format used by CalendarView's min/max date. + * + * @hide Use only as directed. For internal use only. + */ + public static boolean parseDate(String date, Calendar outDate) { + if (date == null || date.isEmpty()) { + return false; + } + + try { + final Date parsedDate = DATE_FORMATTER.parse(date); + outDate.setTime(parsedDate); + return true; + } catch (ParseException e) { + Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT); + return false; + } + } } diff --git a/core/java/android/widget/CalendarViewLegacyDelegate.java b/core/java/android/widget/CalendarViewLegacyDelegate.java index 2ab3548..6ab3828 100644 --- a/core/java/android/widget/CalendarViewLegacyDelegate.java +++ b/core/java/android/widget/CalendarViewLegacyDelegate.java @@ -27,7 +27,6 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.text.TextUtils; import android.text.format.DateUtils; import android.util.AttributeSet; import android.util.DisplayMetrics; @@ -267,12 +266,12 @@ class CalendarViewLegacyDelegate extends CalendarView.AbstractCalendarViewDelega mFirstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek, LocaleData.get(Locale.getDefault()).firstDayOfWeek); final String minDate = a.getString(R.styleable.CalendarView_minDate); - if (TextUtils.isEmpty(minDate) || !parseDate(minDate, mMinDate)) { - parseDate(DEFAULT_MIN_DATE, mMinDate); + if (!CalendarView.parseDate(minDate, mMinDate)) { + CalendarView.parseDate(DEFAULT_MIN_DATE, mMinDate); } final String maxDate = a.getString(R.styleable.CalendarView_maxDate); - if (TextUtils.isEmpty(maxDate) || !parseDate(maxDate, mMaxDate)) { - parseDate(DEFAULT_MAX_DATE, mMaxDate); + if (!CalendarView.parseDate(maxDate, mMaxDate)) { + CalendarView.parseDate(DEFAULT_MAX_DATE, mMaxDate); } if (mMaxDate.before(mMinDate)) { throw new IllegalArgumentException("Max date cannot be before min date."); diff --git a/core/java/android/widget/CalendarViewMaterialDelegate.java b/core/java/android/widget/CalendarViewMaterialDelegate.java index b0f3740..7bce756 100644 --- a/core/java/android/widget/CalendarViewMaterialDelegate.java +++ b/core/java/android/widget/CalendarViewMaterialDelegate.java @@ -16,20 +16,11 @@ package android.widget; -import com.android.internal.R; - +import android.annotation.StyleRes; import android.content.Context; -import android.content.res.Configuration; -import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; -import android.text.TextUtils; import android.util.AttributeSet; -import android.util.MathUtils; import java.util.Calendar; -import java.util.Locale; - -import libcore.icu.LocaleData; class CalendarViewMaterialDelegate extends CalendarView.AbstractCalendarViewDelegate { private final DayPickerView mDayPickerView; @@ -40,142 +31,32 @@ class CalendarViewMaterialDelegate extends CalendarView.AbstractCalendarViewDele int defStyleAttr, int defStyleRes) { super(delegator, context); - final TypedArray a = context.obtainStyledAttributes(attrs, - R.styleable.CalendarView, defStyleAttr, defStyleRes); - final int firstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek, - LocaleData.get(Locale.getDefault()).firstDayOfWeek); - - final long minDate = parseDateToMillis(a.getString( - R.styleable.CalendarView_minDate), DEFAULT_MIN_DATE); - final long maxDate = parseDateToMillis(a.getString( - R.styleable.CalendarView_maxDate), DEFAULT_MAX_DATE); - if (maxDate < minDate) { - throw new IllegalArgumentException("max date cannot be before min date"); - } - - final long setDate = MathUtils.constrain(System.currentTimeMillis(), minDate, maxDate); - final int dateTextAppearanceResId = a.getResourceId( - R.styleable.CalendarView_dateTextAppearance, - R.style.TextAppearance_DeviceDefault_Small); - - a.recycle(); - - mDayPickerView = new DayPickerView(context); - mDayPickerView.setFirstDayOfWeek(firstDayOfWeek); - mDayPickerView.setCalendarTextAppearance(dateTextAppearanceResId); - mDayPickerView.setMinDate(minDate); - mDayPickerView.setMaxDate(maxDate); - mDayPickerView.setDate(setDate, false, true); + mDayPickerView = new DayPickerView(context, attrs, defStyleAttr, defStyleRes); mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener); delegator.addView(mDayPickerView); } - private long parseDateToMillis(String dateStr, String defaultDateStr) { - final Calendar tempCalendar = Calendar.getInstance(); - if (TextUtils.isEmpty(dateStr) || !parseDate(dateStr, tempCalendar)) { - parseDate(defaultDateStr, tempCalendar); - } - return tempCalendar.getTimeInMillis(); - } - @Override - public void setShownWeekCount(int count) { - // Deprecated. - } - - @Override - public int getShownWeekCount() { - // Deprecated. - return 0; - } - - @Override - public void setSelectedWeekBackgroundColor(int color) { - // TODO: Should use a ColorStateList. Deprecate? - } - - @Override - public int getSelectedWeekBackgroundColor() { - return 0; - } - - @Override - public void setFocusedMonthDateColor(int color) { - // TODO: Should use a ColorStateList. Deprecate? - } - - @Override - public int getFocusedMonthDateColor() { - return 0; - } - - @Override - public void setUnfocusedMonthDateColor(int color) { - // TODO: Should use a ColorStateList. Deprecate? - } - - @Override - public int getUnfocusedMonthDateColor() { - return 0; - } - - @Override - public void setWeekDayTextAppearance(int resourceId) { - + public void setWeekDayTextAppearance(@StyleRes int resId) { + mDayPickerView.setDayOfWeekTextAppearance(resId); } + @StyleRes @Override public int getWeekDayTextAppearance() { - return 0; + return mDayPickerView.getDayOfWeekTextAppearance(); } @Override - public void setDateTextAppearance(int resourceId) { - + public void setDateTextAppearance(@StyleRes int resId) { + mDayPickerView.setDayTextAppearance(resId); } + @StyleRes @Override public int getDateTextAppearance() { - return 0; - } - - @Override - public void setWeekNumberColor(int color) { - // Deprecated. - } - - @Override - public int getWeekNumberColor() { - // Deprecated. - return 0; - } - - @Override - public void setWeekSeparatorLineColor(int color) { - // Deprecated. - } - - @Override - public int getWeekSeparatorLineColor() { - // Deprecated. - return 0; - } - - @Override - public void setSelectedDateVerticalBar(int resourceId) { - // Deprecated. - } - - @Override - public void setSelectedDateVerticalBar(Drawable drawable) { - // Deprecated. - } - - @Override - public Drawable getSelectedDateVerticalBar() { - // Deprecated. - return null; + return mDayPickerView.getDayTextAppearance(); } @Override @@ -199,17 +80,6 @@ class CalendarViewMaterialDelegate extends CalendarView.AbstractCalendarViewDele } @Override - public void setShowWeekNumber(boolean showWeekNumber) { - // Deprecated. - } - - @Override - public boolean getShowWeekNumber() { - // Deprecated. - return false; - } - - @Override public void setFirstDayOfWeek(int firstDayOfWeek) { mDayPickerView.setFirstDayOfWeek(firstDayOfWeek); } @@ -221,12 +91,12 @@ class CalendarViewMaterialDelegate extends CalendarView.AbstractCalendarViewDele @Override public void setDate(long date) { - mDayPickerView.setDate(date, true, false); + mDayPickerView.setDate(date, true); } @Override public void setDate(long date, boolean animate, boolean center) { - mDayPickerView.setDate(date, animate, center); + mDayPickerView.setDate(date, animate); } @Override @@ -239,12 +109,6 @@ class CalendarViewMaterialDelegate extends CalendarView.AbstractCalendarViewDele mOnDateChangeListener = listener; } - @Override - public void onConfigurationChanged(Configuration newConfig) { - // Nothing to do here, configuration changes are already propagated - // by ViewGroup. - } - private final DayPickerView.OnDaySelectedListener mOnDaySelectedListener = new DayPickerView.OnDaySelectedListener() { @Override diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index 45998f7..19ae6e2 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -98,7 +98,7 @@ public class DatePicker extends FrameLayout { private final DatePickerDelegate mDelegate; /** - * The callback used to indicate the user changes\d the date. + * The callback used to indicate the user changed the date. */ public interface OnDateChangedListener { @@ -489,15 +489,14 @@ public class DatePicker extends FrameLayout { mDelegator = delegator; mContext = context; - // initialization based on locale setCurrentLocale(Locale.getDefault()); } protected void setCurrentLocale(Locale locale) { - if (locale.equals(mCurrentLocale)) { - return; + if (!locale.equals(mCurrentLocale)) { + mCurrentLocale = locale; + onLocaleChanged(locale); } - mCurrentLocale = locale; } @Override @@ -510,6 +509,10 @@ public class DatePicker extends FrameLayout { mValidationCallback.onValidationChanged(valid); } } + + protected void onLocaleChanged(Locale locale) { + // Stub. + } } /** diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java index 0e3ec7f..de43b2f 100755 --- a/core/java/android/widget/DatePickerCalendarDelegate.java +++ b/core/java/android/widget/DatePickerCalendarDelegate.java @@ -16,6 +16,7 @@ package android.widget; +import android.annotation.Nullable; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Configuration; @@ -26,31 +27,34 @@ import android.os.Parcelable; import android.text.format.DateFormat; import android.text.format.DateUtils; import android.util.AttributeSet; +import android.util.StateSet; import android.view.HapticFeedbackConstants; import android.view.LayoutInflater; import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; +import android.widget.DayPickerView.OnDaySelectedListener; +import android.widget.YearPickerView.OnYearSelectedListener; import com.android.internal.R; -import com.android.internal.widget.AccessibleDateAnimator; import java.text.SimpleDateFormat; import java.util.Calendar; -import java.util.HashSet; import java.util.Locale; /** * A delegate for picking up a date (day / month / year). */ -class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate implements - View.OnClickListener, DatePickerController { +class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate { + private static final int USE_LOCALE = 0; private static final int UNINITIALIZED = -1; - private static final int MONTH_AND_DAY_VIEW = 0; - private static final int YEAR_VIEW = 1; + private static final int VIEW_MONTH_DAY = 0; + private static final int VIEW_YEAR = 1; private static final int DEFAULT_START_YEAR = 1900; private static final int DEFAULT_END_YEAR = 2100; @@ -61,33 +65,30 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i private static final int DAY_INDEX = 1; private static final int YEAR_INDEX = 2; - private SimpleDateFormat mYearFormat = new SimpleDateFormat("y", Locale.getDefault()); - private SimpleDateFormat mDayFormat = new SimpleDateFormat("d", Locale.getDefault()); + public static final int[] ATTRS_TEXT_COLOR = new int[]{com.android.internal.R.attr.textColor}; + + public static final int[] ATTRS_DISABLED_ALPHA = new int[]{ + com.android.internal.R.attr.disabledAlpha}; - private TextView mDayOfWeekView; + private SimpleDateFormat mYearFormat; + private SimpleDateFormat mMonthDayFormat; - /** Layout that contains the current month, day, and year. */ - private LinearLayout mMonthDayYearLayout; + // Top-level container. + private ViewGroup mContainer; - /** Clickable layout that contains the current day and year. */ - private LinearLayout mMonthAndDayLayout; + // Header views. + private TextView mHeaderYear; + private TextView mHeaderMonthDay; - private TextView mHeaderMonthTextView; - private TextView mHeaderDayOfMonthTextView; - private TextView mHeaderYearTextView; + // Picker views. + private ViewAnimator mAnimator; private DayPickerView mDayPickerView; private YearPickerView mYearPickerView; - private boolean mIsEnabled = true; - // Accessibility strings. - private String mDayPickerDescription; private String mSelectDay; - private String mYearPickerDescription; private String mSelectYear; - private AccessibleDateAnimator mAnimator; - private DatePicker.OnDateChangedListener mDateChangedListener; private int mCurrentView = UNINITIALIZED; @@ -99,13 +100,11 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i private int mFirstDayOfWeek = USE_LOCALE; - private HashSet<OnDateChangedListener> mListeners = new HashSet<OnDateChangedListener>(); - public DatePickerCalendarDelegate(DatePicker delegator, Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(delegator, context); - final Locale locale = Locale.getDefault(); + final Locale locale = mCurrentLocale; mMinDate = getCalendarForLocale(mMinDate, locale); mMaxDate = getCalendarForLocale(mMaxDate, locale); mTempDate = getCalendarForLocale(mMaxDate, locale); @@ -120,71 +119,64 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( Context.LAYOUT_INFLATER_SERVICE); final int layoutResourceId = a.getResourceId( - R.styleable.DatePicker_internalLayout, R.layout.date_picker_holo); - final View mainView = inflater.inflate(layoutResourceId, null); - mDelegator.addView(mainView); + R.styleable.DatePicker_internalLayout, R.layout.date_picker_material); - mDayOfWeekView = (TextView) mainView.findViewById(R.id.date_picker_header); + // Set up and attach container. + mContainer = (ViewGroup) inflater.inflate(layoutResourceId, mDelegator); - // Layout that contains the current date and day name header. - final LinearLayout dateLayout = (LinearLayout) mainView.findViewById( - R.id.day_picker_selector_layout); - mMonthDayYearLayout = (LinearLayout) mainView.findViewById( - R.id.date_picker_month_day_year_layout); - mMonthAndDayLayout = (LinearLayout) mainView.findViewById( - R.id.date_picker_month_and_day_layout); - mMonthAndDayLayout.setOnClickListener(this); - mHeaderMonthTextView = (TextView) mainView.findViewById(R.id.date_picker_month); - mHeaderDayOfMonthTextView = (TextView) mainView.findViewById(R.id.date_picker_day); - mHeaderYearTextView = (TextView) mainView.findViewById(R.id.date_picker_year); - mHeaderYearTextView.setOnClickListener(this); + // Set up header views. + final ViewGroup header = (ViewGroup) mContainer.findViewById(R.id.date_picker_header); + mHeaderYear = (TextView) header.findViewById(R.id.date_picker_header_year); + mHeaderYear.setOnClickListener(mOnHeaderClickListener); + mHeaderMonthDay = (TextView) header.findViewById(R.id.date_picker_header_date); + mHeaderMonthDay.setOnClickListener(mOnHeaderClickListener); - // Obtain default highlight color from the theme. - final int defaultHighlightColor = mHeaderYearTextView.getHighlightColor(); + // For the sake of backwards compatibility, attempt to extract the text + // color from the header month text appearance. If it's set, we'll let + // that override the "real" header text color. + ColorStateList headerTextColor = null; - // Use Theme attributes if possible - final int dayOfWeekTextAppearanceResId = a.getResourceId( - R.styleable.DatePicker_dayOfWeekTextAppearance, 0); - if (dayOfWeekTextAppearanceResId != 0) { - mDayOfWeekView.setTextAppearance(context, dayOfWeekTextAppearanceResId); + @SuppressWarnings("deprecation") + final int monthHeaderTextAppearance = a.getResourceId( + R.styleable.DatePicker_headerMonthTextAppearance, 0); + if (monthHeaderTextAppearance != 0) { + final TypedArray textAppearance = mContext.obtainStyledAttributes(null, + ATTRS_TEXT_COLOR, 0, monthHeaderTextAppearance); + final ColorStateList legacyHeaderTextColor = textAppearance.getColorStateList(0); + headerTextColor = applyLegacyColorFixes(legacyHeaderTextColor); + textAppearance.recycle(); } - mDayOfWeekView.setBackground(a.getDrawable(R.styleable.DatePicker_dayOfWeekBackground)); - - dateLayout.setBackground(a.getDrawable(R.styleable.DatePicker_headerBackground)); - - final int monthTextAppearanceResId = a.getResourceId( - R.styleable.DatePicker_headerMonthTextAppearance, 0); - if (monthTextAppearanceResId != 0) { - mHeaderMonthTextView.setTextAppearance(context, monthTextAppearanceResId); + if (headerTextColor == null) { + headerTextColor = a.getColorStateList(R.styleable.DatePicker_headerTextColor); } - final int dayOfMonthTextAppearanceResId = a.getResourceId( - R.styleable.DatePicker_headerDayOfMonthTextAppearance, 0); - if (dayOfMonthTextAppearanceResId != 0) { - mHeaderDayOfMonthTextView.setTextAppearance(context, dayOfMonthTextAppearanceResId); + if (headerTextColor != null) { + mHeaderYear.setTextColor(headerTextColor); + mHeaderMonthDay.setTextColor(headerTextColor); } - final int headerYearTextAppearanceResId = a.getResourceId( - R.styleable.DatePicker_headerYearTextAppearance, 0); - if (headerYearTextAppearanceResId != 0) { - mHeaderYearTextView.setTextAppearance(context, headerYearTextAppearanceResId); + // Set up header background, if available. + if (a.hasValueOrEmpty(R.styleable.DatePicker_headerBackground)) { + header.setBackground(a.getDrawable(R.styleable.DatePicker_headerBackground)); } - mDayPickerView = new DayPickerView(mContext); + // Set up picker container. + mAnimator = (ViewAnimator) mContainer.findViewById(R.id.animator); + + // Set up day picker view. + mDayPickerView = (DayPickerView) mAnimator.findViewById(R.id.date_picker_day_picker); mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek); mDayPickerView.setMinDate(mMinDate.getTimeInMillis()); mDayPickerView.setMaxDate(mMaxDate.getTimeInMillis()); mDayPickerView.setDate(mCurrentDate.getTimeInMillis()); mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener); - mYearPickerView = new YearPickerView(mContext); - mYearPickerView.init(this); + // Set up year picker view. + mYearPickerView = (YearPickerView) mAnimator.findViewById(R.id.date_picker_year_picker); mYearPickerView.setRange(mMinDate, mMaxDate); - - final ColorStateList yearBackgroundColor = a.getColorStateList( - R.styleable.DatePicker_yearListSelectorColor); - mYearPickerView.setYearBackgroundColor(yearBackgroundColor); + mYearPickerView.setDate(mCurrentDate.getTimeInMillis()); + mYearPickerView.setOnYearSelectedListener(mOnYearSelectedListener); final int yearTextAppearanceResId = a.getResourceId( R.styleable.DatePicker_yearListItemTextAppearance, 0); @@ -192,37 +184,138 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i mYearPickerView.setYearTextAppearance(yearTextAppearanceResId); } - final ColorStateList calendarTextColor = a.getColorStateList( - R.styleable.DatePicker_calendarTextColor); - mDayPickerView.setCalendarTextColor(calendarTextColor); + final int yearActivatedTextAppearanceResId = a.getResourceId( + R.styleable.DatePicker_yearListItemActivatedTextAppearance, 0); + if (yearActivatedTextAppearanceResId != 0) { + mYearPickerView.setYearActivatedTextAppearance(yearActivatedTextAppearanceResId); + } - final ColorStateList calendarDayBackgroundColor = a.getColorStateList( - R.styleable.DatePicker_calendarDayBackgroundColor); - mDayPickerView.setCalendarDayBackgroundColor(calendarDayBackgroundColor); + a.recycle(); - mDayPickerDescription = res.getString(R.string.day_picker_description); + // Set up content descriptions. mSelectDay = res.getString(R.string.select_day); - mYearPickerDescription = res.getString(R.string.year_picker_description); mSelectYear = res.getString(R.string.select_year); - mAnimator = (AccessibleDateAnimator) mainView.findViewById(R.id.animator); - mAnimator.addView(mDayPickerView); - mAnimator.addView(mYearPickerView); - mAnimator.setDateMillis(mCurrentDate.getTimeInMillis()); + final Animation inAnim = new AlphaAnimation(0, 1); + inAnim.setDuration(ANIMATION_DURATION); + mAnimator.setInAnimation(inAnim); + + final Animation outAnim = new AlphaAnimation(1, 0); + outAnim.setDuration(ANIMATION_DURATION); + mAnimator.setOutAnimation(outAnim); - final Animation animation = new AlphaAnimation(0.0f, 1.0f); - animation.setDuration(ANIMATION_DURATION); - mAnimator.setInAnimation(animation); + // Initialize for current locale. This also initializes the date, so no + // need to call onDateChanged. + onLocaleChanged(mCurrentLocale); - final Animation animation2 = new AlphaAnimation(1.0f, 0.0f); - animation2.setDuration(ANIMATION_DURATION); - mAnimator.setOutAnimation(animation2); + setCurrentView(VIEW_MONTH_DAY); + } + + /** + * The legacy text color might have been poorly defined. Ensures that it + * has an appropriate activated state, using the selected state if one + * exists or modifying the default text color otherwise. + * + * @param color a legacy text color, or {@code null} + * @return a color state list with an appropriate activated state, or + * {@code null} if a valid activated state could not be generated + */ + @Nullable + private ColorStateList applyLegacyColorFixes(@Nullable ColorStateList color) { + if (color == null || color.hasState(R.attr.state_activated)) { + return color; + } + + final int activatedColor; + final int defaultColor; + if (color.hasState(R.attr.state_selected)) { + activatedColor = color.getColorForState(StateSet.get( + StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_SELECTED), 0); + defaultColor = color.getColorForState(StateSet.get( + StateSet.VIEW_STATE_ENABLED), 0); + } else { + activatedColor = color.getDefaultColor(); + + // Generate a non-activated color using the disabled alpha. + final TypedArray ta = mContext.obtainStyledAttributes(ATTRS_DISABLED_ALPHA); + final float disabledAlpha = ta.getFloat(0, 0.30f); + defaultColor = multiplyAlphaComponent(activatedColor, disabledAlpha); + } + + if (activatedColor == 0 || defaultColor == 0) { + // We somehow failed to obtain the colors. + return null; + } + + final int[][] stateSet = new int[][] {{ R.attr.state_activated }, {}}; + final int[] colors = new int[] { activatedColor, defaultColor }; + return new ColorStateList(stateSet, colors); + } - updateDisplay(false); - setCurrentView(MONTH_AND_DAY_VIEW); + private int multiplyAlphaComponent(int color, float alphaMod) { + final int srcRgb = color & 0xFFFFFF; + final int srcAlpha = (color >> 24) & 0xFF; + final int dstAlpha = (int) (srcAlpha * alphaMod + 0.5f); + return srcRgb | (dstAlpha << 24); } /** + * Listener called when the user selects a day in the day picker view. + */ + private final OnDaySelectedListener mOnDaySelectedListener = new OnDaySelectedListener() { + @Override + public void onDaySelected(DayPickerView view, Calendar day) { + mCurrentDate.setTimeInMillis(day.getTimeInMillis()); + onDateChanged(true, true); + } + }; + + /** + * Listener called when the user selects a year in the year picker view. + */ + private final OnYearSelectedListener mOnYearSelectedListener = new OnYearSelectedListener() { + @Override + public void onYearChanged(YearPickerView view, int year) { + // If the newly selected month / year does not contain the + // currently selected day number, change the selected day number + // to the last day of the selected month or year. + // e.g. Switching from Mar to Apr when Mar 31 is selected -> Apr 30 + // e.g. Switching from 2012 to 2013 when Feb 29, 2012 is selected -> Feb 28, 2013 + final int day = mCurrentDate.get(Calendar.DAY_OF_MONTH); + final int month = mCurrentDate.get(Calendar.MONTH); + final int daysInMonth = getDaysInMonth(month, year); + if (day > daysInMonth) { + mCurrentDate.set(Calendar.DAY_OF_MONTH, daysInMonth); + } + + mCurrentDate.set(Calendar.YEAR, year); + onDateChanged(true, true); + + // Automatically switch to day picker. + setCurrentView(VIEW_MONTH_DAY); + } + }; + + /** + * Listener called when the user clicks on a header item. + */ + private final OnClickListener mOnHeaderClickListener = new OnClickListener() { + @Override + public void onClick(View v) { + tryVibrate(); + + switch (v.getId()) { + case R.id.date_picker_header_year: + setCurrentView(VIEW_YEAR); + break; + case R.id.date_picker_header_date: + setCurrentView(VIEW_MONTH_DAY); + break; + } + } + }; + + /** * Gets a calendar for locale bootstrapped with the value of a given calendar. * * @param oldCalendar The old calendar. @@ -277,85 +370,70 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i return result; } - private void updateDisplay(boolean announce) { - if (mDayOfWeekView != null) { - mDayOfWeekView.setText(mCurrentDate.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, - Locale.getDefault())); + @Override + protected void onLocaleChanged(Locale locale) { + final TextView headerYear = mHeaderYear; + if (headerYear == null) { + // Abort, we haven't initialized yet. This method will get called + // again later after everything has been set up. + return; } - // Compute indices of Month, Day and Year views - final String bestDateTimePattern = - DateFormat.getBestDateTimePattern(mCurrentLocale, "yMMMd"); - final int[] viewIndices = getMonthDayYearIndexes(bestDateTimePattern); + // Update the date formatter. + final String datePattern = DateFormat.getBestDateTimePattern(locale, "EMMMd"); + mMonthDayFormat = new SimpleDateFormat(datePattern, locale); + mYearFormat = new SimpleDateFormat("y", locale); - // Position the Year and MonthAndDay views within the header. - mMonthDayYearLayout.removeAllViews(); - if (viewIndices[YEAR_INDEX] == 0) { - mMonthDayYearLayout.addView(mHeaderYearTextView); - mMonthDayYearLayout.addView(mMonthAndDayLayout); - } else { - mMonthDayYearLayout.addView(mMonthAndDayLayout); - mMonthDayYearLayout.addView(mHeaderYearTextView); - } + // Update the header text. + onCurrentDateChanged(false); + } - // Position Day and Month views within the MonthAndDay view. - mMonthAndDayLayout.removeAllViews(); - if (viewIndices[MONTH_INDEX] > viewIndices[DAY_INDEX]) { - mMonthAndDayLayout.addView(mHeaderDayOfMonthTextView); - mMonthAndDayLayout.addView(mHeaderMonthTextView); - } else { - mMonthAndDayLayout.addView(mHeaderMonthTextView); - mMonthAndDayLayout.addView(mHeaderDayOfMonthTextView); + private void onCurrentDateChanged(boolean announce) { + if (mHeaderYear == null) { + // Abort, we haven't initialized yet. This method will get called + // again later after everything has been set up. + return; } - mHeaderMonthTextView.setText(mCurrentDate.getDisplayName(Calendar.MONTH, Calendar.SHORT, - Locale.getDefault()).toUpperCase(Locale.getDefault())); - mHeaderDayOfMonthTextView.setText(mDayFormat.format(mCurrentDate.getTime())); - mHeaderYearTextView.setText(mYearFormat.format(mCurrentDate.getTime())); + final String year = mYearFormat.format(mCurrentDate.getTime()); + mHeaderYear.setText(year); - // Accessibility. - long millis = mCurrentDate.getTimeInMillis(); - mAnimator.setDateMillis(millis); - int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR; - String monthAndDayText = DateUtils.formatDateTime(mContext, millis, flags); - mMonthAndDayLayout.setContentDescription(monthAndDayText); + final String monthDay = mMonthDayFormat.format(mCurrentDate.getTime()); + mHeaderMonthDay.setText(monthDay); + // TODO: This should use live regions. if (announce) { - flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR; - String fullDateText = DateUtils.formatDateTime(mContext, millis, flags); + final long millis = mCurrentDate.getTimeInMillis(); + final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR; + final String fullDateText = DateUtils.formatDateTime(mContext, millis, flags); mAnimator.announceForAccessibility(fullDateText); } } private void setCurrentView(final int viewIndex) { - long millis = mCurrentDate.getTimeInMillis(); - switch (viewIndex) { - case MONTH_AND_DAY_VIEW: - mDayPickerView.setDate(getSelectedDay().getTimeInMillis()); + case VIEW_MONTH_DAY: + mDayPickerView.setDate(mCurrentDate.getTimeInMillis()); + if (mCurrentView != viewIndex) { - mMonthAndDayLayout.setSelected(true); - mHeaderYearTextView.setSelected(false); - mAnimator.setDisplayedChild(MONTH_AND_DAY_VIEW); + mHeaderMonthDay.setActivated(true); + mHeaderYear.setActivated(false); + mAnimator.setDisplayedChild(VIEW_MONTH_DAY); mCurrentView = viewIndex; } - final int flags = DateUtils.FORMAT_SHOW_DATE; - final String dayString = DateUtils.formatDateTime(mContext, millis, flags); - mAnimator.setContentDescription(mDayPickerDescription + ": " + dayString); mAnimator.announceForAccessibility(mSelectDay); break; - case YEAR_VIEW: - mYearPickerView.onDateChanged(); + case VIEW_YEAR: + mYearPickerView.setDate(mCurrentDate.getTimeInMillis()); + if (mCurrentView != viewIndex) { - mMonthAndDayLayout.setSelected(false); - mHeaderYearTextView.setSelected(true); - mAnimator.setDisplayedChild(YEAR_VIEW); + mHeaderMonthDay.setActivated(false); + mHeaderYear.setActivated(true); + mAnimator.setDisplayedChild(VIEW_YEAR); mCurrentView = viewIndex; } - final CharSequence yearString = mYearFormat.format(millis); - mAnimator.setContentDescription(mYearPickerDescription + ": " + yearString); mAnimator.announceForAccessibility(mSelectYear); break; } @@ -383,20 +461,18 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i } private void onDateChanged(boolean fromUser, boolean callbackToClient) { + final int year = mCurrentDate.get(Calendar.YEAR); + if (callbackToClient && mDateChangedListener != null) { - final int year = mCurrentDate.get(Calendar.YEAR); final int monthOfYear = mCurrentDate.get(Calendar.MONTH); final int dayOfMonth = mCurrentDate.get(Calendar.DAY_OF_MONTH); mDateChangedListener.onDateChanged(mDelegator, year, monthOfYear, dayOfMonth); } - for (OnDateChangedListener listener : mListeners) { - listener.onDateChanged(); - } - - mDayPickerView.setDate(getSelectedDay().getTimeInMillis()); + mDayPickerView.setDate(mCurrentDate.getTimeInMillis()); + mYearPickerView.setYear(year); - updateDisplay(fromUser); + onCurrentDateChanged(fromUser); if (fromUser) { tryVibrate(); @@ -477,15 +553,12 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i @Override public void setEnabled(boolean enabled) { - mMonthAndDayLayout.setEnabled(enabled); - mHeaderYearTextView.setEnabled(enabled); - mAnimator.setEnabled(enabled); - mIsEnabled = enabled; + mContainer.setEnabled(false); } @Override public boolean isEnabled() { - return mIsEnabled; + return mContainer.isEnabled(); } @Override @@ -516,8 +589,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i @Override public void onConfigurationChanged(Configuration newConfig) { - mYearFormat = new SimpleDateFormat("y", newConfig.locale); - mDayFormat = new SimpleDateFormat("d", newConfig.locale); + setCurrentLocale(newConfig.locale); } @Override @@ -529,9 +601,9 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i int listPosition = -1; int listPositionOffset = -1; - if (mCurrentView == MONTH_AND_DAY_VIEW) { + if (mCurrentView == VIEW_MONTH_DAY) { listPosition = mDayPickerView.getMostVisiblePosition(); - } else if (mCurrentView == YEAR_VIEW) { + } else if (mCurrentView == VIEW_YEAR) { listPosition = mYearPickerView.getFirstVisiblePosition(); listPositionOffset = mYearPickerView.getFirstPositionOffset(); } @@ -544,20 +616,22 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i public void onRestoreInstanceState(Parcelable state) { SavedState ss = (SavedState) state; + // TODO: Move instance state into DayPickerView, YearPickerView. mCurrentDate.set(ss.getSelectedYear(), ss.getSelectedMonth(), ss.getSelectedDay()); mCurrentView = ss.getCurrentView(); mMinDate.setTimeInMillis(ss.getMinDate()); mMaxDate.setTimeInMillis(ss.getMaxDate()); - updateDisplay(false); + onCurrentDateChanged(false); setCurrentView(mCurrentView); final int listPosition = ss.getListPosition(); if (listPosition != -1) { - if (mCurrentView == MONTH_AND_DAY_VIEW) { - mDayPickerView.postSetSelection(listPosition); - } else if (mCurrentView == YEAR_VIEW) { - mYearPickerView.postSetSelectionFromTop(listPosition, ss.getListPositionOffset()); + if (mCurrentView == VIEW_MONTH_DAY) { + mDayPickerView.setCurrentItem(listPosition); + } else if (mCurrentView == VIEW_YEAR) { + final int listPositionOffset = ss.getListPositionOffset(); + mYearPickerView.setSelectionFromTop(listPosition, listPositionOffset); } } } @@ -577,28 +651,6 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i return DatePicker.class.getName(); } - @Override - public void onYearSelected(int year) { - adjustDayInMonthIfNeeded(mCurrentDate.get(Calendar.MONTH), year); - mCurrentDate.set(Calendar.YEAR, year); - onDateChanged(true, true); - - // Auto-advance to month and day view. - setCurrentView(MONTH_AND_DAY_VIEW); - } - - // If the newly selected month / year does not contain the currently selected day number, - // change the selected day number to the last day of the selected month or year. - // e.g. Switching from Mar to Apr when Mar 31 is selected -> Apr 30 - // e.g. Switching from 2012 to 2013 when Feb 29, 2012 is selected -> Feb 28, 2013 - private void adjustDayInMonthIfNeeded(int month, int year) { - int day = mCurrentDate.get(Calendar.DAY_OF_MONTH); - int daysInMonth = getDaysInMonth(month, year); - if (day > daysInMonth) { - mCurrentDate.set(Calendar.DAY_OF_MONTH, daysInMonth); - } - } - public static int getDaysInMonth(int month, int year) { switch (month) { case Calendar.JANUARY: @@ -621,43 +673,10 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i } } - @Override - public void registerOnDateChangedListener(OnDateChangedListener listener) { - mListeners.add(listener); - } - - @Override - public Calendar getSelectedDay() { - return mCurrentDate; - } - - @Override - public void tryVibrate() { + private void tryVibrate() { mDelegator.performHapticFeedback(HapticFeedbackConstants.CALENDAR_DATE); } - @Override - public void onClick(View v) { - tryVibrate(); - if (v.getId() == R.id.date_picker_year) { - setCurrentView(YEAR_VIEW); - } else if (v.getId() == R.id.date_picker_month_and_day_layout) { - setCurrentView(MONTH_AND_DAY_VIEW); - } - } - - /** - * Listener called when the user selects a day in the day picker view. - */ - private final DayPickerView.OnDaySelectedListener - mOnDaySelectedListener = new DayPickerView.OnDaySelectedListener() { - @Override - public void onDaySelected(DayPickerView view, Calendar day) { - mCurrentDate.setTimeInMillis(day.getTimeInMillis()); - onDateChanged(true, true); - } - }; - /** * Class for managing state storing/restoring. */ diff --git a/core/java/android/widget/DayPickerAdapter.java b/core/java/android/widget/DayPickerAdapter.java new file mode 100644 index 0000000..4f9f09e --- /dev/null +++ b/core/java/android/widget/DayPickerAdapter.java @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.widget; + +import com.android.internal.widget.PagerAdapter; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.TypedArray; +import android.util.SparseArray; +import android.view.View; +import android.view.ViewGroup; +import android.widget.SimpleMonthView.OnDayClickListener; + +import java.util.Calendar; + +/** + * An adapter for a list of {@link android.widget.SimpleMonthView} items. + */ +class DayPickerAdapter extends PagerAdapter { + private static final int MONTHS_IN_YEAR = 12; + + private final Calendar mMinDate = Calendar.getInstance(); + private final Calendar mMaxDate = Calendar.getInstance(); + + private final SparseArray<SimpleMonthView> mItems = new SparseArray<>(); + + private Calendar mSelectedDay = Calendar.getInstance(); + + private int mMonthTextAppearance; + private int mDayOfWeekTextAppearance; + private int mDayTextAppearance; + + private ColorStateList mCalendarTextColor; + private ColorStateList mDaySelectorColor; + private ColorStateList mDayHighlightColor; + + private OnDaySelectedListener mOnDaySelectedListener; + + private int mFirstDayOfWeek; + + public DayPickerAdapter(Context context) { + final TypedArray ta = context.obtainStyledAttributes(new int[] { + com.android.internal.R.attr.colorControlHighlight}); + mDayHighlightColor = ta.getColorStateList(0); + ta.recycle(); + } + + public void setRange(Calendar min, Calendar max) { + mMinDate.setTimeInMillis(min.getTimeInMillis()); + mMaxDate.setTimeInMillis(max.getTimeInMillis()); + + // Positions are now invalid, clear everything and start over. + notifyDataSetChanged(); + } + + /** + * Sets the first day of the week. + * + * @param weekStart which day the week should start on, valid values are + * {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY} + */ + public void setFirstDayOfWeek(int weekStart) { + mFirstDayOfWeek = weekStart; + + // Update displayed views. + final int count = mItems.size(); + for (int i = 0; i < count; i++) { + final SimpleMonthView monthView = mItems.valueAt(i); + monthView.setFirstDayOfWeek(weekStart); + } + } + + public int getFirstDayOfWeek() { + return mFirstDayOfWeek; + } + + /** + * Sets the selected day. + * + * @param day the selected day + */ + public void setSelectedDay(Calendar day) { + final int oldPosition = getPositionForDay(mSelectedDay); + final int newPosition = getPositionForDay(day); + + // Clear the old position if necessary. + if (oldPosition != newPosition) { + final SimpleMonthView oldMonthView = mItems.get(oldPosition, null); + if (oldMonthView != null) { + oldMonthView.setSelectedDay(-1); + } + } + + // Set the new position. + final SimpleMonthView newMonthView = mItems.get(newPosition, null); + if (newMonthView != null) { + final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH); + newMonthView.setSelectedDay(dayOfMonth); + } + + mSelectedDay = day; + } + + /** + * Sets the listener to call when the user selects a day. + * + * @param listener The listener to call. + */ + public void setOnDaySelectedListener(OnDaySelectedListener listener) { + mOnDaySelectedListener = listener; + } + + void setCalendarTextColor(ColorStateList calendarTextColor) { + mCalendarTextColor = calendarTextColor; + } + + void setDaySelectorColor(ColorStateList selectorColor) { + mDaySelectorColor = selectorColor; + } + + void setMonthTextAppearance(int resId) { + mMonthTextAppearance = resId; + } + + void setDayOfWeekTextAppearance(int resId) { + mDayOfWeekTextAppearance = resId; + } + + int getDayOfWeekTextAppearance() { + return mDayOfWeekTextAppearance; + } + + void setDayTextAppearance(int resId) { + mDayTextAppearance = resId; + } + + int getDayTextAppearance() { + return mDayTextAppearance; + } + + @Override + public int getCount() { + final int diffYear = mMaxDate.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR); + final int diffMonth = mMaxDate.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH); + return diffMonth + MONTHS_IN_YEAR * diffYear + 1; + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } + + private int getMonthForPosition(int position) { + return position % MONTHS_IN_YEAR + mMinDate.get(Calendar.MONTH); + } + + private int getYearForPosition(int position) { + return position / MONTHS_IN_YEAR + mMinDate.get(Calendar.YEAR); + } + + private int getPositionForDay(Calendar day) { + final int yearOffset = (day.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR)); + final int monthOffset = (day.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH)); + return yearOffset * MONTHS_IN_YEAR + monthOffset; + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + final SimpleMonthView v = new SimpleMonthView(container.getContext()); + v.setOnDayClickListener(mOnDayClickListener); + v.setMonthTextAppearance(mMonthTextAppearance); + v.setDayOfWeekTextAppearance(mDayOfWeekTextAppearance); + v.setDayTextAppearance(mDayTextAppearance); + + if (mDaySelectorColor != null) { + v.setDaySelectorColor(mDaySelectorColor); + } + + if (mDayHighlightColor != null) { + v.setDayHighlightColor(mDayHighlightColor); + } + + if (mCalendarTextColor != null) { + v.setMonthTextColor(mCalendarTextColor); + v.setDayOfWeekTextColor(mCalendarTextColor); + v.setDayTextColor(mCalendarTextColor); + } + + final int month = getMonthForPosition(position); + final int year = getYearForPosition(position); + + final int selectedDay; + if (mSelectedDay.get(Calendar.MONTH) == month) { + selectedDay = mSelectedDay.get(Calendar.DAY_OF_MONTH); + } else { + selectedDay = -1; + } + + final int enabledDayRangeStart; + if (mMinDate.get(Calendar.MONTH) == month && mMinDate.get(Calendar.YEAR) == year) { + enabledDayRangeStart = mMinDate.get(Calendar.DAY_OF_MONTH); + } else { + enabledDayRangeStart = 1; + } + + final int enabledDayRangeEnd; + if (mMaxDate.get(Calendar.MONTH) == month && mMaxDate.get(Calendar.YEAR) == year) { + enabledDayRangeEnd = mMaxDate.get(Calendar.DAY_OF_MONTH); + } else { + enabledDayRangeEnd = 31; + } + + v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek, + enabledDayRangeStart, enabledDayRangeEnd); + + mItems.put(position, v); + + container.addView(v); + + return v; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView(mItems.get(position)); + + mItems.remove(position); + } + + @Override + public int getItemPosition(Object object) { + final int index = mItems.indexOfValue((SimpleMonthView) object); + if (index < 0) { + return mItems.keyAt(index); + } + return -1; + } + + @Override + public CharSequence getPageTitle(int position) { + final SimpleMonthView v = mItems.get(position); + if (v != null) { + return v.getTitle(); + } + return null; + } + + private boolean isCalendarInRange(Calendar value) { + return value.compareTo(mMinDate) >= 0 && value.compareTo(mMaxDate) <= 0; + } + + private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() { + @Override + public void onDayClick(SimpleMonthView view, Calendar day) { + if (day != null && isCalendarInRange(day)) { + setSelectedDay(day); + + if (mOnDaySelectedListener != null) { + mOnDaySelectedListener.onDaySelected(DayPickerAdapter.this, day); + } + } + } + }; + + public interface OnDaySelectedListener { + public void onDaySelected(DayPickerAdapter view, Calendar day); + } +} diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java index 65af45d..a7ae926 100644 --- a/core/java/android/widget/DayPickerView.java +++ b/core/java/android/widget/DayPickerView.java @@ -16,87 +16,177 @@ package android.widget; +import com.android.internal.widget.ViewPager; +import com.android.internal.R; + import android.content.Context; import android.content.res.ColorStateList; -import android.content.res.Configuration; -import android.os.Bundle; -import android.util.Log; +import android.content.res.TypedArray; +import android.util.AttributeSet; import android.util.MathUtils; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityNodeInfo; -import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Locale; +import libcore.icu.LocaleData; + /** * This displays a list of months in a calendar format with selectable days. */ -class DayPickerView extends ListView implements AbsListView.OnScrollListener { - private static final String TAG = "DayPickerView"; +class DayPickerView extends ViewPager { + private static final int DEFAULT_START_YEAR = 1900; + private static final int DEFAULT_END_YEAR = 2100; - // How long the GoTo fling animation should last - private static final int GOTO_SCROLL_DURATION = 250; + private final Calendar mSelectedDay = Calendar.getInstance(); + private final Calendar mMinDate = Calendar.getInstance(); + private final Calendar mMaxDate = Calendar.getInstance(); - // How long to wait after receiving an onScrollStateChanged notification before acting on it - private static final int SCROLL_CHANGE_DELAY = 40; + private final DayPickerAdapter mAdapter; - // so that the top line will be under the separator - private static final int LIST_TOP_OFFSET = -1; + /** Temporary calendar used for date calculations. */ + private Calendar mTempCalendar; - private final SimpleMonthAdapter mAdapter = new SimpleMonthAdapter(getContext()); + private OnDaySelectedListener mOnDaySelectedListener; - private final ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable(this); + public DayPickerView(Context context) { + this(context, null); + } - private SimpleDateFormat mYearFormat = new SimpleDateFormat("yyyy", Locale.getDefault()); + public DayPickerView(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.calendarViewStyle); + } - // highlighted time - private Calendar mSelectedDay = Calendar.getInstance(); - private Calendar mTempDay = Calendar.getInstance(); - private Calendar mMinDate = Calendar.getInstance(); - private Calendar mMaxDate = Calendar.getInstance(); + public DayPickerView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } - private Calendar mTempCalendar; + public DayPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); - private OnDaySelectedListener mOnDaySelectedListener; + final TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.CalendarView, defStyleAttr, defStyleRes); - // which month should be displayed/highlighted [0-11] - private int mCurrentMonthDisplayed; - // used for tracking what state listview is in - private int mPreviousScrollState = OnScrollListener.SCROLL_STATE_IDLE; - // used for tracking what state listview is in - private int mCurrentScrollState = OnScrollListener.SCROLL_STATE_IDLE; + final int firstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek, + LocaleData.get(Locale.getDefault()).firstDayOfWeek); - private boolean mPerformingScroll; + final String minDate = a.getString(R.styleable.CalendarView_minDate); + final String maxDate = a.getString(R.styleable.CalendarView_maxDate); - public DayPickerView(Context context) { - super(context); + final int monthTextAppearanceResId = a.getResourceId( + R.styleable.CalendarView_monthTextAppearance, + R.style.TextAppearance_Material_Widget_Calendar_Month); + final int dayOfWeekTextAppearanceResId = a.getResourceId( + R.styleable.CalendarView_weekDayTextAppearance, + R.style.TextAppearance_Material_Widget_Calendar_DayOfWeek); + final int dayTextAppearanceResId = a.getResourceId( + R.styleable.CalendarView_dateTextAppearance, + R.style.TextAppearance_Material_Widget_Calendar_Day); + + final ColorStateList daySelectorColor = a.getColorStateList( + R.styleable.CalendarView_daySelectorColor); + + a.recycle(); + + // Set up adapter. + mAdapter = new DayPickerAdapter(context); + mAdapter.setMonthTextAppearance(monthTextAppearanceResId); + mAdapter.setDayOfWeekTextAppearance(dayOfWeekTextAppearanceResId); + mAdapter.setDayTextAppearance(dayTextAppearanceResId); + mAdapter.setDaySelectorColor(daySelectorColor); setAdapter(mAdapter); - setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); - setDrawSelectorOnTop(false); - setUpListView(); - goTo(mSelectedDay.getTimeInMillis(), false, false, true); + // Set up min and max dates. + final Calendar tempDate = Calendar.getInstance(); + if (!CalendarView.parseDate(minDate, tempDate)) { + tempDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1); + } + final long minDateMillis = tempDate.getTimeInMillis(); + + if (!CalendarView.parseDate(maxDate, tempDate)) { + tempDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31); + } + final long maxDateMillis = tempDate.getTimeInMillis(); + + if (maxDateMillis < minDateMillis) { + throw new IllegalArgumentException("maxDate must be >= minDate"); + } + + final long setDateMillis = MathUtils.constrain( + System.currentTimeMillis(), minDateMillis, maxDateMillis); - mAdapter.setOnDaySelectedListener(mProxyOnDaySelectedListener); + setFirstDayOfWeek(firstDayOfWeek); + setMinDate(minDateMillis); + setMaxDate(maxDateMillis); + setDate(setDateMillis, false); + + // Proxy selection callbacks to our own listener. + mAdapter.setOnDaySelectedListener(new DayPickerAdapter.OnDaySelectedListener() { + @Override + public void onDaySelected(DayPickerAdapter adapter, Calendar day) { + if (mOnDaySelectedListener != null) { + mOnDaySelectedListener.onDaySelected(DayPickerView.this, day); + } + } + }); + } + + public void setDayOfWeekTextAppearance(int resId) { + mAdapter.setDayOfWeekTextAppearance(resId); + } + + public int getDayOfWeekTextAppearance() { + return mAdapter.getDayOfWeekTextAppearance(); + } + + public void setDayTextAppearance(int resId) { + mAdapter.setDayTextAppearance(resId); + } + + public int getDayTextAppearance() { + return mAdapter.getDayTextAppearance(); } /** * Sets the currently selected date to the specified timestamp. Jumps * immediately to the new date. To animate to the new date, use - * {@link #setDate(long, boolean, boolean)}. + * {@link #setDate(long, boolean)}. * - * @param timeInMillis + * @param timeInMillis the target day in milliseconds */ public void setDate(long timeInMillis) { - setDate(timeInMillis, false, true); + setDate(timeInMillis, false); } - public void setDate(long timeInMillis, boolean animate, boolean forceScroll) { - goTo(timeInMillis, animate, true, forceScroll); + /** + * Sets the currently selected date to the specified timestamp. Jumps + * immediately to the new date, optionally animating the transition. + * + * @param timeInMillis the target day in milliseconds + * @param animate whether to smooth scroll to the new position + */ + public void setDate(long timeInMillis, boolean animate) { + setDate(timeInMillis, animate, true); + } + + /** + * Moves to the month containing the specified day, optionally setting the + * day as selected. + * + * @param timeInMillis the target day in milliseconds + * @param animate whether to smooth scroll to the new position + * @param setSelected whether to set the specified day as selected + */ + private void setDate(long timeInMillis, boolean animate, boolean setSelected) { + // Set the selected day + if (setSelected) { + mSelectedDay.setTimeInMillis(timeInMillis); + } + + final int position = getPositionFromDay(timeInMillis); + if (position != getCurrentItem()) { + setCurrentItem(position, animate); + } } public long getDate() { @@ -137,7 +227,7 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener { // Changing the min/max date changes the selection position since we // don't really have stable IDs. Jumps immediately to the new position. - goTo(mSelectedDay.getTimeInMillis(), false, false, true); + setDate(mSelectedDay.getTimeInMillis(), false, false); } /** @@ -149,30 +239,9 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener { mOnDaySelectedListener = listener; } - /* - * Sets all the required fields for the list view. Override this method to - * set a different list view behavior. - */ - private void setUpListView() { - // Transparent background on scroll - setCacheColorHint(0); - // No dividers - setDivider(null); - // Items are clickable - setItemsCanFocus(true); - // The thumb gets in the way, so disable it - setFastScrollEnabled(false); - setVerticalScrollBarEnabled(false); - setOnScrollListener(this); - setFadingEdgeLength(0); - // Make the scrolling behavior nicer - setFriction(ViewConfiguration.getScrollFriction()); - } - private int getDiffMonths(Calendar start, Calendar end) { final int diffYears = end.get(Calendar.YEAR) - start.get(Calendar.YEAR); - final int diffMonths = end.get(Calendar.MONTH) - start.get(Calendar.MONTH) + 12 * diffYears; - return diffMonths; + return end.get(Calendar.MONTH) - start.get(Calendar.MONTH) + 12 * diffYears; } private int getPositionFromDay(long timeInMillis) { @@ -190,366 +259,13 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener { } /** - * This moves to the specified time in the view. If the time is not already - * in range it will move the list so that the first of the month containing - * the time is at the top of the view. If the new time is already in view - * the list will not be scrolled unless forceScroll is true. This time may - * optionally be highlighted as selected as well. - * - * @param day The day to move to - * @param animate Whether to scroll to the given time or just redraw at the - * new location - * @param setSelected Whether to set the given time as selected - * @param forceScroll Whether to recenter even if the time is already - * visible - * @return Whether or not the view animated to the new location - */ - private boolean goTo(long day, boolean animate, boolean setSelected, boolean forceScroll) { - - // Set the selected day - if (setSelected) { - mSelectedDay.setTimeInMillis(day); - } - - mTempDay.setTimeInMillis(day); - final int position = getPositionFromDay(day); - - View child; - int i = 0; - int top = 0; - // Find a child that's completely in the view - do { - child = getChildAt(i++); - if (child == null) { - break; - } - top = child.getTop(); - } while (top < 0); - - // Compute the first and last position visible - int selectedPosition; - if (child != null) { - selectedPosition = getPositionForView(child); - } else { - selectedPosition = 0; - } - - if (setSelected) { - mAdapter.setSelectedDay(mSelectedDay); - } - - // Check if the selected day is now outside of our visible range - // and if so scroll to the month that contains it - if (position != selectedPosition || forceScroll) { - setMonthDisplayed(mTempDay); - mPreviousScrollState = OnScrollListener.SCROLL_STATE_FLING; - if (animate) { - smoothScrollToPositionFromTop( - position, LIST_TOP_OFFSET, GOTO_SCROLL_DURATION); - return true; - } else { - postSetSelection(position); - } - } else if (setSelected) { - setMonthDisplayed(mSelectedDay); - } - return false; - } - - public void postSetSelection(final int position) { - clearFocus(); - post(new Runnable() { - - @Override - public void run() { - setSelection(position); - } - }); - onScrollStateChanged(this, OnScrollListener.SCROLL_STATE_IDLE); - } - - /** - * Updates the title and selected month if the view has moved to a new - * month. - */ - @Override - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, - int totalItemCount) { - SimpleMonthView child = (SimpleMonthView) view.getChildAt(0); - if (child == null) { - return; - } - - mPreviousScrollState = mCurrentScrollState; - } - - /** - * Sets the month displayed at the top of this view based on time. Override - * to add custom events when the title is changed. - */ - protected void setMonthDisplayed(Calendar date) { - if (mCurrentMonthDisplayed != date.get(Calendar.MONTH)) { - mCurrentMonthDisplayed = date.get(Calendar.MONTH); - invalidateViews(); - } - } - - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) { - // use a post to prevent re-entering onScrollStateChanged before it - // exits - mScrollStateChangedRunnable.doScrollStateChange(view, scrollState); - } - - void setCalendarTextColor(ColorStateList colors) { - mAdapter.setCalendarTextColor(colors); - } - - void setCalendarDayBackgroundColor(ColorStateList dayBackgroundColor) { - mAdapter.setCalendarDayBackgroundColor(dayBackgroundColor); - } - - void setCalendarTextAppearance(int resId) { - mAdapter.setCalendarTextAppearance(resId); - } - - protected class ScrollStateRunnable implements Runnable { - private int mNewState; - private View mParent; - - ScrollStateRunnable(View view) { - mParent = view; - } - - /** - * Sets up the runnable with a short delay in case the scroll state - * immediately changes again. - * - * @param view The list view that changed state - * @param scrollState The new state it changed to - */ - public void doScrollStateChange(AbsListView view, int scrollState) { - mParent.removeCallbacks(this); - mNewState = scrollState; - mParent.postDelayed(this, SCROLL_CHANGE_DELAY); - } - - @Override - public void run() { - mCurrentScrollState = mNewState; - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, - "new scroll state: " + mNewState + " old state: " + mPreviousScrollState); - } - // Fix the position after a scroll or a fling ends - if (mNewState == OnScrollListener.SCROLL_STATE_IDLE - && mPreviousScrollState != OnScrollListener.SCROLL_STATE_IDLE - && mPreviousScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { - mPreviousScrollState = mNewState; - int i = 0; - View child = getChildAt(i); - while (child != null && child.getBottom() <= 0) { - child = getChildAt(++i); - } - if (child == null) { - // The view is no longer visible, just return - return; - } - int firstPosition = getFirstVisiblePosition(); - int lastPosition = getLastVisiblePosition(); - boolean scroll = firstPosition != 0 && lastPosition != getCount() - 1; - final int top = child.getTop(); - final int bottom = child.getBottom(); - final int midpoint = getHeight() / 2; - if (scroll && top < LIST_TOP_OFFSET) { - if (bottom > midpoint) { - smoothScrollBy(top, GOTO_SCROLL_DURATION); - } else { - smoothScrollBy(bottom, GOTO_SCROLL_DURATION); - } - } - } else { - mPreviousScrollState = mNewState; - } - } - } - - /** * Gets the position of the view that is most prominently displayed within the list view. */ public int getMostVisiblePosition() { - final int firstPosition = getFirstVisiblePosition(); - final int height = getHeight(); - - int maxDisplayedHeight = 0; - int mostVisibleIndex = 0; - int i=0; - int bottom = 0; - while (bottom < height) { - View child = getChildAt(i); - if (child == null) { - break; - } - bottom = child.getBottom(); - int displayedHeight = Math.min(bottom, height) - Math.max(0, child.getTop()); - if (displayedHeight > maxDisplayedHeight) { - mostVisibleIndex = i; - maxDisplayedHeight = displayedHeight; - } - i++; - } - return firstPosition + mostVisibleIndex; - } - - /** - * Attempts to return the date that has accessibility focus. - * - * @return The date that has accessibility focus, or {@code null} if no date - * has focus. - */ - private Calendar findAccessibilityFocus() { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - if (child instanceof SimpleMonthView) { - final Calendar focus = ((SimpleMonthView) child).getAccessibilityFocus(); - if (focus != null) { - return focus; - } - } - } - - return null; - } - - /** - * Attempts to restore accessibility focus to a given date. No-op if - * {@code day} is {@code null}. - * - * @param day The date that should receive accessibility focus - * @return {@code true} if focus was restored - */ - private boolean restoreAccessibilityFocus(Calendar day) { - if (day == null) { - return false; - } - - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - if (child instanceof SimpleMonthView) { - if (((SimpleMonthView) child).restoreAccessibilityFocus(day)) { - return true; - } - } - } - - return false; - } - - @Override - protected void layoutChildren() { - final Calendar focusedDay = findAccessibilityFocus(); - super.layoutChildren(); - if (mPerformingScroll) { - mPerformingScroll = false; - } else { - restoreAccessibilityFocus(focusedDay); - } - } - - @Override - protected void onConfigurationChanged(Configuration newConfig) { - mYearFormat = new SimpleDateFormat("yyyy", Locale.getDefault()); - } - - /** @hide */ - @Override - public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { - super.onInitializeAccessibilityEventInternal(event); - event.setItemCount(-1); - } - - private String getMonthAndYearString(Calendar day) { - final StringBuilder sbuf = new StringBuilder(); - sbuf.append(day.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault())); - sbuf.append(" "); - sbuf.append(mYearFormat.format(day.getTime())); - return sbuf.toString(); - } - - /** - * Necessary for accessibility, to ensure we support "scrolling" forward and backward - * in the month list. - * - * @hide - */ - @Override - public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfoInternal(info); - info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD); - info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD); - } - - /** - * When scroll forward/backward events are received, announce the newly scrolled-to month. - * - * @hide - */ - @Override - public boolean performAccessibilityActionInternal(int action, Bundle arguments) { - if (action != AccessibilityNodeInfo.ACTION_SCROLL_FORWARD && - action != AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) { - return super.performAccessibilityActionInternal(action, arguments); - } - - // Figure out what month is showing. - final int firstVisiblePosition = getFirstVisiblePosition(); - final int month = firstVisiblePosition % 12; - final int year = firstVisiblePosition / 12 + mMinDate.get(Calendar.YEAR); - final Calendar day = Calendar.getInstance(); - day.set(year, month, 1); - - // Scroll either forward or backward one month. - if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) { - day.add(Calendar.MONTH, 1); - if (day.get(Calendar.MONTH) == 12) { - day.set(Calendar.MONTH, 0); - day.add(Calendar.YEAR, 1); - } - } else if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) { - View firstVisibleView = getChildAt(0); - // If the view is fully visible, jump one month back. Otherwise, we'll just jump - // to the first day of first visible month. - if (firstVisibleView != null && firstVisibleView.getTop() >= -1) { - // There's an off-by-one somewhere, so the top of the first visible item will - // actually be -1 when it's at the exact top. - day.add(Calendar.MONTH, -1); - if (day.get(Calendar.MONTH) == -1) { - day.set(Calendar.MONTH, 11); - day.add(Calendar.YEAR, -1); - } - } - } - - // Go to that month. - announceForAccessibility(getMonthAndYearString(day)); - goTo(day.getTimeInMillis(), true, false, true); - mPerformingScroll = true; - return true; + return getCurrentItem(); } public interface OnDaySelectedListener { public void onDaySelected(DayPickerView view, Calendar day); } - - private final SimpleMonthAdapter.OnDaySelectedListener - mProxyOnDaySelectedListener = new SimpleMonthAdapter.OnDaySelectedListener() { - @Override - public void onDaySelected(SimpleMonthAdapter adapter, Calendar day) { - if (mOnDaySelectedListener != null) { - mOnDaySelectedListener.onDaySelected(DayPickerView.this, day); - } - } - }; } diff --git a/core/java/android/widget/SimpleMonthAdapter.java b/core/java/android/widget/SimpleMonthAdapter.java deleted file mode 100644 index c807d56..0000000 --- a/core/java/android/widget/SimpleMonthAdapter.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.widget; - -import com.android.internal.R; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.TypedArray; -import android.graphics.Color; -import android.view.View; -import android.view.ViewGroup; -import android.widget.SimpleMonthView.OnDayClickListener; - -import java.util.Calendar; - -/** - * An adapter for a list of {@link android.widget.SimpleMonthView} items. - */ -class SimpleMonthAdapter extends BaseAdapter { - private final Calendar mMinDate = Calendar.getInstance(); - private final Calendar mMaxDate = Calendar.getInstance(); - - private final Context mContext; - - private Calendar mSelectedDay = Calendar.getInstance(); - private ColorStateList mCalendarTextColors = ColorStateList.valueOf(Color.BLACK); - private ColorStateList mCalendarDayBackgroundColor = ColorStateList.valueOf(Color.MAGENTA); - private OnDaySelectedListener mOnDaySelectedListener; - - private int mFirstDayOfWeek; - - public SimpleMonthAdapter(Context context) { - mContext = context; - } - - public void setRange(Calendar min, Calendar max) { - mMinDate.setTimeInMillis(min.getTimeInMillis()); - mMaxDate.setTimeInMillis(max.getTimeInMillis()); - - notifyDataSetInvalidated(); - } - - public void setFirstDayOfWeek(int firstDayOfWeek) { - mFirstDayOfWeek = firstDayOfWeek; - - notifyDataSetInvalidated(); - } - - public int getFirstDayOfWeek() { - return mFirstDayOfWeek; - } - - /** - * Updates the selected day and related parameters. - * - * @param day The day to highlight - */ - public void setSelectedDay(Calendar day) { - mSelectedDay = day; - - notifyDataSetChanged(); - } - - /** - * Sets the listener to call when the user selects a day. - * - * @param listener The listener to call. - */ - public void setOnDaySelectedListener(OnDaySelectedListener listener) { - mOnDaySelectedListener = listener; - } - - void setCalendarTextColor(ColorStateList colors) { - mCalendarTextColors = colors; - } - - void setCalendarDayBackgroundColor(ColorStateList dayBackgroundColor) { - mCalendarDayBackgroundColor = dayBackgroundColor; - } - - /** - * Sets the text color, size, style, hint color, and highlight color from - * the specified TextAppearance resource. This is mostly copied from - * {@link TextView#setTextAppearance(Context, int)}. - */ - void setCalendarTextAppearance(int resId) { - final TypedArray a = mContext.obtainStyledAttributes(resId, R.styleable.TextAppearance); - - final ColorStateList textColor = a.getColorStateList(R.styleable.TextAppearance_textColor); - if (textColor != null) { - mCalendarTextColors = textColor; - } - - // TODO: Support font size, etc. - - a.recycle(); - } - - @Override - public int getCount() { - final int diffYear = mMaxDate.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR); - final int diffMonth = mMaxDate.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH); - return diffMonth + 12 * diffYear + 1; - } - - @Override - public Object getItem(int position) { - return null; - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public boolean hasStableIds() { - return true; - } - - @SuppressWarnings("unchecked") - @Override - public View getView(int position, View convertView, ViewGroup parent) { - final SimpleMonthView v; - if (convertView != null) { - v = (SimpleMonthView) convertView; - } else { - v = new SimpleMonthView(mContext); - - // Set up the new view - final AbsListView.LayoutParams params = new AbsListView.LayoutParams( - AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.MATCH_PARENT); - v.setLayoutParams(params); - v.setClickable(true); - v.setOnDayClickListener(mOnDayClickListener); - - v.setMonthTextColor(mCalendarTextColors); - v.setDayOfWeekTextColor(mCalendarTextColors); - v.setDayTextColor(mCalendarTextColors); - - v.setDayBackgroundColor(mCalendarDayBackgroundColor); - } - - final int minMonth = mMinDate.get(Calendar.MONTH); - final int minYear = mMinDate.get(Calendar.YEAR); - final int currentMonth = position + minMonth; - final int month = currentMonth % 12; - final int year = currentMonth / 12 + minYear; - final int selectedDay; - if (isSelectedDayInMonth(year, month)) { - selectedDay = mSelectedDay.get(Calendar.DAY_OF_MONTH); - } else { - selectedDay = -1; - } - - // Invokes requestLayout() to ensure that the recycled view is set with the appropriate - // height/number of weeks before being displayed. - v.reuse(); - - final int enabledDayRangeStart; - if (minMonth == month && minYear == year) { - enabledDayRangeStart = mMinDate.get(Calendar.DAY_OF_MONTH); - } else { - enabledDayRangeStart = 1; - } - - final int enabledDayRangeEnd; - if (mMaxDate.get(Calendar.MONTH) == month && mMaxDate.get(Calendar.YEAR) == year) { - enabledDayRangeEnd = mMaxDate.get(Calendar.DAY_OF_MONTH); - } else { - enabledDayRangeEnd = 31; - } - - v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek, - enabledDayRangeStart, enabledDayRangeEnd); - v.invalidate(); - - return v; - } - - private boolean isSelectedDayInMonth(int year, int month) { - return mSelectedDay.get(Calendar.YEAR) == year && mSelectedDay.get(Calendar.MONTH) == month; - } - - private boolean isCalendarInRange(Calendar value) { - return value.compareTo(mMinDate) >= 0 && value.compareTo(mMaxDate) <= 0; - } - - private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() { - @Override - public void onDayClick(SimpleMonthView view, Calendar day) { - if (day != null && isCalendarInRange(day)) { - setSelectedDay(day); - - if (mOnDaySelectedListener != null) { - mOnDaySelectedListener.onDaySelected(SimpleMonthAdapter.this, day); - } - } - } - }; - - public interface OnDaySelectedListener { - public void onDaySelected(SimpleMonthAdapter view, Calendar day); - } -} diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java index 58ad515..4e5a39a 100644 --- a/core/java/android/widget/SimpleMonthView.java +++ b/core/java/android/widget/SimpleMonthView.java @@ -18,8 +18,8 @@ package android.widget; import android.content.Context; import android.content.res.ColorStateList; -import android.content.res.Configuration; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Align; @@ -29,8 +29,6 @@ import android.graphics.Typeface; import android.os.Bundle; import android.text.TextPaint; import android.text.format.DateFormat; -import android.text.format.DateUtils; -import android.text.format.Time; import android.util.AttributeSet; import android.util.IntArray; import android.util.StateSet; @@ -38,13 +36,13 @@ import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import com.android.internal.R; import com.android.internal.widget.ExploreByTouchHelper; import java.text.SimpleDateFormat; import java.util.Calendar; -import java.util.Formatter; import java.util.Locale; /** @@ -52,93 +50,80 @@ import java.util.Locale; * within the specified month. */ class SimpleMonthView extends View { - private static final int MIN_ROW_HEIGHT = 10; + private static final int DAYS_IN_WEEK = 7; + private static final int MAX_WEEKS_IN_MONTH = 6; private static final int DEFAULT_SELECTED_DAY = -1; private static final int DEFAULT_WEEK_START = Calendar.SUNDAY; - private static final int DEFAULT_NUM_DAYS = 7; - private static final int DEFAULT_NUM_ROWS = 6; - private static final int MAX_NUM_ROWS = 6; - private final Formatter mFormatter; - private final StringBuilder mStringBuilder; - - private final int mMonthTextSize; - private final int mDayOfWeekTextSize; - private final int mDayTextSize; - - /** Height of the header containing the month and day of week labels. */ - private final int mMonthHeaderHeight; + private static final String DEFAULT_TITLE_FORMAT = "MMMMy"; + private static final String DAY_OF_WEEK_FORMAT = "EEEEE"; private final TextPaint mMonthPaint = new TextPaint(); private final TextPaint mDayOfWeekPaint = new TextPaint(); private final TextPaint mDayPaint = new TextPaint(); + private final Paint mDaySelectorPaint = new Paint(); + private final Paint mDayHighlightPaint = new Paint(); - private final Paint mDayBackgroundPaint = new Paint(); + private final Calendar mCalendar = Calendar.getInstance(); + private final Calendar mDayLabelCalendar = Calendar.getInstance(); - /** Single-letter (when available) formatter for the day of week label. */ - private SimpleDateFormat mDayFormatter = new SimpleDateFormat("EEEEE", Locale.getDefault()); + private final MonthViewTouchHelper mTouchHelper; - // affects the padding on the sides of this view - private int mPadding = 0; + private final SimpleDateFormat mTitleFormatter; + private final SimpleDateFormat mDayOfWeekFormatter; - private String mDayOfWeekTypeface; - private String mMonthTypeface; + private CharSequence mTitle; private int mMonth; private int mYear; - // Quick reference to the width of this view, matches parent - private int mWidth; - - // The height this view should draw at in pixels, set by height param - private final int mRowHeight; + private int mPaddedWidth; + private int mPaddedHeight; - // If this view contains the today - private boolean mHasToday = false; + private final int mMonthHeight; + private final int mDayOfWeekHeight; + private final int mDayHeight; + private final int mCellWidth; + private final int mDaySelectorRadius; - // Which day is selected [0-6] or -1 if no day is selected + /** The day of month for the selected day, or -1 if no day is selected. */ private int mActivatedDay = -1; - // Which day is today [0-6] or -1 if no day is today + /** + * The day of month for today, or -1 if the today is not in the current + * month. + */ private int mToday = DEFAULT_SELECTED_DAY; - // Which day of the week to start on [0-6] + /** The first day of the week (ex. Calendar.SUNDAY). */ private int mWeekStart = DEFAULT_WEEK_START; - // How many days to display - private int mNumDays = DEFAULT_NUM_DAYS; - - // The number of days + a spot for week number if it is displayed - private int mNumCells = mNumDays; + /** The number of days (ex. 28) in the current month. */ + private int mDaysInMonth; - private int mDayOfWeekStart = 0; + /** + * The day of week (ex. Calendar.SUNDAY) for the first day of the current + * month. + */ + private int mDayOfWeekStart; - // First enabled day + /** The day of month for the first (inclusive) enabled day. */ private int mEnabledDayStart = 1; - // Last enabled day + /** The day of month for the last (inclusive) enabled day. */ private int mEnabledDayEnd = 31; - private final Calendar mCalendar = Calendar.getInstance(); - private final Calendar mDayLabelCalendar = Calendar.getInstance(); - - private final MonthViewTouchHelper mTouchHelper; - - private int mNumRows = DEFAULT_NUM_ROWS; + /** The number of week rows needed to display the current month. */ + private int mNumWeeks = MAX_WEEKS_IN_MONTH; - // Optional listener for handling day click actions + /** Optional listener for handling day click actions. */ private OnDayClickListener mOnDayClickListener; - // Whether to prevent setting the accessibility delegate - private boolean mLockAccessibilityDelegate; - - private int mNormalTextColor; - private int mDisabledTextColor; - private int mSelectedDayColor; - private ColorStateList mDayTextColor; + private int mTouchedDay = -1; + public SimpleMonthView(Context context) { this(context, null); } @@ -155,64 +140,123 @@ class SimpleMonthView extends View { super(context, attrs, defStyleAttr, defStyleRes); final Resources res = context.getResources(); - mDayOfWeekTypeface = res.getString(R.string.day_of_week_label_typeface); - mMonthTypeface = res.getString(R.string.sans_serif); - - mStringBuilder = new StringBuilder(50); - mFormatter = new Formatter(mStringBuilder, Locale.getDefault()); - - mDayTextSize = res.getDimensionPixelSize(R.dimen.datepicker_day_number_size); - mMonthTextSize = res.getDimensionPixelSize(R.dimen.datepicker_month_label_size); - mDayOfWeekTextSize = res.getDimensionPixelSize( - R.dimen.datepicker_month_day_label_text_size); - mMonthHeaderHeight = res.getDimensionPixelOffset( - R.dimen.datepicker_month_list_item_header_height); - - mRowHeight = Math.max(MIN_ROW_HEIGHT, - (res.getDimensionPixelOffset(R.dimen.datepicker_view_animator_height) - - mMonthHeaderHeight) / MAX_NUM_ROWS); + mMonthHeight = res.getDimensionPixelSize(R.dimen.date_picker_month_height); + mDayOfWeekHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_of_week_height); + mDayHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_height); + mCellWidth = res.getDimensionPixelSize(R.dimen.date_picker_day_width); + mDaySelectorRadius = res.getDimensionPixelSize(R.dimen.date_picker_day_selector_radius); // Set up accessibility components. mTouchHelper = new MonthViewTouchHelper(this); setAccessibilityDelegate(mTouchHelper); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); - mLockAccessibilityDelegate = true; - initPaints(); + final Locale locale = res.getConfiguration().locale; + final String titleFormat = DateFormat.getBestDateTimePattern(locale, DEFAULT_TITLE_FORMAT); + mTitleFormatter = new SimpleDateFormat(titleFormat, locale); + mDayOfWeekFormatter = new SimpleDateFormat(DAY_OF_WEEK_FORMAT, locale); + + setClickable(true); + initPaints(res); + } + + /** + * Applies the specified text appearance resource to a paint, returning the + * text color if one is set in the text appearance. + * + * @param p the paint to modify + * @param resId the resource ID of the text appearance + * @return the text color, if available + */ + private ColorStateList applyTextAppearance(Paint p, int resId) { + final TypedArray ta = mContext.obtainStyledAttributes(null, + R.styleable.TextAppearance, 0, resId); + + final String fontFamily = ta.getString(R.styleable.TextAppearance_fontFamily); + if (fontFamily != null) { + p.setTypeface(Typeface.create(fontFamily, 0)); + } + + p.setTextSize(ta.getDimensionPixelSize( + R.styleable.TextAppearance_textSize, (int) p.getTextSize())); + + final ColorStateList textColor = ta.getColorStateList(R.styleable.TextAppearance_textColor); + if (textColor != null) { + final int enabledColor = textColor.getColorForState(ENABLED_STATE_SET, 0); + p.setColor(enabledColor); + } + + ta.recycle(); + + return textColor; + } + + public void setMonthTextAppearance(int resId) { + applyTextAppearance(mMonthPaint, resId); + invalidate(); + } + + public void setDayOfWeekTextAppearance(int resId) { + applyTextAppearance(mDayOfWeekPaint, resId); + invalidate(); + } + + public void setDayTextAppearance(int resId) { + final ColorStateList textColor = applyTextAppearance(mDayPaint, resId); + if (textColor != null) { + mDayTextColor = textColor; + } + + invalidate(); + } + + public CharSequence getTitle() { + if (mTitle == null) { + mTitle = mTitleFormatter.format(mCalendar.getTime()); + } + return mTitle; } /** * Sets up the text and style properties for painting. */ - private void initPaints() { + private void initPaints(Resources res) { + final String monthTypeface = res.getString(R.string.date_picker_month_typeface); + final String dayOfWeekTypeface = res.getString(R.string.date_picker_day_of_week_typeface); + final String dayTypeface = res.getString(R.string.date_picker_day_typeface); + + final int monthTextSize = res.getDimensionPixelSize( + R.dimen.date_picker_month_text_size); + final int dayOfWeekTextSize = res.getDimensionPixelSize( + R.dimen.date_picker_day_of_week_text_size); + final int dayTextSize = res.getDimensionPixelSize( + R.dimen.date_picker_day_text_size); + mMonthPaint.setAntiAlias(true); - mMonthPaint.setTextSize(mMonthTextSize); - mMonthPaint.setTypeface(Typeface.create(mMonthTypeface, Typeface.BOLD)); + mMonthPaint.setTextSize(monthTextSize); + mMonthPaint.setTypeface(Typeface.create(monthTypeface, 0)); mMonthPaint.setTextAlign(Align.CENTER); mMonthPaint.setStyle(Style.FILL); mDayOfWeekPaint.setAntiAlias(true); - mDayOfWeekPaint.setTextSize(mDayOfWeekTextSize); - mDayOfWeekPaint.setTypeface(Typeface.create(mDayOfWeekTypeface, Typeface.BOLD)); + mDayOfWeekPaint.setTextSize(dayOfWeekTextSize); + mDayOfWeekPaint.setTypeface(Typeface.create(dayOfWeekTypeface, 0)); mDayOfWeekPaint.setTextAlign(Align.CENTER); mDayOfWeekPaint.setStyle(Style.FILL); - mDayBackgroundPaint.setAntiAlias(true); - mDayBackgroundPaint.setStyle(Style.FILL); + mDaySelectorPaint.setAntiAlias(true); + mDaySelectorPaint.setStyle(Style.FILL); + + mDayHighlightPaint.setAntiAlias(true); + mDayHighlightPaint.setStyle(Style.FILL); mDayPaint.setAntiAlias(true); - mDayPaint.setTextSize(mDayTextSize); + mDayPaint.setTextSize(dayTextSize); + mDayPaint.setTypeface(Typeface.create(dayTypeface, 0)); mDayPaint.setTextAlign(Align.CENTER); mDayPaint.setStyle(Style.FILL); } - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - - mDayFormatter = new SimpleDateFormat("EEEEE", newConfig.locale); - } - void setMonthTextColor(ColorStateList monthTextColor) { final int enabledColor = monthTextColor.getColorForState(ENABLED_STATE_SET, 0); mMonthPaint.setColor(enabledColor); @@ -230,20 +274,18 @@ class SimpleMonthView extends View { invalidate(); } - void setDayBackgroundColor(ColorStateList dayBackgroundColor) { + void setDaySelectorColor(ColorStateList dayBackgroundColor) { final int activatedColor = dayBackgroundColor.getColorForState( StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0); - mDayBackgroundPaint.setColor(activatedColor); + mDaySelectorPaint.setColor(activatedColor); invalidate(); } - @Override - public void setAccessibilityDelegate(AccessibilityDelegate delegate) { - // Workaround for a JB MR1 issue where accessibility delegates on - // top-level ListView items are overwritten. - if (!mLockAccessibilityDelegate) { - super.setAccessibilityDelegate(delegate); - } + void setDayHighlightColor(ColorStateList dayHighlightColor) { + final int pressedColor = dayHighlightColor.getColorForState( + StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED), 0); + mDayHighlightPaint.setColor(pressedColor); + invalidate(); } public void setOnDayClickListener(OnDayClickListener listener) { @@ -253,30 +295,124 @@ class SimpleMonthView extends View { @Override public boolean dispatchHoverEvent(MotionEvent event) { // First right-of-refusal goes the touch exploration helper. - if (mTouchHelper.dispatchHoverEvent(event)) { - return true; - } - return super.dispatchHoverEvent(event); + return mTouchHelper.dispatchHoverEvent(event) || super.dispatchHoverEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { - case MotionEvent.ACTION_UP: - final int day = getDayFromLocation(event.getX(), event.getY()); - if (day >= 0) { - onDayClick(day); + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_MOVE: + final int touchedDay = getDayAtLocation(event.getX(), event.getY()); + if (mTouchedDay != touchedDay) { + mTouchedDay = touchedDay; + invalidate(); } break; + + case MotionEvent.ACTION_UP: + final int clickedDay = getDayAtLocation(event.getX(), event.getY()); + onDayClicked(clickedDay); + // Fall through. + case MotionEvent.ACTION_CANCEL: + // Reset touched day on stream end. + mTouchedDay = -1; + invalidate(); + break; } return true; } @Override protected void onDraw(Canvas canvas) { - drawMonthTitle(canvas); - drawWeekDayLabels(canvas); + final int paddingLeft = getPaddingLeft(); + final int paddingTop = getPaddingTop(); + canvas.translate(paddingLeft, paddingTop); + + drawMonth(canvas); + drawDaysOfWeek(canvas); drawDays(canvas); + + canvas.translate(-paddingLeft, -paddingTop); + } + + private void drawMonth(Canvas canvas) { + final float x = mPaddedWidth / 2f; + + // Vertically centered within the month header height. + final float lineHeight = mMonthPaint.ascent() + mMonthPaint.descent(); + final float y = (mMonthHeight - lineHeight) / 2f; + + canvas.drawText(getTitle().toString(), x, y, mMonthPaint); + } + + private void drawDaysOfWeek(Canvas canvas) { + final float cellWidthHalf = mPaddedWidth / (DAYS_IN_WEEK * 2); + + // Vertically centered within the cell height. + final float lineHeight = mDayOfWeekPaint.ascent() + mDayOfWeekPaint.descent(); + final float y = mMonthHeight + (mDayOfWeekHeight - lineHeight) / 2f; + + for (int i = 0; i < DAYS_IN_WEEK; i++) { + final int calendarDay = (i + mWeekStart) % DAYS_IN_WEEK; + mDayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay); + + final String dayLabel = mDayOfWeekFormatter.format(mDayLabelCalendar.getTime()); + final float x = (2 * i + 1) * cellWidthHalf; + canvas.drawText(dayLabel, x, y, mDayOfWeekPaint); + } + } + + /** + * Draws the month days. + */ + private void drawDays(Canvas canvas) { + final int cellWidthHalf = mPaddedWidth / (DAYS_IN_WEEK * 2); + + // Vertically centered within the cell height. + final float halfLineHeight = (mDayPaint.ascent() + mDayPaint.descent()) / 2; + float centerY = mMonthHeight + mDayOfWeekHeight + mDayHeight / 2f; + + for (int day = 1, j = findDayOffset(); day <= mDaysInMonth; day++) { + final int x = (2 * j + 1) * cellWidthHalf; + int stateMask = 0; + + if (day >= mEnabledDayStart && day <= mEnabledDayEnd) { + stateMask |= StateSet.VIEW_STATE_ENABLED; + } + + final boolean isDayActivated = mActivatedDay == day; + if (isDayActivated) { + stateMask |= StateSet.VIEW_STATE_ACTIVATED; + + // Adjust the circle to be centered on the row. + canvas.drawCircle(x, centerY, mDaySelectorRadius, mDaySelectorPaint); + } else if (mTouchedDay == day) { + stateMask |= StateSet.VIEW_STATE_PRESSED; + + // Adjust the circle to be centered on the row. + canvas.drawCircle(x, centerY, mDaySelectorRadius, mDayHighlightPaint); + } + + final boolean isDayToday = mToday == day; + final int dayTextColor; + if (isDayToday && !isDayActivated) { + dayTextColor = mDaySelectorPaint.getColor(); + } else { + final int[] stateSet = StateSet.get(stateMask); + dayTextColor = mDayTextColor.getColorForState(stateSet, 0); + } + mDayPaint.setColor(dayTextColor); + + canvas.drawText("" + day, x, centerY - halfLineHeight, mDayPaint); + + j++; + + if (j == DAYS_IN_WEEK) { + j = 0; + centerY += mDayHeight; + } + } } private static boolean isValidDayOfWeek(int day) { @@ -288,18 +424,52 @@ class SimpleMonthView extends View { } /** - * Sets all the parameters for displaying this week. Parameters have a default value and - * will only update if a new value is included, except for focus month, which will always - * default to no focus month if no value is passed in. The only required parameter is the - * week start. + * Sets the selected day. * - * @param selectedDay the selected day of the month, or -1 for no selection. - * @param month the month. - * @param year the year. - * @param weekStart which day the week should start on. {@link Calendar#SUNDAY} through - * {@link Calendar#SATURDAY}. - * @param enabledDayStart the first enabled day. - * @param enabledDayEnd the last enabled day. + * @param dayOfMonth the selected day of the month, or {@code -1} to clear + * the selection + */ + public void setSelectedDay(int dayOfMonth) { + mActivatedDay = dayOfMonth; + + // Invalidate cached accessibility information. + mTouchHelper.invalidateRoot(); + invalidate(); + } + + /** + * Sets the first day of the week. + * + * @param weekStart which day the week should start on, valid values are + * {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY} + */ + public void setFirstDayOfWeek(int weekStart) { + if (isValidDayOfWeek(weekStart)) { + mWeekStart = weekStart; + } else { + mWeekStart = mCalendar.getFirstDayOfWeek(); + } + + // Invalidate cached accessibility information. + mTouchHelper.invalidateRoot(); + invalidate(); + } + + /** + * Sets all the parameters for displaying this week. + * <p> + * Parameters have a default value and will only update if a new value is + * included, except for focus month, which will always default to no focus + * month if no value is passed in. The only required parameter is the week + * start. + * + * @param selectedDay the selected day of the month, or -1 for no selection + * @param month the month + * @param year the year + * @param weekStart which day the week should start on, valid values are + * {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY} + * @param enabledDayStart the first enabled day + * @param enabledDayEnd the last enabled day */ void setMonthParams(int selectedDay, int month, int year, int weekStart, int enabledDayStart, int enabledDayEnd) { @@ -310,12 +480,6 @@ class SimpleMonthView extends View { } mYear = year; - // Figure out what day today is - final Time today = new Time(Time.getCurrentTimezone()); - today.setToNow(); - mHasToday = false; - mToday = -1; - mCalendar.set(Calendar.MONTH, mMonth); mCalendar.set(Calendar.YEAR, mYear); mCalendar.set(Calendar.DAY_OF_MONTH, 1); @@ -334,15 +498,20 @@ class SimpleMonthView extends View { mEnabledDayEnd = enabledDayEnd; } - mNumCells = getDaysInMonth(mMonth, mYear); - for (int i = 0; i < mNumCells; i++) { + // Figure out what day today is. + final Calendar today = Calendar.getInstance(); + mToday = -1; + mDaysInMonth = getDaysInMonth(mMonth, mYear); + for (int i = 0; i < mDaysInMonth; i++) { final int day = i + 1; if (sameDay(day, today)) { - mHasToday = true; mToday = day; } } - mNumRows = calculateNumRows(); + mNumWeeks = calculateNumRows(); + + // Invalidate the old title. + mTitle = null; // Invalidate cached accessibility information. mTouchHelper.invalidateRoot(); @@ -371,154 +540,118 @@ class SimpleMonthView extends View { } public void reuse() { - mNumRows = DEFAULT_NUM_ROWS; + mNumWeeks = MAX_WEEKS_IN_MONTH; requestLayout(); } private int calculateNumRows() { - int offset = findDayOffset(); - int dividend = (offset + mNumCells) / mNumDays; - int remainder = (offset + mNumCells) % mNumDays; - return (dividend + (remainder > 0 ? 1 : 0)); + final int offset = findDayOffset(); + final int dividend = (offset + mDaysInMonth) / DAYS_IN_WEEK; + final int remainder = (offset + mDaysInMonth) % DAYS_IN_WEEK; + return dividend + (remainder > 0 ? 1 : 0); } - private boolean sameDay(int day, Time today) { - return mYear == today.year && - mMonth == today.month && - day == today.monthDay; + private boolean sameDay(int day, Calendar today) { + return mYear == today.get(Calendar.YEAR) && mMonth == today.get(Calendar.MONTH) + && day == today.get(Calendar.DAY_OF_MONTH); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mRowHeight * mNumRows - + mMonthHeaderHeight); + final int preferredHeight = mDayHeight * mNumWeeks + mDayOfWeekHeight + mMonthHeight + + getPaddingTop() + getPaddingBottom(); + final int preferredWidth = mCellWidth * DAYS_IN_WEEK + + getPaddingStart() + getPaddingEnd(); + final int resolvedWidth = resolveSize(preferredWidth, widthMeasureSpec); + final int resolvedHeight = resolveSize(preferredHeight, heightMeasureSpec); + setMeasuredDimension(resolvedWidth, resolvedHeight); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { - mWidth = w; + mPaddedWidth = w - getPaddingLeft() - getPaddingRight(); + mPaddedHeight = w - getPaddingTop() - getPaddingBottom(); // Invalidate cached accessibility information. mTouchHelper.invalidateRoot(); } - private String getMonthAndYearString() { - int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR - | DateUtils.FORMAT_NO_MONTH_DAY; - mStringBuilder.setLength(0); - long millis = mCalendar.getTimeInMillis(); - return DateUtils.formatDateRange(getContext(), mFormatter, millis, millis, flags, - Time.getCurrentTimezone()).toString(); - } - - private void drawMonthTitle(Canvas canvas) { - final float x = (mWidth + 2 * mPadding) / 2f; - - // Centered on the upper half of the month header. - final float lineHeight = mMonthPaint.ascent() + mMonthPaint.descent(); - final float y = mMonthHeaderHeight * 0.25f - lineHeight / 2f; - - canvas.drawText(getMonthAndYearString(), x, y, mMonthPaint); - } - - private void drawWeekDayLabels(Canvas canvas) { - final float dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2); - - // Centered on the lower half of the month header. - final float lineHeight = mDayOfWeekPaint.ascent() + mDayOfWeekPaint.descent(); - final float y = mMonthHeaderHeight * 0.75f - lineHeight / 2f; - - for (int i = 0; i < mNumDays; i++) { - final int calendarDay = (i + mWeekStart) % mNumDays; - mDayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay); - - final String dayLabel = mDayFormatter.format(mDayLabelCalendar.getTime()); - final float x = (2 * i + 1) * dayWidthHalf + mPadding; - canvas.drawText(dayLabel, x, y, mDayOfWeekPaint); + private int findDayOffset() { + final int offset = mDayOfWeekStart - mWeekStart; + if (mDayOfWeekStart < mWeekStart) { + return offset + DAYS_IN_WEEK; } + return offset; } /** - * Draws the month days. + * Calculates the day of the month at the specified touch position. Returns + * the day of the month or -1 if the position wasn't in a valid day. + * + * @param x the x position of the touch event + * @param y the y position of the touch event + * @return the day of the month at (x, y) or -1 if the position wasn't in a + * valid day */ - private void drawDays(Canvas canvas) { - final int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2); - - // Centered within the row. - final float lineHeight = mDayOfWeekPaint.ascent() + mDayOfWeekPaint.descent(); - float y = mMonthHeaderHeight + (mRowHeight - lineHeight) / 2f; - - for (int day = 1, j = findDayOffset(); day <= mNumCells; day++) { - final int x = (2 * j + 1) * dayWidthHalf + mPadding; - int stateMask = 0; - - if (day >= mEnabledDayStart && day <= mEnabledDayEnd) { - stateMask |= StateSet.VIEW_STATE_ENABLED; - } - - if (mActivatedDay == day) { - stateMask |= StateSet.VIEW_STATE_ACTIVATED; - - // Adjust the circle to be centered the row. - final float rowCenterY = y + lineHeight / 2; - canvas.drawCircle(x, rowCenterY, mRowHeight / 2, - mDayBackgroundPaint); - } - - final int[] stateSet = StateSet.get(stateMask); - final int dayTextColor = mDayTextColor.getColorForState(stateSet, 0); - mDayPaint.setColor(dayTextColor); - - final boolean isDayToday = mHasToday && mToday == day; - mDayPaint.setFakeBoldText(isDayToday); - - canvas.drawText(String.format("%d", day), x, y, mDayPaint); + private int getDayAtLocation(float x, float y) { + final int paddedX = (int) (x - getPaddingLeft() + 0.5f); + if (paddedX < 0 || paddedX >= mPaddedWidth) { + return -1; + } - j++; + final int headerHeight = mMonthHeight + mDayOfWeekHeight; + final int paddedY = (int) (y - getPaddingTop() + 0.5f); + if (paddedY < headerHeight || paddedY >= mPaddedHeight) { + return -1; + } - if (j == mNumDays) { - j = 0; - y += mRowHeight; - } + final int row = (paddedY - headerHeight) / mDayHeight; + final int col = (paddedX * DAYS_IN_WEEK) / mPaddedWidth; + final int index = col + row * DAYS_IN_WEEK; + final int day = index + 1 - findDayOffset(); + if (day < 1 || day > mDaysInMonth) { + return -1; } - } - private int findDayOffset() { - return (mDayOfWeekStart < mWeekStart ? (mDayOfWeekStart + mNumDays) : mDayOfWeekStart) - - mWeekStart; + return day; } /** - * Calculates the day that the given x position is in, accounting for week - * number. Returns the day or -1 if the position wasn't in a day. + * Calculates the bounds of the specified day. * - * @param x The x position of the touch event - * @return The day number, or -1 if the position wasn't in a day + * @param day the day of the month + * @param outBounds the rect to populate with bounds */ - private int getDayFromLocation(float x, float y) { - int dayStart = mPadding; - if (x < dayStart || x > mWidth - mPadding) { - return -1; + private boolean getBoundsForDay(int day, Rect outBounds) { + if (day < 1 || day > mDaysInMonth) { + return false; } - // Selection is (x - start) / (pixels/day) == (x -s) * day / pixels - int row = (int) (y - mMonthHeaderHeight) / mRowHeight; - int column = (int) ((x - dayStart) * mNumDays / (mWidth - dayStart - mPadding)); - int day = column - findDayOffset() + 1; - day += row * mNumDays; - if (day < 1 || day > mNumCells) { - return -1; - } - return day; + final int index = day - 1 + findDayOffset(); + final int row = index / DAYS_IN_WEEK; + final int col = index % DAYS_IN_WEEK; + + final int headerHeight = mMonthHeight + mDayOfWeekHeight; + final int paddedY = row * mDayHeight + headerHeight; + final int paddedX = col * mPaddedWidth; + + final int y = paddedY + getPaddingTop(); + final int x = paddedX + getPaddingLeft(); + + final int cellHeight = mDayHeight; + final int cellWidth = mPaddedWidth / DAYS_IN_WEEK; + outBounds.set(x, y, (x + cellWidth), (y + cellHeight)); + + return true; } /** * Called when the user clicks on a day. Handles callbacks to the * {@link OnDayClickListener} if one is set. * - * @param day The day that was clicked + * @param day the day that was clicked */ - private void onDayClick(int day) { + private void onDayClicked(int day) { if (mOnDayClickListener != null) { Calendar date = Calendar.getInstance(); date.set(mYear, mMonth, day); @@ -530,44 +663,6 @@ class SimpleMonthView extends View { } /** - * @return The date that has accessibility focus, or {@code null} if no date - * has focus - */ - Calendar getAccessibilityFocus() { - final int day = mTouchHelper.getFocusedVirtualView(); - Calendar date = null; - if (day >= 0) { - date = Calendar.getInstance(); - date.set(mYear, mMonth, day); - } - return date; - } - - /** - * Clears accessibility focus within the view. No-op if the view does not - * contain accessibility focus. - */ - public void clearAccessibilityFocus() { - mTouchHelper.clearFocusedVirtualView(); - } - - /** - * Attempts to restore accessibility focus to the specified date. - * - * @param day The date which should receive focus - * @return {@code false} if the date is not valid for this month view, or - * {@code true} if the date received focus - */ - boolean restoreAccessibilityFocus(Calendar day) { - if ((day.get(Calendar.YEAR) != mYear) || (day.get(Calendar.MONTH) != mMonth) || - (day.get(Calendar.DAY_OF_MONTH) > mNumCells)) { - return false; - } - mTouchHelper.setFocusedVirtualView(day.get(Calendar.DAY_OF_MONTH)); - return true; - } - - /** * Provides a virtual view hierarchy for interfacing with an accessibility * service. */ @@ -581,24 +676,9 @@ class SimpleMonthView extends View { super(host); } - public void setFocusedVirtualView(int virtualViewId) { - getAccessibilityNodeProvider(SimpleMonthView.this).performAction( - virtualViewId, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); - } - - public void clearFocusedVirtualView() { - final int focusedVirtualView = getFocusedVirtualView(); - if (focusedVirtualView != ExploreByTouchHelper.INVALID_ID) { - getAccessibilityNodeProvider(SimpleMonthView.this).performAction( - focusedVirtualView, - AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, - null); - } - } - @Override protected int getVirtualViewAt(float x, float y) { - final int day = getDayFromLocation(x, y); + final int day = getDayAtLocation(x, y); if (day >= 0) { return day; } @@ -607,7 +687,7 @@ class SimpleMonthView extends View { @Override protected void getVisibleVirtualViews(IntArray virtualViewIds) { - for (int day = 1; day <= mNumCells; day++) { + for (int day = 1; day <= mDaysInMonth; day++) { virtualViewIds.add(day); } } @@ -619,11 +699,20 @@ class SimpleMonthView extends View { @Override protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfo node) { - getItemBounds(virtualViewId, mTempRect); + final boolean hasBounds = getBoundsForDay(virtualViewId, mTempRect); + + if (!hasBounds) { + // The day is invalid, kill the node. + mTempRect.setEmpty(); + node.setContentDescription(""); + node.setBoundsInParent(mTempRect); + node.setVisibleToUser(false); + return; + } node.setContentDescription(getItemDescription(virtualViewId)); node.setBoundsInParent(mTempRect); - node.addAction(AccessibilityNodeInfo.ACTION_CLICK); + node.addAction(AccessibilityAction.ACTION_CLICK); if (virtualViewId == mActivatedDay) { node.setSelected(true); @@ -636,7 +725,7 @@ class SimpleMonthView extends View { Bundle arguments) { switch (action) { case AccessibilityNodeInfo.ACTION_CLICK: - onDayClick(virtualViewId); + onDayClicked(virtualViewId); return true; } @@ -644,26 +733,6 @@ class SimpleMonthView extends View { } /** - * Calculates the bounding rectangle of a given time object. - * - * @param day The day to calculate bounds for - * @param rect The rectangle in which to store the bounds - */ - private void getItemBounds(int day, Rect rect) { - final int offsetX = mPadding; - final int offsetY = mMonthHeaderHeight; - final int cellHeight = mRowHeight; - final int cellWidth = ((mWidth - (2 * mPadding)) / mNumDays); - final int index = ((day - 1) + findDayOffset()); - final int row = (index / mNumDays); - final int column = (index % mNumDays); - final int x = (offsetX + (column * cellWidth)); - final int y = (offsetY + (row * cellHeight)); - - rect.set(x, y, (x + cellWidth), (y + cellHeight)); - } - - /** * Generates a description for a given time object. Since this * description will be spoken, the components are ordered by descending * specificity as DAY MONTH YEAR. diff --git a/core/java/android/widget/TextViewWithCircularIndicator.java b/core/java/android/widget/TextViewWithCircularIndicator.java deleted file mode 100644 index d3c786c..0000000 --- a/core/java/android/widget/TextViewWithCircularIndicator.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.widget; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Typeface; -import android.util.AttributeSet; - -import com.android.internal.R; - -class TextViewWithCircularIndicator extends TextView { - private final Paint mCirclePaint = new Paint(); - private final String mItemIsSelectedText; - - public TextViewWithCircularIndicator(Context context) { - this(context, null); - } - - public TextViewWithCircularIndicator(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public TextViewWithCircularIndicator(Context context, AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); - } - - public TextViewWithCircularIndicator(Context context, AttributeSet attrs, - int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - - final Resources res = context.getResources(); - mItemIsSelectedText = res.getString(R.string.item_is_selected); - - init(); - } - - private void init() { - mCirclePaint.setTypeface(Typeface.create(mCirclePaint.getTypeface(), Typeface.BOLD)); - mCirclePaint.setAntiAlias(true); - mCirclePaint.setTextAlign(Paint.Align.CENTER); - mCirclePaint.setStyle(Paint.Style.FILL); - } - - public void setCircleColor(int color) { - mCirclePaint.setColor(color); - invalidate(); - } - - @Override - public void onDraw(Canvas canvas) { - if (isActivated()) { - final int width = getWidth(); - final int height = getHeight(); - final int radius = Math.min(width, height) / 2; - canvas.drawCircle(width / 2, height / 2, radius, mCirclePaint); - } - - super.onDraw(canvas); - } - - @Override - public CharSequence getContentDescription() { - final CharSequence itemText = getText(); - if (isActivated()) { - return String.format(mItemIsSelectedText, itemText); - } else { - return itemText; - } - } -}
\ No newline at end of file diff --git a/core/java/android/widget/YearPickerView.java b/core/java/android/widget/YearPickerView.java index 6f0465f..7bd502e 100644 --- a/core/java/android/widget/YearPickerView.java +++ b/core/java/android/widget/YearPickerView.java @@ -17,10 +17,9 @@ package android.widget; import android.content.Context; -import android.content.res.ColorStateList; import android.content.res.Resources; import android.util.AttributeSet; -import android.util.StateSet; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; @@ -32,23 +31,14 @@ import com.android.internal.R; /** * Displays a selectable list of years. */ -class YearPickerView extends ListView implements AdapterView.OnItemClickListener, - OnDateChangedListener { - private final Calendar mMinDate = Calendar.getInstance(); - private final Calendar mMaxDate = Calendar.getInstance(); - +class YearPickerView extends ListView { private final YearAdapter mAdapter; private final int mViewSize; private final int mChildSize; - private DatePickerController mController; - - private int mSelectedPosition = -1; - private int mYearActivatedColor; + private OnYearSelectedListener mOnYearSelectedListener; - public YearPickerView(Context context) { - this(context, null); - } + private long mCurrentTimeMillis; public YearPickerView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.listViewStyle); @@ -69,104 +59,187 @@ class YearPickerView extends ListView implements AdapterView.OnItemClickListener mViewSize = res.getDimensionPixelOffset(R.dimen.datepicker_view_animator_height); mChildSize = res.getDimensionPixelOffset(R.dimen.datepicker_year_label_height); - setVerticalFadingEdgeEnabled(true); - setFadingEdgeLength(mChildSize / 3); - - final int paddingTop = res.getDimensionPixelSize( - R.dimen.datepicker_year_picker_padding_top); - setPadding(0, paddingTop, 0, 0); + setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + final int year = mAdapter.getYearForPosition(position); + mAdapter.setSelection(year); - setOnItemClickListener(this); - setDividerHeight(0); + if (mOnYearSelectedListener != null) { + mOnYearSelectedListener.onYearChanged(YearPickerView.this, year); + } + } + }); - mAdapter = new YearAdapter(getContext(), R.layout.year_label_text_view); + mAdapter = new YearAdapter(getContext()); setAdapter(mAdapter); } - public void setRange(Calendar min, Calendar max) { - mMinDate.setTimeInMillis(min.getTimeInMillis()); - mMaxDate.setTimeInMillis(max.getTimeInMillis()); + public void setOnYearSelectedListener(OnYearSelectedListener listener) { + mOnYearSelectedListener = listener; + } - updateAdapterData(); + public void setDate(long currentTimeMillis) { + mCurrentTimeMillis = currentTimeMillis; } - public void init(DatePickerController controller) { - mController = controller; - mController.registerOnDateChangedListener(this); + /** + * Sets the currently selected year. Jumps immediately to the new year. + * + * @param year the target year + */ + public void setYear(final int year) { + mAdapter.setSelection(year); - updateAdapterData(); + post(new Runnable() { + @Override + public void run() { + final int position = mAdapter.getPositionForYear(year); + if (position >= 0 && position < getCount()) { + setSelectionCentered(position); + } + } + }); + } - onDateChanged(); + public void setSelectionCentered(int position) { + final int offset = mViewSize / 2 - mChildSize / 2; + setSelectionFromTop(position, offset); } - public void setYearBackgroundColor(ColorStateList yearBackgroundColor) { - mYearActivatedColor = yearBackgroundColor.getColorForState( - StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0); - invalidate(); + public void setRange(Calendar min, Calendar max) { + mAdapter.setRange(min, max); } public void setYearTextAppearance(int resId) { mAdapter.setItemTextAppearance(resId); } - private void updateAdapterData() { - mAdapter.clear(); + public void setYearActivatedTextAppearance(int resId) { + mAdapter.setItemActivatedTextAppearance(resId); + } + + private static class YearAdapter extends BaseAdapter { + private static final int ITEM_LAYOUT = R.layout.year_label_text_view; + + private final LayoutInflater mInflater; + + private int mActivatedYear; + private int mMinYear; + private int mCount; - final int maxYear = mMaxDate.get(Calendar.YEAR); - for (int year = mMinDate.get(Calendar.YEAR); year <= maxYear; year++) { - mAdapter.add(year); + private int mItemTextAppearanceResId; + private int mItemActivatedTextAppearanceResId; + + public YearAdapter(Context context) { + mInflater = LayoutInflater.from(context); } - } - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - mController.tryVibrate(); - if (position != mSelectedPosition) { - mSelectedPosition = position; - mAdapter.notifyDataSetChanged(); + public void setRange(Calendar minDate, Calendar maxDate) { + final int minYear = minDate.get(Calendar.YEAR); + final int count = maxDate.get(Calendar.YEAR) - minYear + 1; + + if (mMinYear != minYear || mCount != count) { + mMinYear = minYear; + mCount = count; + notifyDataSetInvalidated(); + } } - mController.onYearSelected(mAdapter.getItem(position)); - } - private class YearAdapter extends ArrayAdapter<Integer> { - private int mItemTextAppearanceResId; + public boolean setSelection(int year) { + if (mActivatedYear != year) { + mActivatedYear = year; + notifyDataSetChanged(); + return true; + } + return false; + } + + public void setItemTextAppearance(int resId) { + mItemTextAppearanceResId = resId; + notifyDataSetChanged(); + } + + public void setItemActivatedTextAppearance(int resId) { + mItemActivatedTextAppearanceResId = resId; + notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mCount; + } - public YearAdapter(Context context, int resource) { - super(context, resource); + @Override + public Integer getItem(int position) { + return getYearForPosition(position); + } + + @Override + public long getItemId(int position) { + return getYearForPosition(position); + } + + public int getPositionForYear(int year) { + return year - mMinYear; + } + + public int getYearForPosition(int position) { + return mMinYear + position; + } + + @Override + public boolean hasStableIds() { + return true; } @Override public View getView(int position, View convertView, ViewGroup parent) { - final TextViewWithCircularIndicator v = (TextViewWithCircularIndicator) - super.getView(position, convertView, parent); - v.setTextAppearance(v.getContext(), mItemTextAppearanceResId); - v.setCircleColor(mYearActivatedColor); + if (convertView == null) { + convertView = mInflater.inflate(ITEM_LAYOUT, parent, false); + } - final int year = getItem(position); - final boolean selected = mController.getSelectedDay().get(Calendar.YEAR) == year; - v.setActivated(selected); + final int year = getYearForPosition(position); + final boolean activated = mActivatedYear == year; + final int textAppearanceResId; + if (activated && mItemActivatedTextAppearanceResId != 0) { + textAppearanceResId = mItemActivatedTextAppearanceResId; + } else { + textAppearanceResId = mItemTextAppearanceResId; + } + + final TextView v = (TextView) convertView; + v.setText("" + year); + v.setTextAppearance(v.getContext(), textAppearanceResId); + v.setActivated(activated); return v; } - public void setItemTextAppearance(int resId) { - mItemTextAppearanceResId = resId; + @Override + public int getItemViewType(int position) { + return 0; } - } - public void postSetSelectionCentered(final int position) { - postSetSelectionFromTop(position, mViewSize / 2 - mChildSize / 2); - } + @Override + public int getViewTypeCount() { + return 1; + } - public void postSetSelectionFromTop(final int position, final int offset) { - post(new Runnable() { + @Override + public boolean isEmpty() { + return false; + } - @Override - public void run() { - setSelectionFromTop(position, offset); - requestLayout(); - } - }); + @Override + public boolean areAllItemsEnabled() { + return true; + } + + @Override + public boolean isEnabled(int position) { + return true; + } } public int getFirstPositionOffset() { @@ -177,22 +250,28 @@ class YearPickerView extends ListView implements AdapterView.OnItemClickListener return firstChild.getTop(); } - @Override - public void onDateChanged() { - updateAdapterData(); - mAdapter.notifyDataSetChanged(); - postSetSelectionCentered( - mController.getSelectedDay().get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR)); - } - /** @hide */ @Override public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { super.onInitializeAccessibilityEventInternal(event); + // There are a bunch of years, so don't bother. if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { event.setFromIndex(0); event.setToIndex(0); } } + + /** + * The callback used to indicate the user changed the year. + */ + public interface OnYearSelectedListener { + /** + * Called upon a year change. + * + * @param view The view associated with this listener. + * @param year The year that was set. + */ + void onYearChanged(YearPickerView view, int year); + } }
\ No newline at end of file diff --git a/core/java/com/android/internal/widget/AccessibleDateAnimator.java b/core/java/com/android/internal/widget/AccessibleDateAnimator.java deleted file mode 100644 index f97a5d1..0000000 --- a/core/java/com/android/internal/widget/AccessibleDateAnimator.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.widget; - -import android.content.Context; -import android.text.format.DateUtils; -import android.util.AttributeSet; -import android.view.accessibility.AccessibilityEvent; -import android.widget.ViewAnimator; - -/** - * @hide - */ -public class AccessibleDateAnimator extends ViewAnimator { - private long mDateMillis; - - public AccessibleDateAnimator(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public void setDateMillis(long dateMillis) { - mDateMillis = dateMillis; - } - - /** - * Announce the currently-selected date when launched. - */ - @Override - public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { - if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { - // Clear the event's current text so that only the current date will be spoken. - event.getText().clear(); - int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR | - DateUtils.FORMAT_SHOW_WEEKDAY; - - String dateString = DateUtils.formatDateTime(getContext(), mDateMillis, flags); - event.getText().add(dateString); - return true; - } - return super.dispatchPopulateAccessibilityEventInternal(event); - } -} diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java index f916e6f..8018942 100644 --- a/core/java/com/android/internal/widget/ViewPager.java +++ b/core/java/com/android/internal/widget/ViewPager.java @@ -137,7 +137,7 @@ public class ViewPager extends ViewGroup { private int mRestoredCurItem = -1; private Parcelable mRestoredAdapterState = null; private ClassLoader mRestoredClassLoader = null; - private Scroller mScroller; + private final Scroller mScroller; private PagerObserver mObserver; private int mPageMargin; @@ -162,9 +162,9 @@ public class ViewPager extends ViewGroup { private boolean mIsBeingDragged; private boolean mIsUnableToDrag; - private int mDefaultGutterSize; + private final int mDefaultGutterSize; private int mGutterSize; - private int mTouchSlop; + private final int mTouchSlop; /** * Position of the last motion event. */ @@ -187,10 +187,10 @@ public class ViewPager extends ViewGroup { * Determines speed during touch scrolling */ private VelocityTracker mVelocityTracker; - private int mMinimumVelocity; - private int mMaximumVelocity; - private int mFlingDistance; - private int mCloseEnough; + private final int mMinimumVelocity; + private final int mMaximumVelocity; + private final int mFlingDistance; + private final int mCloseEnough; // If the pager is at least this close to its final position, complete the scroll // on touch down and let the user interact with the content inside instead of @@ -200,8 +200,8 @@ public class ViewPager extends ViewGroup { private boolean mFakeDragging; private long mFakeDragBeginTime; - private EdgeEffect mLeftEdge; - private EdgeEffect mRightEdge; + private final EdgeEffect mLeftEdge; + private final EdgeEffect mRightEdge; private boolean mFirstLayout = true; private boolean mNeedCalculatePageOffsets = false; @@ -339,20 +339,24 @@ public class ViewPager extends ViewGroup { interface Decor {} public ViewPager(Context context) { - super(context); - initViewPager(); + this(context, null); } public ViewPager(Context context, AttributeSet attrs) { - super(context, attrs); - initViewPager(); + this(context, attrs, 0); } - void initViewPager() { + public ViewPager(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public ViewPager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + setWillNotDraw(false); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); setFocusable(true); - final Context context = getContext(); + mScroller = new Scroller(context, sInterpolator); final ViewConfiguration configuration = ViewConfiguration.get(context); final float density = context.getResources().getDisplayMetrics().density; diff --git a/core/res/res/color/date_picker_header_text_material.xml b/core/res/res/color/date_picker_header_text_material.xml index cda894b..baa8958 100644 --- a/core/res/res/color/date_picker_header_text_material.xml +++ b/core/res/res/color/date_picker_header_text_material.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item - android:state_selected="true" + android:state_activated="true" android:color="?attr/textColorPrimaryInverse" /> <item android:color="?attr/textColorSecondaryInverse" /> diff --git a/core/res/res/layout-land/date_picker_holo.xml b/core/res/res/layout-land/date_picker_holo.xml deleted file mode 100644 index 991888c..0000000 --- a/core/res/res/layout-land/date_picker_holo.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2011 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="@dimen/datepicker_view_animator_height" - android:gravity="center" - android:orientation="horizontal" - android:minWidth="@dimen/datepicker_dialog_width" > - - <include - layout="@layout/date_picker_selected_date" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_weight="1" /> - - <include layout="@layout/date_picker_view_animator" /> - -</LinearLayout> diff --git a/core/res/res/layout-land/date_picker_material.xml b/core/res/res/layout-land/date_picker_material.xml new file mode 100644 index 0000000..1e711c5 --- /dev/null +++ b/core/res/res/layout-land/date_picker_material.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal"> + + <include + layout="@layout/date_picker_header_material" + android:layout_width="168dp" + android:layout_height="match_parent" /> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="vertical"> + + <include + layout="@layout/date_picker_view_animator_material" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" /> + + <ViewStub + android:id="@id/buttonPanel" + android:layout="@layout/alert_dialog_button_bar_material" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/day_picker_button_margin_top" /> + + </LinearLayout> + +</LinearLayout> diff --git a/core/res/res/layout/alert_dialog_button_bar_material.xml b/core/res/res/layout/alert_dialog_button_bar_material.xml index 891bcd5..1eea4e1 100644 --- a/core/res/res/layout/alert_dialog_button_bar_material.xml +++ b/core/res/res/layout/alert_dialog_button_bar_material.xml @@ -18,16 +18,16 @@ <com.android.internal.widget.ButtonBarLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/buttonPanel" - style="?attr/buttonBarStyle" android:layout_width="match_parent" android:layout_height="wrap_content" android:layoutDirection="locale" android:orientation="horizontal" android:paddingStart="12dp" android:paddingEnd="12dp" - android:paddingTop="8dp" - android:paddingBottom="8dp" - android:gravity="bottom"> + android:paddingTop="4dp" + android:paddingBottom="4dp" + android:gravity="bottom" + style="?attr/buttonBarStyle"> <Button android:id="@+id/button3" diff --git a/core/res/res/layout/date_picker_header_material.xml b/core/res/res/layout/date_picker_header_material.xml new file mode 100644 index 0000000..bda7de9 --- /dev/null +++ b/core/res/res/layout/date_picker_header_material.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/date_picker_header" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="18dp" + android:paddingStart="?attr/dialogPreferredPadding" + android:paddingEnd="?attr/dialogPreferredPadding" + android:orientation="vertical" + tools:background="@color/accent_material_light" + tools:paddingStart="24dp" + tools:paddingEnd="24dp"> + + <!-- Top padding should stay on this view so that + the touch target is a bit larger. --> + <TextView + android:id="@+id/date_picker_header_year" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="16dp" + android:textAppearance="@style/TextAppearance.Material.DatePicker.YearLabel" + tools:text="2015" + tools:textSize="@dimen/date_picker_year_label_size" + tools:textColor="@color/white" /> + + <TextView + android:id="@+id/date_picker_header_date" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.Material.DatePicker.DateLabel" + android:maxLines="2" + android:ellipsize="none" + tools:text="Thu, Sep 30" + tools:textSize="@dimen/date_picker_date_label_size" + tools:textColor="@color/white" /> + +</LinearLayout> diff --git a/core/res/res/layout/date_picker_holo.xml b/core/res/res/layout/date_picker_material.xml index 72030ea..a1c97ff 100644 --- a/core/res/res/layout/date_picker_holo.xml +++ b/core/res/res/layout/date_picker_material.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - Copyright (C) 2011 The Android Open Source Project + Copyright (C) 2014 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,17 +14,21 @@ See the License for the specific language governing permissions and limitations under the License. --> + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="@dimen/datepicker_component_width" + android:layout_width="match_parent" android:layout_height="match_parent" - android:gravity="center" android:orientation="vertical"> <include - layout="@layout/date_picker_selected_date" + layout="@layout/date_picker_header_material" android:layout_width="match_parent" android:layout_height="wrap_content" /> - <include layout="@layout/date_picker_view_animator" /> + <include + layout="@layout/date_picker_view_animator_material" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" /> </LinearLayout> diff --git a/core/res/res/layout/date_picker_selected_date.xml b/core/res/res/layout/date_picker_selected_date.xml deleted file mode 100644 index 9becb81..0000000 --- a/core/res/res/layout/date_picker_selected_date.xml +++ /dev/null @@ -1,73 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2014 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/day_picker_selector_layout" - android:layout_width="@dimen/datepicker_component_width" - android:layout_height="wrap_content" - android:gravity="center" - android:orientation="vertical"> - - <TextView - android:id="@+id/date_picker_header" - android:layout_width="match_parent" - android:layout_height="@dimen/datepicker_header_height" - android:gravity="center" - android:importantForAccessibility="no" /> - - <LinearLayout - android:id="@+id/date_picker_month_day_year_layout" - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="1" - android:paddingTop="4dp" - android:paddingBottom="4dp" - android:orientation="vertical" - android:gravity="center"> - - <LinearLayout - android:id="@+id/date_picker_month_and_day_layout" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:clickable="true" - android:orientation="vertical"> - - <TextView - android:id="@+id/date_picker_month" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:duplicateParentState="true" - android:gravity="center" /> - - <TextView - android:id="@+id/date_picker_day" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="-23dp" - android:layout_marginBottom="-20dp" - android:duplicateParentState="true" - android:gravity="center" /> - </LinearLayout> - - <TextView - android:id="@+id/date_picker_year" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" /> - </LinearLayout> - -</LinearLayout> diff --git a/core/res/res/layout/date_picker_view_animator.xml b/core/res/res/layout/date_picker_view_animator.xml deleted file mode 100644 index 9085ed5..0000000 --- a/core/res/res/layout/date_picker_view_animator.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2014 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<com.android.internal.widget.AccessibleDateAnimator - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/animator" - android:layout_width="@dimen/datepicker_component_width" - android:layout_height="@dimen/datepicker_view_animator_height" - android:gravity="center" />
\ No newline at end of file diff --git a/core/res/res/layout/date_picker_view_animator_material.xml b/core/res/res/layout/date_picker_view_animator_material.xml new file mode 100644 index 0000000..98ef1dd --- /dev/null +++ b/core/res/res/layout/date_picker_view_animator_material.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<ViewAnimator xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/animator" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:gravity="center"> + + <android.widget.DayPickerView + android:id="@+id/date_picker_day_picker" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingStart="@dimen/day_picker_padding_horizontal" + android:paddingEnd="@dimen/day_picker_padding_horizontal" + android:paddingTop="@dimen/day_picker_padding_top" /> + + <android.widget.YearPickerView + android:id="@+id/date_picker_year_picker" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + +</ViewAnimator> diff --git a/core/res/res/layout/year_label_text_view.xml b/core/res/res/layout/year_label_text_view.xml index e5bd068..6240c4b 100644 --- a/core/res/res/layout/year_label_text_view.xml +++ b/core/res/res/layout/year_label_text_view.xml @@ -13,10 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> -<android.widget.TextViewWithCircularIndicator - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/month_text_view" - android:layout_width="match_parent" - android:layout_height="@dimen/datepicker_year_label_height" - android:layout_gravity="center" - android:gravity="center" /> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/month_text_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?attr/listPreferredItemHeightSmall" + android:paddingTop="12dp" + android:paddingBottom="12dp" + android:gravity="center" /> diff --git a/core/res/res/values-land/dimens_material.xml b/core/res/res/values-land/dimens_material.xml index 379ccf6..202f4a4 100644 --- a/core/res/res/values-land/dimens_material.xml +++ b/core/res/res/values-land/dimens_material.xml @@ -48,4 +48,14 @@ <dimen name="timepicker_text_inset_inner">46dp</dimen> <dimen name="timepicker_text_size_normal">14sp</dimen> <dimen name="timepicker_text_size_inner">12sp</dimen> + + <!-- Used by Material-style SimpleMonthView --> + <dimen name="date_picker_month_height">40dp</dimen> + <dimen name="date_picker_day_of_week_height">14dp</dimen> + <dimen name="date_picker_day_height">32dp</dimen> + <dimen name="date_picker_day_width">46dp</dimen> + <dimen name="date_picker_day_selector_radius">16dp</dimen> + <dimen name="day_picker_padding_horizontal">18dp</dimen> + <dimen name="day_picker_padding_top">0dp</dimen> + <dimen name="day_picker_button_margin_top">-8dp</dimen> </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 15797dd..b5576c5 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1036,7 +1036,7 @@ <attr name="colorSwitchThumbNormal" format="color" /> <!-- @hide The background used by framework controls. --> - <attr name="controlBackground" format="color" /> + <attr name="controlBackground" format="reference" /> <!-- The color applied to the edge effect on scrolling containers. --> <attr name="colorEdgeEffect" format="color" /> @@ -4443,46 +4443,42 @@ </declare-styleable> <declare-styleable name="DatePicker"> - <!-- The first year (inclusive), for example "1940". - {@deprecated Use minDate instead.} --> + <!-- The first year (inclusive), for example "1940". {@deprecated Use minDate instead.} --> <attr name="startYear" format="integer" /> - <!-- The last year (inclusive), for example "2010". - {@deprecated Use maxDate instead.} --> + <!-- The last year (inclusive), for example "2010". {@deprecated Use maxDate instead.} --> <attr name="endYear" format="integer" /> - <!-- Whether the spinners are shown. --> - <attr name="spinnersShown" format="boolean" /> - <!-- Whether the calendar view is shown. --> - <attr name="calendarViewShown" format="boolean" /> + + <!-- The first day of week according to {@link java.util.Calendar}. --> + <attr name="firstDayOfWeek" /> <!-- The minimal date shown by this calendar view in mm/dd/yyyy format. --> <attr name="minDate" format="string" /> <!-- The maximal date shown by this calendar view in mm/dd/yyyy format. --> <attr name="maxDate" format="string" /> - <!-- The first day of week according to {@link java.util.Calendar}. --> - <attr name="firstDayOfWeek" /> + + <!-- Whether the spinners are shown. Only valid for "spinner" mode. --> + <attr name="spinnersShown" format="boolean" /> + <!-- Whether the calendar view is shown. Only valid for "spinner" mode. --> + <attr name="calendarViewShown" format="boolean" /> + <!-- @hide The layout of the date picker. --> <attr name="internalLayout" format="reference" /> <!-- @hide The layout of the legacy DatePicker. --> <attr name="legacyLayout" /> - <!-- The background color for the date selector 's day of week. --> - <attr name="dayOfWeekBackground" format="color|reference" /> - <!-- The text color for the date selector's day of week. --> - <attr name="dayOfWeekTextAppearance" format="reference" /> - <!-- The month's text appearance in the date selector. --> - <attr name="headerMonthTextAppearance" format="reference" /> - <!-- The day of month's text appearance in the date selector. --> - <attr name="headerDayOfMonthTextAppearance" format="reference" /> - <!-- The year's text appearance in the date selector. --> - <attr name="headerYearTextAppearance" format="reference" /> - <!-- The background for the date selector. --> + + <!-- The text color for the selected date header text, ex. "2014" or + "Tue, Mar 18". This should be a color state list where the + activated state will be used when the year picker or day picker is + active.--> + <attr name="headerTextColor" format="color" /> + <!-- The background for the selected date header. --> <attr name="headerBackground" /> + <!-- The list year's text appearance in the list. --> <attr name="yearListItemTextAppearance" format="reference" /> - <!-- The list year's selected circle color in the list. --> - <attr name="yearListSelectorColor" format="color" /> + <!-- @hide The list year's text appearance in the list when activated. --> + <attr name="yearListItemActivatedTextAppearance" format="reference" /> <!-- The text color list of the calendar. --> <attr name="calendarTextColor" format="color" /> - <!-- @hide The activated background color for the calendar. --> - <attr name="calendarDayBackgroundColor" format="color" /> <!-- Defines the look of the widget. Prior to the L release, the only choice was spinner. As of L, with the Material theme selected, the default layout is calendar, but this attribute can be used to force spinner to be used instead. --> @@ -4492,6 +4488,19 @@ <!-- Date picker with calendar to select the date. --> <enum name="calendar" value="2" /> </attr> + + <!-- @deprecated The text appearance for the month (ex. May) in the selected date header. --> + <attr name="headerMonthTextAppearance" format="reference" /> + <!-- @deprecated The text appearance for the day of month (ex. 28) in the selected date header. --> + <attr name="headerDayOfMonthTextAppearance" format="reference" /> + <!-- The text appearance for the year (ex. 2014) in the selected date header. --> + <attr name="headerYearTextAppearance" format="reference" /> + <!-- @deprecated The background color for the header's day of week. --> + <attr name="dayOfWeekBackground" format="color" /> + <!-- @deprecated The text color for the header's day of week. --> + <attr name="dayOfWeekTextAppearance" format="reference" /> + <!-- @deprecated The list year's selected circle color in the list. --> + <attr name="yearListSelectorColor" format="color" /> </declare-styleable> <declare-styleable name="TwoLineListItem"> @@ -4709,35 +4718,42 @@ <declare-styleable name="CalendarView"> <!-- The first day of week according to {@link java.util.Calendar}. --> <attr name="firstDayOfWeek" format="integer" /> - <!-- Whether do show week numbers. --> - <attr name="showWeekNumber" format="boolean" /> <!-- The minimal date shown by this calendar view in mm/dd/yyyy format. --> <attr name="minDate" /> <!-- The minimal date shown by this calendar view in mm/dd/yyyy format. --> <attr name="maxDate" /> - <!-- The number of weeks to be shown. --> + <!-- The text appearance for the month and year in the calendar header. --> + <attr name="monthTextAppearance" format="reference" /> + <!-- The text appearance for the week day abbreviation in the calendar header. --> + <attr name="weekDayTextAppearance" format="reference" /> + <!-- The text appearance for the day numbers in the calendar grid. --> + <attr name="dateTextAppearance" format="reference" /> + <!-- @hide The background color used for the day selection indicator. --> + <attr name="daySelectorColor" format="color" /> + <!-- @hide The background color used for the day highlight indicator. --> + <attr name="dayHighlightColor" format="color" /> + <!-- @hide Which style of calendar delegate to use. --> + <attr name="calendarViewMode"> + <enum name="holo" value="0" /> + <enum name="material" value="1" /> + </attr> + + <!-- @deprecated Whether do show week numbers. --> + <attr name="showWeekNumber" format="boolean" /> + <!-- @deprecated The number of weeks to be shown. --> <attr name="shownWeekCount" format="integer"/> - <!-- The background color for the selected week. --> + <!-- @deprecated The background color for the selected week. --> <attr name="selectedWeekBackgroundColor" format="color|reference" /> - <!-- The color for the dates of the focused month. --> + <!-- @deprecated The color for the dates of the focused month. --> <attr name="focusedMonthDateColor" format="color|reference" /> - <!-- The color for the dates of an unfocused month. --> + <!-- @deprecated The color for the dates of an unfocused month. --> <attr name="unfocusedMonthDateColor" format="color|reference" /> - <!-- The color for the week numbers. --> + <!-- @deprecated The color for the week numbers. --> <attr name="weekNumberColor" format="color|reference" /> - <!-- The color for the separator line between weeks. --> + <!-- @deprecated The color for the separator line between weeks. --> <attr name="weekSeparatorLineColor" format="color|reference" /> - <!-- Drawable for the vertical bar shown at the beginning and at the end of the selected date. --> + <!-- @deprecated Drawable for the vertical bar shown at the beginning and at the end of the selected date. --> <attr name="selectedDateVerticalBar" format="reference" /> - <!-- The text appearance for the week day abbreviation of the calendar header. --> - <attr name="weekDayTextAppearance" format="reference" /> - <!-- The text appearance for the calendar dates. --> - <attr name="dateTextAppearance" format="reference" /> - <!-- The number of weeks to be shown. --> - <attr name="calendarViewMode"> - <enum name="holo" value="0" /> - <enum name="material" value="1" /> - </attr> </declare-styleable> <declare-styleable name="NumberPicker"> diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml index 8d2afde..6fd39f6 100644 --- a/core/res/res/values/dimens_material.xml +++ b/core/res/res/values/dimens_material.xml @@ -143,9 +143,7 @@ <dimen name="timepicker_text_size_inner">12sp</dimen> <!-- Material date picker dimensions. --> - <dimen name="datepicker_year_picker_padding_top">8dp</dimen> <dimen name="datepicker_year_label_height">64dp</dimen> - <dimen name="datepicker_year_label_text_size">22dp</dimen> <dimen name="datepicker_component_width">260dp</dimen> <dimen name="datepicker_dialog_width">520dp</dimen> <dimen name="datepicker_selected_date_day_size">88dp</dimen> @@ -154,10 +152,24 @@ <dimen name="datepicker_header_height">30dp</dimen> <dimen name="datepicker_header_text_size">14dp</dimen> + <dimen name="datepicker_list_year_label_size">16sp</dimen> + <dimen name="datepicker_list_year_activated_label_size">26sp</dimen> + + <dimen name="date_picker_year_label_size">16sp</dimen> + <dimen name="date_picker_date_label_size">34dp</dimen> + <!-- Used by Material-style SimpleMonthView --> - <dimen name="datepicker_day_number_size">12sp</dimen> - <dimen name="datepicker_month_label_size">14sp</dimen> - <dimen name="datepicker_month_day_label_text_size">12sp</dimen> - <dimen name="datepicker_month_list_item_header_height">48dp</dimen> + <dimen name="date_picker_month_text_size">14sp</dimen> + <dimen name="date_picker_day_of_week_text_size">12sp</dimen> + <dimen name="date_picker_day_text_size">12sp</dimen> + <dimen name="date_picker_month_height">56dp</dimen> + <dimen name="date_picker_day_of_week_height">36dp</dimen> + <dimen name="date_picker_day_height">40dp</dimen> + <dimen name="date_picker_day_width">44dp</dimen> + <dimen name="date_picker_day_selector_radius">20dp</dimen> + <dimen name="day_picker_padding_horizontal">20dp</dimen> + <dimen name="day_picker_padding_top">6dp</dimen> + <dimen name="day_picker_button_margin_top">0dp</dimen> + <dimen name="datepicker_view_animator_height">226dp</dimen> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 19cae03..7672e93 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -5042,18 +5042,6 @@ <!-- Accessibility announcement for minute circular picker [CHAR LIMIT=NONE] --> <string name="select_minutes">Select minutes</string> - <!-- - Content description for the month and day selector in the date picker, which displays - a selectable grid of days laid out by month. - [CHAR LIMIT=50] - --> - <string name="day_picker_description">Month grid of days</string> - <!-- - Content description for the year selector in the date picker, which displays - a scrolling, vertical list of years. - [CHAR LIMIT=50] - --> - <string name="year_picker_description">Year list</string> <!-- Accessibility announcement for the day picker [CHAR LIMIT=NONE] --> <string name="select_day">Select month and day</string> <!-- Accessibility announcement for the year picker [CHAR LIMIT=NONE] --> @@ -5079,7 +5067,11 @@ <string name="sans_serif">sans-serif</string> <!-- DO NOT TRANSLATE --> - <string name="day_of_week_label_typeface">sans-serif</string> + <string name="date_picker_month_typeface">sans-serif-medium</string> + <!-- DO NOT TRANSLATE --> + <string name="date_picker_day_of_week_typeface">sans-serif-medium</string> + <!-- DO NOT TRANSLATE --> + <string name="date_picker_day_typeface">sans-serif-medium</string> <!-- Notify use that they are in Lock-to-app --> <string name="lock_to_app_toast">To unpin this screen, touch and hold Back and Overview at the same time.</string> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index a8ab18d..9c2f1eb 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -372,11 +372,13 @@ please see styles_device_defaults.xml. <style name="TextAppearance.Material.WindowTitle" parent="TextAppearance.Material.Title" /> <style name="TextAppearance.Material.DialogWindowTitle" parent="TextAppearance.Material.Title" /> - <style name="TextAppearance.Material.CalendarViewWeekDayView" parent="TextAppearance.Material.Small"> - <item name="textStyle">bold</item> - <item name="textColor">#505050</item> + <style name="TextAppearance.Material.Widget.Calendar.Day" parent="TextAppearance.Material.Caption"> + <item name="textColor">?attr/textColorPrimaryActivated</item> </style> + <style name="TextAppearance.Material.Widget.Calendar.DayOfWeek" parent="TextAppearance.Material.Caption" /> + <style name="TextAppearance.Material.Widget.Calendar.Month" parent="TextAppearance.Material.Body2" /> + <style name="TextAppearance.Material.TimePicker.TimeLabel" parent="TextAppearance.Material"> <item name="textSize">@dimen/timepicker_time_label_size</item> <item name="textColor">@color/time_picker_header_text_material</item> @@ -406,14 +408,27 @@ please see styles_device_defaults.xml. </style> <style name="TextAppearance.Material.DatePicker.YearLabel" parent="TextAppearance.Material"> - <item name="includeFontPadding">false</item> <item name="textColor">@color/date_picker_header_text_material</item> - <item name="textSize">@dimen/datepicker_selected_date_year_size</item> + <item name="textSize">@dimen/date_picker_year_label_size</item> + <item name="fontFamily">sans-serif-medium</item> + </style> + + <style name="TextAppearance.Material.DatePicker.DateLabel" parent="TextAppearance.Material"> + <item name="textColor">@color/date_picker_header_text_material</item> + <item name="textSize">@dimen/date_picker_date_label_size</item> + <item name="fontFamily">sans-serif-medium</item> </style> <style name="TextAppearance.Material.DatePicker.List.YearLabel" parent="TextAppearance.Material"> - <item name="textColor">?attr/textColorSecondaryActivated</item> - <item name="textSize">@dimen/datepicker_year_label_text_size</item> + <item name="textColor">?attr/textColorPrimary</item> + <item name="textSize">@dimen/datepicker_list_year_label_size</item> + <item name="fontFamily">sans-serif</item> + </style> + + <style name="TextAppearance.Material.DatePicker.List.YearLabel.Activated"> + <item name="textColor">?attr/colorControlActivated</item> + <item name="textSize">@dimen/datepicker_list_year_activated_label_size</item> + <item name="fontFamily">sans-serif-medium</item> </style> <style name="TextAppearance.Material.Notification"> @@ -487,7 +502,8 @@ please see styles_device_defaults.xml. <!-- Alert dialog button bar button --> <style name="Widget.Material.Button.ButtonBar.AlertDialog" parent="Widget.Material.Button.Borderless.Colored"> <item name="minWidth">64dp</item> - <item name="maxLines">2</item> + <item name="singleLine">true</item> + <item name="ellipsize">none</item> <item name="minHeight">@dimen/alert_dialog_button_bar_height</item> </style> @@ -615,14 +631,13 @@ please see styles_device_defaults.xml. </style> <style name="Widget.Material.CalendarView" parent="Widget.CalendarView"> - <item name="selectedWeekBackgroundColor">#330099FF</item> - <item name="focusedMonthDateColor">#FFFFFFFF</item> - <item name="unfocusedMonthDateColor">#66FFFFFF</item> - <item name="weekNumberColor">#33FFFFFF</item> - <item name="weekSeparatorLineColor">#19FFFFFF</item> - <item name="selectedDateVerticalBar">@drawable/day_picker_week_view_dayline_holo</item> - <item name="weekDayTextAppearance">@style/TextAppearance.Material.CalendarViewWeekDayView</item> <item name="calendarViewMode">material</item> + + <item name="monthTextAppearance">@style/TextAppearance.Material.Widget.Calendar.Month</item> + <item name="weekDayTextAppearance">@style/TextAppearance.Material.Widget.Calendar.DayOfWeek</item> + <item name="dateTextAppearance">@style/TextAppearance.Material.Widget.Calendar.Day</item> + <item name="daySelectorColor">?attr/colorControlActivated</item> + <item name="dayHighlightColor">?attr/colorControlHighlight</item> </style> <style name="Widget.Material.ImageButton" parent="Widget.ImageButton"> @@ -650,7 +665,7 @@ please see styles_device_defaults.xml. <item name="headerBackground">@drawable/time_picker_header_material</item> <item name="numbersTextColor">?attr/textColorPrimaryActivated</item> <item name="numbersInnerTextColor">?attr/textColorSecondaryActivated</item> - <item name="numbersBackgroundColor">#10ffffff</item> + <item name="numbersBackgroundColor">#08ffffff</item> <item name="numbersSelectorColor">?attr/colorControlActivated</item> <item name="amPmTextColor">?attr/textColorSecondary</item> </style> @@ -660,17 +675,10 @@ please see styles_device_defaults.xml. <item name="legacyLayout">@layout/date_picker_legacy_holo</item> <item name="calendarViewShown">true</item> <!-- Attributes for new-style DatePicker. --> - <item name="internalLayout">@layout/date_picker_holo</item> - <item name="dayOfWeekBackground">#10000000</item> - <item name="dayOfWeekTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfWeekLabel</item> - <item name="headerMonthTextAppearance">@style/TextAppearance.Material.DatePicker.MonthLabel</item> - <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfMonthLabel</item> - <item name="headerYearTextAppearance">@style/TextAppearance.Material.DatePicker.YearLabel</item> + <item name="internalLayout">@layout/date_picker_material</item> <item name="headerBackground">?attr/colorAccent</item> <item name="yearListItemTextAppearance">@style/TextAppearance.Material.DatePicker.List.YearLabel</item> - <item name="yearListSelectorColor">?attr/colorControlActivated</item> - <item name="calendarTextColor">?attr/textColorSecondaryActivated</item> - <item name="calendarDayBackgroundColor">?attr/colorControlActivated</item> + <item name="yearListItemActivatedTextAppearance">@style/TextAppearance.Material.DatePicker.List.YearLabel.Activated</item> </style> <style name="Widget.Material.ActivityChooserView" parent="Widget.ActivityChooserView"> @@ -1021,17 +1029,7 @@ please see styles_device_defaults.xml. <style name="Widget.Material.Light.GestureOverlayView" parent="Widget.Material.GestureOverlayView"/> <style name="Widget.Material.Light.GridView" parent="Widget.Material.GridView"/> <style name="Widget.Material.Light.ImageButton" parent="Widget.Material.ImageButton"/> - - <style name="Widget.Material.Light.CalendarView" parent="Widget.CalendarView"> - <item name="selectedWeekBackgroundColor">#330066ff</item> - <item name="focusedMonthDateColor">#FF000000</item> - <item name="unfocusedMonthDateColor">#7F08002B</item> - <item name="weekNumberColor">#7F080021</item> - <item name="weekSeparatorLineColor">#7F08002A</item> - <item name="weekDayTextAppearance">@style/TextAppearance.Material.CalendarViewWeekDayView</item> - <item name="calendarViewMode">material</item> - </style> - + <style name="Widget.Material.Light.CalendarView" parent="Widget.Material.CalendarView" /> <style name="Widget.Material.Light.NumberPicker" parent="Widget.Material.NumberPicker"/> <style name="Widget.Material.Light.TimePicker" parent="Widget.Material.TimePicker"> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 203b017..c4e9e8e 100755 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1988,7 +1988,7 @@ <java-symbol type="layout" name="time_picker_material" /> <java-symbol type="layout" name="time_picker_header_material" /> <java-symbol type="layout" name="year_label_text_view" /> - <java-symbol type="layout" name="date_picker_holo" /> + <java-symbol type="layout" name="date_picker_material" /> <java-symbol type="id" name="time_header" /> <java-symbol type="id" name="hours" /> @@ -1999,11 +1999,8 @@ <java-symbol type="id" name="radial_picker" /> <java-symbol type="id" name="separator" /> <java-symbol type="id" name="date_picker_header" /> - <java-symbol type="id" name="date_picker_month_and_day_layout" /> - <java-symbol type="id" name="day_picker_selector_layout" /> - <java-symbol type="id" name="date_picker_month" /> - <java-symbol type="id" name="date_picker_day" /> - <java-symbol type="id" name="date_picker_year" /> + <java-symbol type="id" name="date_picker_header_year" /> + <java-symbol type="id" name="date_picker_header_date" /> <java-symbol type="id" name="animator" /> <java-symbol type="string" name="done_label" /> @@ -2039,19 +2036,24 @@ <java-symbol type="string" name="muted_by" /> <java-symbol type="string" name="item_is_selected" /> - <java-symbol type="string" name="day_of_week_label_typeface" /> <java-symbol type="string" name="select_day" /> - <java-symbol type="string" name="day_picker_description" /> <java-symbol type="string" name="select_year" /> - <java-symbol type="string" name="year_picker_description" /> - <java-symbol type="dimen" name="datepicker_day_number_size" /> - <java-symbol type="dimen" name="datepicker_month_label_size" /> - <java-symbol type="dimen" name="datepicker_month_day_label_text_size" /> - <java-symbol type="dimen" name="datepicker_month_list_item_header_height" /> + <java-symbol type="string" name="date_picker_month_typeface" /> + <java-symbol type="string" name="date_picker_day_of_week_typeface" /> + <java-symbol type="string" name="date_picker_day_typeface" /> + <java-symbol type="dimen" name="date_picker_month_text_size" /> + <java-symbol type="dimen" name="date_picker_day_of_week_text_size" /> + <java-symbol type="dimen" name="date_picker_day_text_size" /> + <java-symbol type="dimen" name="date_picker_month_height" /> + <java-symbol type="dimen" name="date_picker_day_height" /> + <java-symbol type="dimen" name="date_picker_day_width" /> + <java-symbol type="dimen" name="date_picker_day_selector_radius" /> + <java-symbol type="id" name="date_picker_day_picker" /> + <java-symbol type="id" name="date_picker_year_picker" /> + <java-symbol type="dimen" name="datepicker_view_animator_height" /> <java-symbol type="dimen" name="datepicker_year_label_height" /> - <java-symbol type="dimen" name="datepicker_year_picker_padding_top" /> <java-symbol type="array" name="config_clockTickVibePattern" /> <java-symbol type="array" name="config_calendarDateVibePattern" /> @@ -2115,7 +2117,6 @@ <java-symbol type="id" name="transitionTransform" /> <java-symbol type="id" name="parentMatrix" /> <java-symbol type="bool" name="config_auto_attach_data_on_creation" /> - <java-symbol type="id" name="date_picker_month_day_year_layout" /> <java-symbol type="attr" name="closeItemLayout" /> <java-symbol type="layout" name="resolver_different_item_header" /> <java-symbol type="array" name="config_default_vm_number" /> @@ -2167,4 +2168,10 @@ <java-symbol type="integer" name="config_screen_magnification_multi_tap_adjustment" /> <java-symbol type="dimen" name="config_screen_magnification_scaling_threshold" /> <java-symbol type="dimen" name="timepicker_selector_stroke"/> + + <java-symbol type="style" name="TextAppearance.Material.Widget.Calendar.Month" /> + <java-symbol type="style" name="TextAppearance.Material.Widget.Calendar.DayOfWeek" /> + <java-symbol type="style" name="TextAppearance.Material.Widget.Calendar.Day" /> + <java-symbol type="dimen" name="day_picker_padding_top"/> + <java-symbol type="dimen" name="date_picker_day_of_week_height"/> </resources> |