Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4612740d authored by Alan Viverette's avatar Alan Viverette
Browse files

Implement Material-style delegate for CalendarView

BUG: 18266649
Change-Id: Ifd749328754b82dc43259ca7dadb472e449bdfff
parent 4fc2ea84
Loading
Loading
Loading
Loading
+38 −1578

File changed.

Preview size limit exceeded, changes collapsed.

+1527 −0

File added.

Preview size limit exceeded, changes collapsed.

+260 −0
Original line number Original line Diff line number Diff line
/*
 * 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.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;

    private CalendarView.OnDateChangeListener mOnDateChangeListener;

    public CalendarViewMaterialDelegate(CalendarView delegator, Context context, AttributeSet attrs,
            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.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) {

    }

    @Override
    public int getWeekDayTextAppearance() {
        return 0;
    }

    @Override
    public void setDateTextAppearance(int resourceId) {

    }

    @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;
    }

    @Override
    public void setMinDate(long minDate) {
        mDayPickerView.setMinDate(minDate);
    }

    @Override
    public long getMinDate() {
        return mDayPickerView.getMinDate();
    }

    @Override
    public void setMaxDate(long maxDate) {
        mDayPickerView.setMaxDate(maxDate);
    }

    @Override
    public long getMaxDate() {
        return mDayPickerView.getMaxDate();
    }

    @Override
    public void setShowWeekNumber(boolean showWeekNumber) {
        // Deprecated.
    }

    @Override
    public boolean getShowWeekNumber() {
        // Deprecated.
        return false;
    }

    @Override
    public void setFirstDayOfWeek(int firstDayOfWeek) {
        mDayPickerView.setFirstDayOfWeek(firstDayOfWeek);
    }

    @Override
    public int getFirstDayOfWeek() {
        return mDayPickerView.getFirstDayOfWeek();
    }

    @Override
    public void setDate(long date) {
        mDayPickerView.setDate(date, true, false);
    }

    @Override
    public void setDate(long date, boolean animate, boolean center) {
        mDayPickerView.setDate(date, animate, center);
    }

    @Override
    public long getDate() {
        return mDayPickerView.getDate();
    }

    @Override
    public void setOnDateChangeListener(CalendarView.OnDateChangeListener listener) {
        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
        public void onDaySelected(DayPickerView view, Calendar day) {
            if (mOnDateChangeListener != null) {
                final int year = day.get(Calendar.YEAR);
                final int month = day.get(Calendar.MONTH);
                final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH);
                mOnDateChangeListener.onSelectedDayChange(mDelegator, year, month, dayOfMonth);
            }
        }
    };
}
+7 −6
Original line number Original line Diff line number Diff line
@@ -185,8 +185,9 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i


        mDayPickerView = new DayPickerView(mContext);
        mDayPickerView = new DayPickerView(mContext);
        mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek);
        mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek);
        mDayPickerView.setRange(mMinDate, mMaxDate);
        mDayPickerView.setMinDate(mMinDate.getTimeInMillis());
        mDayPickerView.setDay(mCurrentDate);
        mDayPickerView.setMaxDate(mMaxDate.getTimeInMillis());
        mDayPickerView.setDate(mCurrentDate.getTimeInMillis());
        mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener);
        mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener);


        mYearPickerView = new YearPickerView(mContext);
        mYearPickerView = new YearPickerView(mContext);
@@ -336,7 +337,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i


        switch (viewIndex) {
        switch (viewIndex) {
            case MONTH_AND_DAY_VIEW:
            case MONTH_AND_DAY_VIEW:
                mDayPickerView.setDay(getSelectedDay());
                mDayPickerView.setDate(getSelectedDay().getTimeInMillis());
                if (mCurrentView != viewIndex) {
                if (mCurrentView != viewIndex) {
                    mMonthAndDayLayout.setSelected(true);
                    mMonthAndDayLayout.setSelected(true);
                    mHeaderYearTextView.setSelected(false);
                    mHeaderYearTextView.setSelected(false);
@@ -414,7 +415,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
            updateDisplay(false);
            updateDisplay(false);
        }
        }
        mMinDate.setTimeInMillis(minDate);
        mMinDate.setTimeInMillis(minDate);
        mDayPickerView.setRange(mMinDate, mMaxDate);
        mDayPickerView.setMinDate(minDate);
        mYearPickerView.setRange(mMinDate, mMaxDate);
        mYearPickerView.setRange(mMinDate, mMaxDate);
    }
    }


@@ -436,7 +437,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
            updateDisplay(false);
            updateDisplay(false);
        }
        }
        mMaxDate.setTimeInMillis(maxDate);
        mMaxDate.setTimeInMillis(maxDate);
        mDayPickerView.setRange(mMinDate, mMaxDate);
        mDayPickerView.setMaxDate(maxDate);
        mYearPickerView.setRange(mMinDate, mMaxDate);
        mYearPickerView.setRange(mMinDate, mMaxDate);
    }
    }


@@ -616,7 +617,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
            listener.onDateChanged();
            listener.onDateChanged();
        }
        }


        mDayPickerView.setDay(getSelectedDay());
        mDayPickerView.setDate(getSelectedDay().getTimeInMillis());
    }
    }


    @Override
    @Override
+68 −17
Original line number Original line Diff line number Diff line
@@ -58,6 +58,8 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener {
    private Calendar mMinDate = Calendar.getInstance();
    private Calendar mMinDate = Calendar.getInstance();
    private Calendar mMaxDate = Calendar.getInstance();
    private Calendar mMaxDate = Calendar.getInstance();


    private Calendar mTempCalendar;

    private OnDaySelectedListener mOnDaySelectedListener;
    private OnDaySelectedListener mOnDaySelectedListener;


    // which month should be displayed/highlighted [0-11]
    // which month should be displayed/highlighted [0-11]
@@ -77,28 +79,65 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener {
        setDrawSelectorOnTop(false);
        setDrawSelectorOnTop(false);
        setUpListView();
        setUpListView();


        goTo(mSelectedDay, false, true, true);
        goTo(mSelectedDay.getTimeInMillis(), false, false, true);


        mAdapter.setOnDaySelectedListener(mProxyOnDaySelectedListener);
        mAdapter.setOnDaySelectedListener(mProxyOnDaySelectedListener);
    }
    }


    public void setDay(Calendar day) {
    /**
        goTo(day, false, true, true);
     * 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)}.
     *
     * @param timeInMillis
     */
    public void setDate(long timeInMillis) {
        setDate(timeInMillis, false, true);
    }

    public void setDate(long timeInMillis, boolean animate, boolean forceScroll) {
        goTo(timeInMillis, animate, true, forceScroll);
    }

    public long getDate() {
        return mSelectedDay.getTimeInMillis();
    }
    }


    public void setFirstDayOfWeek(int firstDayOfWeek) {
    public void setFirstDayOfWeek(int firstDayOfWeek) {
        mAdapter.setFirstDayOfWeek(firstDayOfWeek);
        mAdapter.setFirstDayOfWeek(firstDayOfWeek);
    }
    }


    public void setRange(Calendar minDate, Calendar maxDate) {
    public int getFirstDayOfWeek() {
        mMinDate.setTimeInMillis(minDate.getTimeInMillis());
        return mAdapter.getFirstDayOfWeek();
        mMaxDate.setTimeInMillis(maxDate.getTimeInMillis());
    }

    public void setMinDate(long timeInMillis) {
        mMinDate.setTimeInMillis(timeInMillis);
        onRangeChanged();
    }

    public long getMinDate() {
        return mMinDate.getTimeInMillis();
    }

    public void setMaxDate(long timeInMillis) {
        mMaxDate.setTimeInMillis(timeInMillis);
        onRangeChanged();
    }


    public long getMaxDate() {
        return mMaxDate.getTimeInMillis();
    }

    /**
     * Handles changes to date range.
     */
    public void onRangeChanged() {
        mAdapter.setRange(mMinDate, mMaxDate);
        mAdapter.setRange(mMinDate, mMaxDate);


        // Changing the min/max date changes the selection position since we
        // Changing the min/max date changes the selection position since we
        // don't really have stable IDs.
        // don't really have stable IDs. Jumps immediately to the new position.
        goTo(mSelectedDay, false, true, true);
        goTo(mSelectedDay.getTimeInMillis(), false, false, true);
    }
    }


    /**
    /**
@@ -136,12 +175,20 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener {
        return diffMonths;
        return diffMonths;
    }
    }


    private int getPositionFromDay(Calendar day) {
    private int getPositionFromDay(long timeInMillis) {
        final int diffMonthMax = getDiffMonths(mMinDate, mMaxDate);
        final int diffMonthMax = getDiffMonths(mMinDate, mMaxDate);
        final int diffMonth = getDiffMonths(mMinDate, day);
        final int diffMonth = getDiffMonths(mMinDate, getTempCalendarForTime(timeInMillis));
        return MathUtils.constrain(diffMonth, 0, diffMonthMax);
        return MathUtils.constrain(diffMonth, 0, diffMonthMax);
    }
    }


    private Calendar getTempCalendarForTime(long timeInMillis) {
        if (mTempCalendar == null) {
            mTempCalendar = Calendar.getInstance();
        }
        mTempCalendar.setTimeInMillis(timeInMillis);
        return mTempCalendar;
    }

    /**
    /**
     * This moves to the specified time in the view. If the time is not already
     * 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
     * in range it will move the list so that the first of the month containing
@@ -157,14 +204,14 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener {
     *            visible
     *            visible
     * @return Whether or not the view animated to the new location
     * @return Whether or not the view animated to the new location
     */
     */
    private boolean goTo(Calendar day, boolean animate, boolean setSelected, boolean forceScroll) {
    private boolean goTo(long day, boolean animate, boolean setSelected, boolean forceScroll) {


        // Set the selected day
        // Set the selected day
        if (setSelected) {
        if (setSelected) {
            mSelectedDay.setTimeInMillis(day.getTimeInMillis());
            mSelectedDay.setTimeInMillis(day);
        }
        }


        mTempDay.setTimeInMillis(day.getTimeInMillis());
        mTempDay.setTimeInMillis(day);
        final int position = getPositionFromDay(day);
        final int position = getPositionFromDay(day);


        View child;
        View child;
@@ -258,6 +305,10 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener {
        mAdapter.setCalendarTextColor(colors);
        mAdapter.setCalendarTextColor(colors);
    }
    }


    void setCalendarTextAppearance(int resId) {
        mAdapter.setCalendarTextAppearance(resId);
    }

    protected class ScrollStateRunnable implements Runnable {
    protected class ScrollStateRunnable implements Runnable {
        private int mNewState;
        private int mNewState;
        private View mParent;
        private View mParent;
@@ -415,7 +466,7 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener {
    }
    }


    private String getMonthAndYearString(Calendar day) {
    private String getMonthAndYearString(Calendar day) {
        StringBuffer sbuf = new StringBuffer();
        final StringBuilder sbuf = new StringBuilder();
        sbuf.append(day.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault()));
        sbuf.append(day.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault()));
        sbuf.append(" ");
        sbuf.append(" ");
        sbuf.append(mYearFormat.format(day.getTime()));
        sbuf.append(mYearFormat.format(day.getTime()));
@@ -429,8 +480,8 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener {
    @Override
    @Override
    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
        super.onInitializeAccessibilityNodeInfo(info);
        super.onInitializeAccessibilityNodeInfo(info);
        info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
        info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
        info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
        info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
    }
    }


    /**
    /**
@@ -474,7 +525,7 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener {


        // Go to that month.
        // Go to that month.
        announceForAccessibility(getMonthAndYearString(day));
        announceForAccessibility(getMonthAndYearString(day));
        goTo(day, true, false, true);
        goTo(day.getTimeInMillis(), true, false, true);
        mPerformingScroll = true;
        mPerformingScroll = true;
        return true;
        return true;
    }
    }
Loading