SimpleMonthView.java revision 5c33949d0272c4dfc313cf8b56d28597e2ec2c62
1bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio/* 2bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Copyright (C) 2014 The Android Open Source Project 3bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 4bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Licensed under the Apache License, Version 2.0 (the "License"); 5bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * you may not use this file except in compliance with the License. 6bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * You may obtain a copy of the License at 7bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 8bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * http://www.apache.org/licenses/LICENSE-2.0 9bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 10bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Unless required by applicable law or agreed to in writing, software 11bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * distributed under the License is distributed on an "AS IS" BASIS, 12bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * See the License for the specific language governing permissions and 14bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * limitations under the License. 15bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 16bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 17bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Megliopackage android.widget; 18bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 19bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.Context; 20bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.res.ColorStateList; 21bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.res.Resources; 220ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport android.content.res.TypedArray; 23bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.graphics.Canvas; 24bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.graphics.Paint; 25bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.graphics.Paint.Align; 26bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.graphics.Paint.Style; 27bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.graphics.Rect; 28bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.graphics.Typeface; 29bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.os.Bundle; 305dc973cb03889c58988703b58aefbd2397fb02c3Alan Viveretteimport android.text.TextPaint; 31bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.text.format.DateFormat; 32bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.util.AttributeSet; 33ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viveretteimport android.util.IntArray; 345c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viveretteimport android.util.MathUtils; 35c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viveretteimport android.util.StateSet; 36bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.MotionEvent; 37bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.View; 38bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityEvent; 39bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityNodeInfo; 400ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 41bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 42bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport com.android.internal.R; 43bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport com.android.internal.widget.ExploreByTouchHelper; 44bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 45fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viveretteimport java.text.SimpleDateFormat; 46bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.Calendar; 47bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.Locale; 48bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 49bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio/** 50bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * A calendar-like view displaying a specified month and the appropriate selectable day numbers 51bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * within the specified month. 52bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 53bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioclass SimpleMonthView extends View { 540ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private static final int DAYS_IN_WEEK = 7; 550ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private static final int MAX_WEEKS_IN_MONTH = 6; 56bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 57bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final int DEFAULT_SELECTED_DAY = -1; 58bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final int DEFAULT_WEEK_START = Calendar.SUNDAY; 59bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 600ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private static final String DEFAULT_TITLE_FORMAT = "MMMMy"; 610ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private static final String DAY_OF_WEEK_FORMAT = "EEEEE"; 62c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 635dc973cb03889c58988703b58aefbd2397fb02c3Alan Viverette private final TextPaint mMonthPaint = new TextPaint(); 645dc973cb03889c58988703b58aefbd2397fb02c3Alan Viverette private final TextPaint mDayOfWeekPaint = new TextPaint(); 655dc973cb03889c58988703b58aefbd2397fb02c3Alan Viverette private final TextPaint mDayPaint = new TextPaint(); 660ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private final Paint mDaySelectorPaint = new Paint(); 670ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private final Paint mDayHighlightPaint = new Paint(); 685dc973cb03889c58988703b58aefbd2397fb02c3Alan Viverette 690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private final Calendar mCalendar = Calendar.getInstance(); 7060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette private final Calendar mDayOfWeekLabelCalendar = Calendar.getInstance(); 71bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 720ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private final MonthViewTouchHelper mTouchHelper; 73fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette 740ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private final SimpleDateFormat mTitleFormatter; 750ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private final SimpleDateFormat mDayOfWeekFormatter; 76bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 77f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette // Desired dimensions. 78f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private final int mDesiredMonthHeight; 79f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private final int mDesiredDayOfWeekHeight; 80f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private final int mDesiredDayHeight; 81f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private final int mDesiredCellWidth; 82f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private final int mDesiredDaySelectorRadius; 8360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 840ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private CharSequence mTitle; 85bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 86bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mMonth; 87bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mYear; 88bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 89f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette // Dimensions as laid out. 90f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private int mMonthHeight; 91f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private int mDayOfWeekHeight; 92f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private int mDayHeight; 93f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private int mCellWidth; 94f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private int mDaySelectorRadius; 95f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette 960ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private int mPaddedWidth; 970ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private int mPaddedHeight; 98bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 990ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** The day of month for the selected day, or -1 if no day is selected. */ 100c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private int mActivatedDay = -1; 101bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1020ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** 1030ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * The day of month for today, or -1 if the today is not in the current 1040ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * month. 1050ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette */ 106bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mToday = DEFAULT_SELECTED_DAY; 107bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1080ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** The first day of the week (ex. Calendar.SUNDAY). */ 109bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mWeekStart = DEFAULT_WEEK_START; 110bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1110ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** The number of days (ex. 28) in the current month. */ 1120ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private int mDaysInMonth; 113bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1140ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** 1150ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * The day of week (ex. Calendar.SUNDAY) for the first day of the current 1160ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * month. 1170ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette */ 1180ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private int mDayOfWeekStart; 119bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1200ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** The day of month for the first (inclusive) enabled day. */ 121bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mEnabledDayStart = 1; 122bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1230ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** The day of month for the last (inclusive) enabled day. */ 124bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mEnabledDayEnd = 31; 125bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1260ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** Optional listener for handling day click actions. */ 127bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private OnDayClickListener mOnDayClickListener; 128bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 129c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private ColorStateList mDayTextColor; 130c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 13160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette private int mTouchedItem = -1; 13260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 133bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public SimpleMonthView(Context context) { 134bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio this(context, null); 135bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 136bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 137bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public SimpleMonthView(Context context, AttributeSet attrs) { 138bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio this(context, attrs, R.attr.datePickerStyle); 139bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 140bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 14150eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette public SimpleMonthView(Context context, AttributeSet attrs, int defStyleAttr) { 14250eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette this(context, attrs, defStyleAttr, 0); 14350eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette } 144bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 14550eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette public SimpleMonthView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 14650eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette super(context, attrs, defStyleAttr, defStyleRes); 147bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 14850eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette final Resources res = context.getResources(); 149f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mDesiredMonthHeight = res.getDimensionPixelSize(R.dimen.date_picker_month_height); 150f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mDesiredDayOfWeekHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_of_week_height); 151f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mDesiredDayHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_height); 152f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mDesiredCellWidth = res.getDimensionPixelSize(R.dimen.date_picker_day_width); 15378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette mDesiredDaySelectorRadius = res.getDimensionPixelSize( 15478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette R.dimen.date_picker_day_selector_radius); 15560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 156bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Set up accessibility components. 157bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper = new MonthViewTouchHelper(this); 158bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setAccessibilityDelegate(mTouchHelper); 159bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 160bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1610ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final Locale locale = res.getConfiguration().locale; 1620ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final String titleFormat = DateFormat.getBestDateTimePattern(locale, DEFAULT_TITLE_FORMAT); 1630ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mTitleFormatter = new SimpleDateFormat(titleFormat, locale); 1640ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayOfWeekFormatter = new SimpleDateFormat(DAY_OF_WEEK_FORMAT, locale); 1650ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 1660ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette initPaints(res); 1670ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 1680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 1690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** 1700ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * Applies the specified text appearance resource to a paint, returning the 1710ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * text color if one is set in the text appearance. 1720ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * 1730ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param p the paint to modify 1740ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param resId the resource ID of the text appearance 1750ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @return the text color, if available 1760ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette */ 1770ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private ColorStateList applyTextAppearance(Paint p, int resId) { 1780ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final TypedArray ta = mContext.obtainStyledAttributes(null, 1790ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette R.styleable.TextAppearance, 0, resId); 1800ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 1810ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final String fontFamily = ta.getString(R.styleable.TextAppearance_fontFamily); 1820ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (fontFamily != null) { 1830ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette p.setTypeface(Typeface.create(fontFamily, 0)); 1840ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 1850ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 1860ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette p.setTextSize(ta.getDimensionPixelSize( 1870ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette R.styleable.TextAppearance_textSize, (int) p.getTextSize())); 1880ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 1890ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final ColorStateList textColor = ta.getColorStateList(R.styleable.TextAppearance_textColor); 1900ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (textColor != null) { 1910ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int enabledColor = textColor.getColorForState(ENABLED_STATE_SET, 0); 1920ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette p.setColor(enabledColor); 1930ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 1940ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 1950ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette ta.recycle(); 1960ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 1970ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return textColor; 1980ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 1990ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 20078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette public int getMonthHeight() { 20178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette return mMonthHeight; 20278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 20378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 20478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette public int getCellWidth() { 20578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette return mCellWidth; 20678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 20778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 2080ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette public void setMonthTextAppearance(int resId) { 20978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette applyTextAppearance(mMonthPaint, resId); 21060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 2110ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 2120ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 2130ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 2140ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette public void setDayOfWeekTextAppearance(int resId) { 2150ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette applyTextAppearance(mDayOfWeekPaint, resId); 2160ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 2170ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 2180ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 2190ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette public void setDayTextAppearance(int resId) { 2200ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final ColorStateList textColor = applyTextAppearance(mDayPaint, resId); 2210ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (textColor != null) { 2220ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayTextColor = textColor; 2230ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 2240ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 2250ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 2260ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 2270ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 2280ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette public CharSequence getTitle() { 2290ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (mTitle == null) { 2300ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mTitle = mTitleFormatter.format(mCalendar.getTime()); 2310ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 2320ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return mTitle; 233c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette } 234c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 235c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette /** 236c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette * Sets up the text and style properties for painting. 237c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette */ 2380ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private void initPaints(Resources res) { 2390ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final String monthTypeface = res.getString(R.string.date_picker_month_typeface); 2400ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final String dayOfWeekTypeface = res.getString(R.string.date_picker_day_of_week_typeface); 2410ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final String dayTypeface = res.getString(R.string.date_picker_day_typeface); 2420ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 2430ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int monthTextSize = res.getDimensionPixelSize( 2440ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette R.dimen.date_picker_month_text_size); 2450ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int dayOfWeekTextSize = res.getDimensionPixelSize( 2460ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette R.dimen.date_picker_day_of_week_text_size); 2470ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int dayTextSize = res.getDimensionPixelSize( 2480ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette R.dimen.date_picker_day_text_size); 2490ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 250c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthPaint.setAntiAlias(true); 2510ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mMonthPaint.setTextSize(monthTextSize); 2520ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mMonthPaint.setTypeface(Typeface.create(monthTypeface, 0)); 253c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthPaint.setTextAlign(Align.CENTER); 254c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthPaint.setStyle(Style.FILL); 255c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 256c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekPaint.setAntiAlias(true); 2570ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayOfWeekPaint.setTextSize(dayOfWeekTextSize); 2580ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayOfWeekPaint.setTypeface(Typeface.create(dayOfWeekTypeface, 0)); 259c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekPaint.setTextAlign(Align.CENTER); 260c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekPaint.setStyle(Style.FILL); 261c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 2620ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDaySelectorPaint.setAntiAlias(true); 2630ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDaySelectorPaint.setStyle(Style.FILL); 2640ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 2650ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayHighlightPaint.setAntiAlias(true); 2660ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayHighlightPaint.setStyle(Style.FILL); 267c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 268c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayPaint.setAntiAlias(true); 2690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayPaint.setTextSize(dayTextSize); 2700ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayPaint.setTypeface(Typeface.create(dayTypeface, 0)); 271c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayPaint.setTextAlign(Align.CENTER); 272c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayPaint.setStyle(Style.FILL); 273bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 274bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 275c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette void setMonthTextColor(ColorStateList monthTextColor) { 276c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final int enabledColor = monthTextColor.getColorForState(ENABLED_STATE_SET, 0); 277c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthPaint.setColor(enabledColor); 278c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette invalidate(); 279c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette } 280bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 281c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette void setDayOfWeekTextColor(ColorStateList dayOfWeekTextColor) { 282c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final int enabledColor = dayOfWeekTextColor.getColorForState(ENABLED_STATE_SET, 0); 283c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekPaint.setColor(enabledColor); 284c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette invalidate(); 285c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette } 286bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 287c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette void setDayTextColor(ColorStateList dayTextColor) { 288c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayTextColor = dayTextColor; 289c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette invalidate(); 290c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette } 291bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 2920ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette void setDaySelectorColor(ColorStateList dayBackgroundColor) { 2935dc973cb03889c58988703b58aefbd2397fb02c3Alan Viverette final int activatedColor = dayBackgroundColor.getColorForState( 294c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0); 2950ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDaySelectorPaint.setColor(activatedColor); 296c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette invalidate(); 297bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 298bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 2990ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette void setDayHighlightColor(ColorStateList dayHighlightColor) { 3000ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int pressedColor = dayHighlightColor.getColorForState( 3010ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED), 0); 3020ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayHighlightPaint.setColor(pressedColor); 3030ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 304bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 305bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 306bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void setOnDayClickListener(OnDayClickListener listener) { 307bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mOnDayClickListener = listener; 308bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 309bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 310bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 311bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public boolean dispatchHoverEvent(MotionEvent event) { 312bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // First right-of-refusal goes the touch exploration helper. 3130ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return mTouchHelper.dispatchHoverEvent(event) || super.dispatchHoverEvent(event); 314bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 315bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 316bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 317bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public boolean onTouchEvent(MotionEvent event) { 31860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int x = (int) (event.getX() + 0.5f); 31960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int y = (int) (event.getY() + 0.5f); 32060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 321ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette final int action = event.getAction(); 322ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette switch (action) { 3230ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette case MotionEvent.ACTION_DOWN: 3240ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette case MotionEvent.ACTION_MOVE: 32578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final int touchedItem = getDayAtLocation(x, y); 32660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette if (mTouchedItem != touchedItem) { 32760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette mTouchedItem = touchedItem; 3280ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 329bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 330ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette if (action == MotionEvent.ACTION_DOWN && touchedItem < 0) { 331ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette // Touch something that's not an item, reject event. 332ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette return false; 333ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } 334bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio break; 3350ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 3360ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette case MotionEvent.ACTION_UP: 33778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final int clickedDay = getDayAtLocation(x, y); 33878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette onDayClicked(clickedDay); 3390ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Fall through. 3400ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette case MotionEvent.ACTION_CANCEL: 3410ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Reset touched day on stream end. 34260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette mTouchedItem = -1; 3430ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 3440ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette break; 345bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 346bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 347bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 348bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 349bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 350bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onDraw(Canvas canvas) { 3510ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int paddingLeft = getPaddingLeft(); 3520ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int paddingTop = getPaddingTop(); 3530ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette canvas.translate(paddingLeft, paddingTop); 3540ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 3550ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette drawMonth(canvas); 3560ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette drawDaysOfWeek(canvas); 357bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio drawDays(canvas); 3580ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 3590ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette canvas.translate(-paddingLeft, -paddingTop); 3600ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 3610ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 3620ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private void drawMonth(Canvas canvas) { 3630ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final float x = mPaddedWidth / 2f; 3640ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 3650ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Vertically centered within the month header height. 3660ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final float lineHeight = mMonthPaint.ascent() + mMonthPaint.descent(); 3670ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final float y = (mMonthHeight - lineHeight) / 2f; 3680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 3690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette canvas.drawText(getTitle().toString(), x, y, mMonthPaint); 3700ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 3710ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 3720ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private void drawDaysOfWeek(Canvas canvas) { 37360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final TextPaint p = mDayOfWeekPaint; 37460b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int headerHeight = mMonthHeight; 37560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int rowHeight = mDayOfWeekHeight; 376f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int colWidth = mCellWidth; 37760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 37860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette // Text is vertically centered within the day of week height. 37960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final float halfLineHeight = (p.ascent() + p.descent()) / 2f; 38060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int rowCenter = headerHeight + rowHeight / 2; 38160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 38260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette for (int col = 0; col < DAYS_IN_WEEK; col++) { 38360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int colCenter = colWidth * col + colWidth / 2; 384ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette final int colCenterRtl; 385ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette if (isLayoutRtl()) { 386ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette colCenterRtl = mPaddedWidth - colCenter; 387ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } else { 388ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette colCenterRtl = colCenter; 389ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } 390ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette 39160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int dayOfWeek = (col + mWeekStart) % DAYS_IN_WEEK; 39260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final String label = getDayOfWeekLabel(dayOfWeek); 393ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette canvas.drawText(label, colCenterRtl, rowCenter - halfLineHeight, p); 3940ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 3950ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 3960ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 39760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette private String getDayOfWeekLabel(int dayOfWeek) { 39860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette mDayOfWeekLabelCalendar.set(Calendar.DAY_OF_WEEK, dayOfWeek); 39960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette return mDayOfWeekFormatter.format(mDayOfWeekLabelCalendar.getTime()); 40060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette } 40160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 4020ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** 4030ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * Draws the month days. 4040ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette */ 4050ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private void drawDays(Canvas canvas) { 40660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final TextPaint p = mDayPaint; 40760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int headerHeight = mMonthHeight + mDayOfWeekHeight; 40860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int rowHeight = mDayHeight; 409f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int colWidth = mCellWidth; 4100ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 41160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette // Text is vertically centered within the row height. 41260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final float halfLineHeight = (p.ascent() + p.descent()) / 2f; 41360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette int rowCenter = headerHeight + rowHeight / 2; 4140ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 41560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette for (int day = 1, col = findDayOffset(); day <= mDaysInMonth; day++) { 41660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int colCenter = colWidth * col + colWidth / 2; 417ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette final int colCenterRtl; 418ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette if (isLayoutRtl()) { 419ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette colCenterRtl = mPaddedWidth - colCenter; 420ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } else { 421ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette colCenterRtl = colCenter; 422ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } 423ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette 4240ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette int stateMask = 0; 4250ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 4265c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette final boolean isDayEnabled = isDayEnabled(day); 4275c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (isDayEnabled) { 4280ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette stateMask |= StateSet.VIEW_STATE_ENABLED; 4290ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 4300ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 4310ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final boolean isDayActivated = mActivatedDay == day; 4320ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (isDayActivated) { 4330ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette stateMask |= StateSet.VIEW_STATE_ACTIVATED; 4340ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 4350ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Adjust the circle to be centered on the row. 436ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette canvas.drawCircle(colCenterRtl, rowCenter, mDaySelectorRadius, mDaySelectorPaint); 43760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette } else if (mTouchedItem == day) { 4380ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette stateMask |= StateSet.VIEW_STATE_PRESSED; 4390ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 4405c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (isDayEnabled) { 4415c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette // Adjust the circle to be centered on the row. 4425c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette canvas.drawCircle(colCenterRtl, rowCenter, 4435c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette mDaySelectorRadius, mDayHighlightPaint); 4445c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette } 4450ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 4460ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 4470ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final boolean isDayToday = mToday == day; 4480ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int dayTextColor; 4490ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (isDayToday && !isDayActivated) { 4500ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette dayTextColor = mDaySelectorPaint.getColor(); 4510ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } else { 4520ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int[] stateSet = StateSet.get(stateMask); 4530ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette dayTextColor = mDayTextColor.getColorForState(stateSet, 0); 4540ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 45560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette p.setColor(dayTextColor); 4560ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 457ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette canvas.drawText(Integer.toString(day), colCenterRtl, rowCenter - halfLineHeight, p); 4580ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 45960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette col++; 4600ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 46160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette if (col == DAYS_IN_WEEK) { 46260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette col = 0; 46360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette rowCenter += rowHeight; 4640ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 4650ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 466bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 467bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 4685c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette private boolean isDayEnabled(int day) { 4695c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette return day >= mEnabledDayStart && day <= mEnabledDayEnd; 4705c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette } 4715c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette 4725c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette private boolean isValidDayOfMonth(int day) { 4735c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette return day >= 1 && day <= mDaysInMonth; 4745c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette } 4755c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette 476518ff0de95e64116ecb07706fc564d4c19197ca7Alan Viverette private static boolean isValidDayOfWeek(int day) { 4775878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette return day >= Calendar.SUNDAY && day <= Calendar.SATURDAY; 4785878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette } 4795878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette 4805878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette private static boolean isValidMonth(int month) { 4815878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette return month >= Calendar.JANUARY && month <= Calendar.DECEMBER; 48275b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio } 48375b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio 484bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 4850ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * Sets the selected day. 486bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 4870ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param dayOfMonth the selected day of the month, or {@code -1} to clear 4880ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * the selection 4890ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette */ 4900ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette public void setSelectedDay(int dayOfMonth) { 4910ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mActivatedDay = dayOfMonth; 4920ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 4930ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Invalidate cached accessibility information. 4940ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mTouchHelper.invalidateRoot(); 4950ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 4960ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 4970ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 4980ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** 4990ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * Sets the first day of the week. 5000ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * 5010ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param weekStart which day the week should start on, valid values are 5020ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY} 5030ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette */ 5040ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette public void setFirstDayOfWeek(int weekStart) { 5050ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (isValidDayOfWeek(weekStart)) { 5060ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mWeekStart = weekStart; 5070ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } else { 5080ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mWeekStart = mCalendar.getFirstDayOfWeek(); 5090ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 5100ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 5110ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Invalidate cached accessibility information. 5120ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mTouchHelper.invalidateRoot(); 5130ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 5140ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 5150ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 5160ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** 5170ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * Sets all the parameters for displaying this week. 5180ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * <p> 5190ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * Parameters have a default value and will only update if a new value is 5200ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * included, except for focus month, which will always default to no focus 5210ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * month if no value is passed in. The only required parameter is the week 5220ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * start. 5230ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * 5240ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param selectedDay the selected day of the month, or -1 for no selection 5250ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param month the month 5260ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param year the year 5270ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param weekStart which day the week should start on, valid values are 5280ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY} 5290ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param enabledDayStart the first enabled day 5300ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param enabledDayEnd the last enabled day 531bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 53275b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio void setMonthParams(int selectedDay, int month, int year, int weekStart, int enabledDayStart, 53375b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio int enabledDayEnd) { 534c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mActivatedDay = selectedDay; 535bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 5365878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette if (isValidMonth(month)) { 53775b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mMonth = month; 53875b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio } 53975b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mYear = year; 540bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 541bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mCalendar.set(Calendar.MONTH, mMonth); 542bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mCalendar.set(Calendar.YEAR, mYear); 543bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mCalendar.set(Calendar.DAY_OF_MONTH, 1); 544bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayOfWeekStart = mCalendar.get(Calendar.DAY_OF_WEEK); 545bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 546518ff0de95e64116ecb07706fc564d4c19197ca7Alan Viverette if (isValidDayOfWeek(weekStart)) { 54775b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mWeekStart = weekStart; 548bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } else { 549bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mWeekStart = mCalendar.getFirstDayOfWeek(); 550bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 551bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 5520ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Figure out what day today is. 5530ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final Calendar today = Calendar.getInstance(); 5540ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mToday = -1; 5550ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDaysInMonth = getDaysInMonth(mMonth, mYear); 5560ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette for (int i = 0; i < mDaysInMonth; i++) { 557bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int day = i + 1; 558bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (sameDay(day, today)) { 559bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mToday = day; 560bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 561bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 5620ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 5635c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette mEnabledDayStart = MathUtils.constrain(enabledDayStart, 1, mDaysInMonth); 5645c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette mEnabledDayEnd = MathUtils.constrain(enabledDayEnd, mEnabledDayStart, mDaysInMonth); 5655c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette 5660ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Invalidate the old title. 5670ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mTitle = null; 568bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 569bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Invalidate cached accessibility information. 570bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.invalidateRoot(); 571bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 572bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 573bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static int getDaysInMonth(int month, int year) { 574bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (month) { 575bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.JANUARY: 576bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.MARCH: 577bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.MAY: 578bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.JULY: 579bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.AUGUST: 580bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.OCTOBER: 581bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.DECEMBER: 582bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return 31; 583bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.APRIL: 584bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.JUNE: 585bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.SEPTEMBER: 586bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.NOVEMBER: 587bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return 30; 588bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.FEBRUARY: 589bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return (year % 4 == 0) ? 29 : 28; 590bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 591bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new IllegalArgumentException("Invalid Month"); 592bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 593bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 594bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 5950ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private boolean sameDay(int day, Calendar today) { 5960ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return mYear == today.get(Calendar.YEAR) && mMonth == today.get(Calendar.MONTH) 5970ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette && day == today.get(Calendar.DAY_OF_MONTH); 598bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 599bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 600bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 601bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 602816aa142023c75cf427401c21831193998bdf233Alan Viverette final int preferredHeight = mDesiredDayHeight * MAX_WEEKS_IN_MONTH 603816aa142023c75cf427401c21831193998bdf233Alan Viverette + mDesiredDayOfWeekHeight + mDesiredMonthHeight 604816aa142023c75cf427401c21831193998bdf233Alan Viverette + getPaddingTop() + getPaddingBottom(); 605f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int preferredWidth = mDesiredCellWidth * DAYS_IN_WEEK 6060ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette + getPaddingStart() + getPaddingEnd(); 6070ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int resolvedWidth = resolveSize(preferredWidth, widthMeasureSpec); 6080ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int resolvedHeight = resolveSize(preferredHeight, heightMeasureSpec); 6090ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette setMeasuredDimension(resolvedWidth, resolvedHeight); 610bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 611bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 612bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 613ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 614ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette super.onRtlPropertiesChanged(layoutDirection); 615ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette 616ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette requestLayout(); 617ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } 618ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette 619ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette @Override 620f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 621f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette if (!changed) { 622f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette return; 623f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette } 624f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette 625f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette // Let's initialize a completely reasonable number of variables. 626f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int w = right - left; 627f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int h = bottom - top; 628f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddingLeft = getPaddingLeft(); 629f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddingTop = getPaddingTop(); 630f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddingRight = getPaddingRight(); 631f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddingBottom = getPaddingBottom(); 632f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddedRight = w - paddingRight; 633f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddedBottom = h - paddingBottom; 634f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddedWidth = paddedRight - paddingLeft; 635f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddedHeight = paddedBottom - paddingTop; 636f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette if (paddedWidth == mPaddedWidth || paddedHeight == mPaddedHeight) { 637f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette return; 638f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette } 639f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette 640f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mPaddedWidth = paddedWidth; 641f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mPaddedHeight = paddedHeight; 642f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette 643f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette // We may have been laid out smaller than our preferred size. If so, 644f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette // scale all dimensions to fit. 645f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int measuredPaddedHeight = getMeasuredHeight() - paddingTop - paddingBottom; 646f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final float scaleH = paddedHeight / (float) measuredPaddedHeight; 647f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int monthHeight = (int) (mDesiredMonthHeight * scaleH); 64860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int cellWidth = mPaddedWidth / DAYS_IN_WEEK; 649f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mMonthHeight = monthHeight; 650f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mDayOfWeekHeight = (int) (mDesiredDayOfWeekHeight * scaleH); 651f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mDayHeight = (int) (mDesiredDayHeight * scaleH); 652f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mCellWidth = cellWidth; 653f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette 654f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette // Compute the largest day selector radius that's still within the clip 655f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette // bounds and desired selector radius. 656f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int maxSelectorWidth = cellWidth / 2 + Math.min(paddingLeft, paddingRight); 657f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int maxSelectorHeight = mDayHeight / 2 + paddingBottom; 658f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mDaySelectorRadius = Math.min(mDesiredDaySelectorRadius, 659f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette Math.min(maxSelectorWidth, maxSelectorHeight)); 66060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 661bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Invalidate cached accessibility information. 662bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.invalidateRoot(); 663bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 664bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 6650ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private int findDayOffset() { 6660ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int offset = mDayOfWeekStart - mWeekStart; 6670ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (mDayOfWeekStart < mWeekStart) { 6680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return offset + DAYS_IN_WEEK; 669bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 6700ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return offset; 671bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 672bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 673bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 67478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * Calculates the day of the month at the specified touch position. Returns 67578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * the day of the month or -1 if the position wasn't in a valid day. 6760ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * 6770ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param x the x position of the touch event 6780ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param y the y position of the touch event 67978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * @return the day of the month at (x, y), or -1 if the position wasn't in 68078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * a valid day 681bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 68278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette private int getDayAtLocation(int x, int y) { 68360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int paddedX = x - getPaddingLeft(); 6840ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (paddedX < 0 || paddedX >= mPaddedWidth) { 6850ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return -1; 6860ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 687c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 6880ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int headerHeight = mMonthHeight + mDayOfWeekHeight; 68960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int paddedY = y - getPaddingTop(); 6900ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (paddedY < headerHeight || paddedY >= mPaddedHeight) { 6910ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return -1; 6920ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 693c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 694ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette // Adjust for RTL after applying padding. 695ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette final int paddedXRtl; 696ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette if (isLayoutRtl()) { 697ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette paddedXRtl = mPaddedWidth - paddedX; 698ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } else { 699ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette paddedXRtl = paddedX; 700ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } 701ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette 7020ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int row = (paddedY - headerHeight) / mDayHeight; 703ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette final int col = (paddedXRtl * DAYS_IN_WEEK) / mPaddedWidth; 7040ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int index = col + row * DAYS_IN_WEEK; 7050ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int day = index + 1 - findDayOffset(); 7065c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (!isValidDayOfMonth(day)) { 7070ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return -1; 708bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 709bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 7100ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return day; 711bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 712bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 713bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 7140ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * Calculates the bounds of the specified day. 715bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 71678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * @param id the day of the month 7170ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param outBounds the rect to populate with bounds 718bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 71978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette private boolean getBoundsForDay(int id, Rect outBounds) { 7205c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (!isValidDayOfMonth(id)) { 7210ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return false; 722bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 723bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 72460b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int index = id - 1 + findDayOffset(); 72560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 726ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette // Compute left edge, taking into account RTL. 7270ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int col = index % DAYS_IN_WEEK; 728f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int colWidth = mCellWidth; 729ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette final int left; 730ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette if (isLayoutRtl()) { 731ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette left = getWidth() - getPaddingRight() - (col + 1) * colWidth; 732ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } else { 733ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette left = getPaddingLeft() + col * colWidth; 734ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } 7350ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 73660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette // Compute top edge. 73760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int row = index / DAYS_IN_WEEK; 73860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int rowHeight = mDayHeight; 7390ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int headerHeight = mMonthHeight + mDayOfWeekHeight; 74060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int top = getPaddingTop() + headerHeight + row * rowHeight; 7410ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 74260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette outBounds.set(left, top, left + colWidth, top + rowHeight); 743bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 74478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette return true; 74560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette } 74660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 74760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette /** 748bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Called when the user clicks on a day. Handles callbacks to the 749bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link OnDayClickListener} if one is set. 750bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 7510ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param day the day that was clicked 752bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 75360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette private boolean onDayClicked(int day) { 7545c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (!isValidDayOfMonth(day) || !isDayEnabled(day)) { 75560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette return false; 75660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette } 75760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 758bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mOnDayClickListener != null) { 75960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final Calendar date = Calendar.getInstance(); 760bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio date.set(mYear, mMonth, day); 761bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mOnDayClickListener.onDayClick(this, date); 762bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 763bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 764bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // This is a no-op if accessibility is turned off. 765bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.sendEventForVirtualView(day, AccessibilityEvent.TYPE_VIEW_CLICKED); 76660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette return true; 76760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette } 76860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 76960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette /** 770bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Provides a virtual view hierarchy for interfacing with an accessibility 771bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * service. 772bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 773bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private class MonthViewTouchHelper extends ExploreByTouchHelper { 774bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final String DATE_FORMAT = "dd MMMM yyyy"; 775bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 776bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final Rect mTempRect = new Rect(); 777bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final Calendar mTempCalendar = Calendar.getInstance(); 778bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 779bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public MonthViewTouchHelper(View host) { 780bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio super(host); 781bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 782bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 783bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 784bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected int getVirtualViewAt(float x, float y) { 78578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final int day = getDayAtLocation((int) (x + 0.5f), (int) (y + 0.5f)); 7865c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (day != -1) { 787bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return day; 788bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 789bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return ExploreByTouchHelper.INVALID_ID; 790bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 791bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 792bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 793ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette protected void getVisibleVirtualViews(IntArray virtualViewIds) { 7940ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette for (int day = 1; day <= mDaysInMonth; day++) { 795bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio virtualViewIds.add(day); 796bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 797bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 798bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 799bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 800bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) { 80178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette event.setContentDescription(getDayDescription(virtualViewId)); 802bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 803bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 804bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 805bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfo node) { 80678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final boolean hasBounds = getBoundsForDay(virtualViewId, mTempRect); 8070ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 8080ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (!hasBounds) { 8090ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // The day is invalid, kill the node. 8100ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mTempRect.setEmpty(); 8110ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette node.setContentDescription(""); 8120ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette node.setBoundsInParent(mTempRect); 8130ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette node.setVisibleToUser(false); 8140ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return; 8150ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 816bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 81778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette node.setText(getDayText(virtualViewId)); 81878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette node.setContentDescription(getDayDescription(virtualViewId)); 819bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setBoundsInParent(mTempRect); 8205c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette 8215c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette final boolean isDayEnabled = isDayEnabled(virtualViewId); 8225c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (isDayEnabled) { 8235c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette node.addAction(AccessibilityAction.ACTION_CLICK); 8245c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette } 8255c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette 8265c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette node.setEnabled(isDayEnabled); 827bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 828c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette if (virtualViewId == mActivatedDay) { 82960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette // TODO: This should use activated once that's supported. 83060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette node.setChecked(true); 831bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 832bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 833bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 834bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 835bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 836bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected boolean onPerformActionForVirtualView(int virtualViewId, int action, 837bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio Bundle arguments) { 838bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (action) { 839bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case AccessibilityNodeInfo.ACTION_CLICK: 84078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette return onDayClicked(virtualViewId); 841bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 842bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 843bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 844bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 845bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 846bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 84760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette * Generates a description for a given virtual view. 848bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 84978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * @param id the day to generate a description for 85060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette * @return a description of the virtual view 851bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 85278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette private CharSequence getDayDescription(int id) { 8535c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (isValidDayOfMonth(id)) { 85460b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette mTempCalendar.set(mYear, mMonth, id); 85560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette return DateFormat.format(DATE_FORMAT, mTempCalendar.getTimeInMillis()); 85660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette } 857bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 85860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette return ""; 85960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette } 86060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 86160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette /** 86260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette * Generates displayed text for a given virtual view. 86360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette * 86478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * @param id the day to generate text for 86560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette * @return the visible text of the virtual view 86660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette */ 86778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette private CharSequence getDayText(int id) { 8685c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (isValidDayOfMonth(id)) { 86960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette return Integer.toString(id); 870bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 871bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 87260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette return null; 873bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 874bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 875bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 876bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 877bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Handles callbacks when the user clicks on a time object. 878bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 879bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public interface OnDayClickListener { 88078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette void onDayClick(SimpleMonthView view, Calendar day); 881bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 882bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio} 883