SimpleMonthView.java revision a7f827bab3df423d2a3b527853de3e9ac9e378fd
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; 29a7f827bab3df423d2a3b527853de3e9ac9e378fdDeepanshu Guptaimport android.icu.text.SimpleDateFormat; 30bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.os.Bundle; 315dc973cb03889c58988703b58aefbd2397fb02c3Alan Viveretteimport android.text.TextPaint; 32bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.text.format.DateFormat; 33bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.util.AttributeSet; 34ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viveretteimport android.util.IntArray; 355c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viveretteimport android.util.MathUtils; 36c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viveretteimport android.util.StateSet; 37bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.MotionEvent; 38bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.View; 39bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityEvent; 40bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityNodeInfo; 410ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viveretteimport android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 42bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 43bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport com.android.internal.R; 44bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport com.android.internal.widget.ExploreByTouchHelper; 45bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 461ea4715cecf8d1a17a21f3d21ea4df56519e5ea6Chet Haaseimport java.text.NumberFormat; 47bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.Calendar; 48bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.Locale; 49bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 50bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio/** 51bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * A calendar-like view displaying a specified month and the appropriate selectable day numbers 52bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * within the specified month. 53bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 54bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioclass SimpleMonthView extends View { 550ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private static final int DAYS_IN_WEEK = 7; 560ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private static final int MAX_WEEKS_IN_MONTH = 6; 57bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 58bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final int DEFAULT_SELECTED_DAY = -1; 59bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final int DEFAULT_WEEK_START = Calendar.SUNDAY; 60bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 610ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private static final String DEFAULT_TITLE_FORMAT = "MMMMy"; 620ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private static final String DAY_OF_WEEK_FORMAT = "EEEEE"; 63c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 645dc973cb03889c58988703b58aefbd2397fb02c3Alan Viverette private final TextPaint mMonthPaint = new TextPaint(); 655dc973cb03889c58988703b58aefbd2397fb02c3Alan Viverette private final TextPaint mDayOfWeekPaint = new TextPaint(); 665dc973cb03889c58988703b58aefbd2397fb02c3Alan Viverette private final TextPaint mDayPaint = new TextPaint(); 670ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private final Paint mDaySelectorPaint = new Paint(); 680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private final Paint mDayHighlightPaint = new Paint(); 695dc973cb03889c58988703b58aefbd2397fb02c3Alan Viverette 700ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private final Calendar mCalendar = Calendar.getInstance(); 7160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette private final Calendar mDayOfWeekLabelCalendar = Calendar.getInstance(); 72bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 730ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private final MonthViewTouchHelper mTouchHelper; 74fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette 750ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private final SimpleDateFormat mTitleFormatter; 760ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private final SimpleDateFormat mDayOfWeekFormatter; 771ea4715cecf8d1a17a21f3d21ea4df56519e5ea6Chet Haase private final NumberFormat mDayFormatter; 78bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 79f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette // Desired dimensions. 80f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private final int mDesiredMonthHeight; 81f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private final int mDesiredDayOfWeekHeight; 82f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private final int mDesiredDayHeight; 83f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private final int mDesiredCellWidth; 84f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private final int mDesiredDaySelectorRadius; 8560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 860ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private CharSequence mTitle; 87bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 88bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mMonth; 89bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mYear; 90bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 91f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette // Dimensions as laid out. 92f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private int mMonthHeight; 93f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private int mDayOfWeekHeight; 94f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private int mDayHeight; 95f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private int mCellWidth; 96f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette private int mDaySelectorRadius; 97f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette 980ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private int mPaddedWidth; 990ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private int mPaddedHeight; 100bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1010ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** The day of month for the selected day, or -1 if no day is selected. */ 102c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private int mActivatedDay = -1; 103bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1040ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** 1050ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * The day of month for today, or -1 if the today is not in the current 1060ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * month. 1070ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette */ 108bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mToday = DEFAULT_SELECTED_DAY; 109bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1100ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** The first day of the week (ex. Calendar.SUNDAY). */ 111bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mWeekStart = DEFAULT_WEEK_START; 112bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1130ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** The number of days (ex. 28) in the current month. */ 1140ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private int mDaysInMonth; 115bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1160ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** 1170ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * The day of week (ex. Calendar.SUNDAY) for the first day of the current 1180ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * month. 1190ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette */ 1200ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private int mDayOfWeekStart; 121bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1220ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** The day of month for the first (inclusive) enabled day. */ 123bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mEnabledDayStart = 1; 124bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1250ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** The day of month for the last (inclusive) enabled day. */ 126bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mEnabledDayEnd = 31; 127bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1280ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** Optional listener for handling day click actions. */ 129bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private OnDayClickListener mOnDayClickListener; 130bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 131c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private ColorStateList mDayTextColor; 132c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 13360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette private int mTouchedItem = -1; 13460b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 135bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public SimpleMonthView(Context context) { 136bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio this(context, null); 137bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 138bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 139bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public SimpleMonthView(Context context, AttributeSet attrs) { 140bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio this(context, attrs, R.attr.datePickerStyle); 141bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 142bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 14350eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette public SimpleMonthView(Context context, AttributeSet attrs, int defStyleAttr) { 14450eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette this(context, attrs, defStyleAttr, 0); 14550eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette } 146bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 14750eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette public SimpleMonthView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 14850eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette super(context, attrs, defStyleAttr, defStyleRes); 149bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 15050eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette final Resources res = context.getResources(); 151f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mDesiredMonthHeight = res.getDimensionPixelSize(R.dimen.date_picker_month_height); 152f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mDesiredDayOfWeekHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_of_week_height); 153f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mDesiredDayHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_height); 154f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mDesiredCellWidth = res.getDimensionPixelSize(R.dimen.date_picker_day_width); 15578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette mDesiredDaySelectorRadius = res.getDimensionPixelSize( 15678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette R.dimen.date_picker_day_selector_radius); 15760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 158bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Set up accessibility components. 159bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper = new MonthViewTouchHelper(this); 160bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setAccessibilityDelegate(mTouchHelper); 161bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 162bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 1630ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final Locale locale = res.getConfiguration().locale; 1640ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final String titleFormat = DateFormat.getBestDateTimePattern(locale, DEFAULT_TITLE_FORMAT); 1650ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mTitleFormatter = new SimpleDateFormat(titleFormat, locale); 1660ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayOfWeekFormatter = new SimpleDateFormat(DAY_OF_WEEK_FORMAT, locale); 1671ea4715cecf8d1a17a21f3d21ea4df56519e5ea6Chet Haase mDayFormatter = NumberFormat.getIntegerInstance(locale); 1680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 1690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette initPaints(res); 1700ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 1710ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 1720ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** 1730ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * Applies the specified text appearance resource to a paint, returning the 1740ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * text color if one is set in the text appearance. 1750ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * 1760ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param p the paint to modify 1770ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param resId the resource ID of the text appearance 1780ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @return the text color, if available 1790ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette */ 1800ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private ColorStateList applyTextAppearance(Paint p, int resId) { 1810ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final TypedArray ta = mContext.obtainStyledAttributes(null, 1820ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette R.styleable.TextAppearance, 0, resId); 1830ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 1840ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final String fontFamily = ta.getString(R.styleable.TextAppearance_fontFamily); 1850ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (fontFamily != null) { 1860ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette p.setTypeface(Typeface.create(fontFamily, 0)); 1870ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 1880ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 1890ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette p.setTextSize(ta.getDimensionPixelSize( 1900ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette R.styleable.TextAppearance_textSize, (int) p.getTextSize())); 1910ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 1920ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final ColorStateList textColor = ta.getColorStateList(R.styleable.TextAppearance_textColor); 1930ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (textColor != null) { 1940ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int enabledColor = textColor.getColorForState(ENABLED_STATE_SET, 0); 1950ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette p.setColor(enabledColor); 1960ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 1970ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 1980ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette ta.recycle(); 1990ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 2000ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return textColor; 2010ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 2020ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 20378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette public int getMonthHeight() { 20478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette return mMonthHeight; 20578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 20678bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 20778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette public int getCellWidth() { 20878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette return mCellWidth; 20978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette } 21078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette 2110ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette public void setMonthTextAppearance(int resId) { 21278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette applyTextAppearance(mMonthPaint, resId); 21360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 2140ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 2150ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 2160ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 2170ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette public void setDayOfWeekTextAppearance(int resId) { 2180ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette applyTextAppearance(mDayOfWeekPaint, resId); 2190ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 2200ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 2210ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 2220ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette public void setDayTextAppearance(int resId) { 2230ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final ColorStateList textColor = applyTextAppearance(mDayPaint, resId); 2240ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (textColor != null) { 2250ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayTextColor = textColor; 2260ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 2270ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 2280ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 2290ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 2300ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 2310ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette public CharSequence getTitle() { 2320ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (mTitle == null) { 2330ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mTitle = mTitleFormatter.format(mCalendar.getTime()); 2340ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 2350ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return mTitle; 236c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette } 237c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 238c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette /** 239c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette * Sets up the text and style properties for painting. 240c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette */ 2410ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private void initPaints(Resources res) { 2420ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final String monthTypeface = res.getString(R.string.date_picker_month_typeface); 2430ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final String dayOfWeekTypeface = res.getString(R.string.date_picker_day_of_week_typeface); 2440ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final String dayTypeface = res.getString(R.string.date_picker_day_typeface); 2450ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 2460ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int monthTextSize = res.getDimensionPixelSize( 2470ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette R.dimen.date_picker_month_text_size); 2480ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int dayOfWeekTextSize = res.getDimensionPixelSize( 2490ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette R.dimen.date_picker_day_of_week_text_size); 2500ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int dayTextSize = res.getDimensionPixelSize( 2510ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette R.dimen.date_picker_day_text_size); 2520ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 253c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthPaint.setAntiAlias(true); 2540ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mMonthPaint.setTextSize(monthTextSize); 2550ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mMonthPaint.setTypeface(Typeface.create(monthTypeface, 0)); 256c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthPaint.setTextAlign(Align.CENTER); 257c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthPaint.setStyle(Style.FILL); 258c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 259c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekPaint.setAntiAlias(true); 2600ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayOfWeekPaint.setTextSize(dayOfWeekTextSize); 2610ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayOfWeekPaint.setTypeface(Typeface.create(dayOfWeekTypeface, 0)); 262c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekPaint.setTextAlign(Align.CENTER); 263c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekPaint.setStyle(Style.FILL); 264c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 2650ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDaySelectorPaint.setAntiAlias(true); 2660ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDaySelectorPaint.setStyle(Style.FILL); 2670ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 2680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayHighlightPaint.setAntiAlias(true); 2690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayHighlightPaint.setStyle(Style.FILL); 270c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 271c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayPaint.setAntiAlias(true); 2720ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayPaint.setTextSize(dayTextSize); 2730ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayPaint.setTypeface(Typeface.create(dayTypeface, 0)); 274c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayPaint.setTextAlign(Align.CENTER); 275c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayPaint.setStyle(Style.FILL); 276bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 277bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 278c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette void setMonthTextColor(ColorStateList monthTextColor) { 279c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final int enabledColor = monthTextColor.getColorForState(ENABLED_STATE_SET, 0); 280c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthPaint.setColor(enabledColor); 281c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette invalidate(); 282c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette } 283bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 284c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette void setDayOfWeekTextColor(ColorStateList dayOfWeekTextColor) { 285c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final int enabledColor = dayOfWeekTextColor.getColorForState(ENABLED_STATE_SET, 0); 286c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekPaint.setColor(enabledColor); 287c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette invalidate(); 288c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette } 289bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 290c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette void setDayTextColor(ColorStateList dayTextColor) { 291c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayTextColor = dayTextColor; 292c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette invalidate(); 293c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette } 294bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 2950ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette void setDaySelectorColor(ColorStateList dayBackgroundColor) { 2965dc973cb03889c58988703b58aefbd2397fb02c3Alan Viverette final int activatedColor = dayBackgroundColor.getColorForState( 297c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0); 2980ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDaySelectorPaint.setColor(activatedColor); 299c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette invalidate(); 300bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 301bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 3020ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette void setDayHighlightColor(ColorStateList dayHighlightColor) { 3030ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int pressedColor = dayHighlightColor.getColorForState( 3040ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED), 0); 3050ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDayHighlightPaint.setColor(pressedColor); 3060ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 307bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 308bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 309bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void setOnDayClickListener(OnDayClickListener listener) { 310bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mOnDayClickListener = listener; 311bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 312bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 313bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 314bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public boolean dispatchHoverEvent(MotionEvent event) { 315bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // First right-of-refusal goes the touch exploration helper. 3160ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return mTouchHelper.dispatchHoverEvent(event) || super.dispatchHoverEvent(event); 317bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 318bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 319bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 320bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public boolean onTouchEvent(MotionEvent event) { 32160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int x = (int) (event.getX() + 0.5f); 32260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int y = (int) (event.getY() + 0.5f); 32360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 324ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette final int action = event.getAction(); 325ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette switch (action) { 3260ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette case MotionEvent.ACTION_DOWN: 3270ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette case MotionEvent.ACTION_MOVE: 32878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final int touchedItem = getDayAtLocation(x, y); 32960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette if (mTouchedItem != touchedItem) { 33060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette mTouchedItem = touchedItem; 3310ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 332bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 333ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette if (action == MotionEvent.ACTION_DOWN && touchedItem < 0) { 334ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette // Touch something that's not an item, reject event. 335ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette return false; 336ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } 337bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio break; 3380ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 3390ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette case MotionEvent.ACTION_UP: 34078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final int clickedDay = getDayAtLocation(x, y); 34178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette onDayClicked(clickedDay); 3420ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Fall through. 3430ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette case MotionEvent.ACTION_CANCEL: 3440ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Reset touched day on stream end. 34560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette mTouchedItem = -1; 3460ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 3470ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette break; 348bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 349bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 350bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 351bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 352bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 353bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onDraw(Canvas canvas) { 3540ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int paddingLeft = getPaddingLeft(); 3550ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int paddingTop = getPaddingTop(); 3560ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette canvas.translate(paddingLeft, paddingTop); 3570ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 3580ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette drawMonth(canvas); 3590ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette drawDaysOfWeek(canvas); 360bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio drawDays(canvas); 3610ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 3620ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette canvas.translate(-paddingLeft, -paddingTop); 3630ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 3640ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 3650ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private void drawMonth(Canvas canvas) { 3660ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final float x = mPaddedWidth / 2f; 3670ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 3680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Vertically centered within the month header height. 3690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final float lineHeight = mMonthPaint.ascent() + mMonthPaint.descent(); 3700ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final float y = (mMonthHeight - lineHeight) / 2f; 3710ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 3720ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette canvas.drawText(getTitle().toString(), x, y, mMonthPaint); 3730ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 3740ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 3750ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private void drawDaysOfWeek(Canvas canvas) { 37660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final TextPaint p = mDayOfWeekPaint; 37760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int headerHeight = mMonthHeight; 37860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int rowHeight = mDayOfWeekHeight; 379f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int colWidth = mCellWidth; 38060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 38160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette // Text is vertically centered within the day of week height. 38260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final float halfLineHeight = (p.ascent() + p.descent()) / 2f; 38360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int rowCenter = headerHeight + rowHeight / 2; 38460b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 38560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette for (int col = 0; col < DAYS_IN_WEEK; col++) { 38660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int colCenter = colWidth * col + colWidth / 2; 387ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette final int colCenterRtl; 388ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette if (isLayoutRtl()) { 389ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette colCenterRtl = mPaddedWidth - colCenter; 390ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } else { 391ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette colCenterRtl = colCenter; 392ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } 393ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette 39460b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int dayOfWeek = (col + mWeekStart) % DAYS_IN_WEEK; 39560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final String label = getDayOfWeekLabel(dayOfWeek); 396ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette canvas.drawText(label, colCenterRtl, rowCenter - halfLineHeight, p); 3970ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 3980ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 3990ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 40060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette private String getDayOfWeekLabel(int dayOfWeek) { 40160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette mDayOfWeekLabelCalendar.set(Calendar.DAY_OF_WEEK, dayOfWeek); 40260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette return mDayOfWeekFormatter.format(mDayOfWeekLabelCalendar.getTime()); 40360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette } 40460b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 4050ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** 4060ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * Draws the month days. 4070ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette */ 4080ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private void drawDays(Canvas canvas) { 40960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final TextPaint p = mDayPaint; 41060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int headerHeight = mMonthHeight + mDayOfWeekHeight; 41160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int rowHeight = mDayHeight; 412f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int colWidth = mCellWidth; 4130ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 41460b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette // Text is vertically centered within the row height. 41560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final float halfLineHeight = (p.ascent() + p.descent()) / 2f; 41660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette int rowCenter = headerHeight + rowHeight / 2; 4170ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 41860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette for (int day = 1, col = findDayOffset(); day <= mDaysInMonth; day++) { 41960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int colCenter = colWidth * col + colWidth / 2; 420ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette final int colCenterRtl; 421ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette if (isLayoutRtl()) { 422ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette colCenterRtl = mPaddedWidth - colCenter; 423ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } else { 424ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette colCenterRtl = colCenter; 425ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } 426ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette 4270ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette int stateMask = 0; 4280ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 4295c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette final boolean isDayEnabled = isDayEnabled(day); 4305c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (isDayEnabled) { 4310ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette stateMask |= StateSet.VIEW_STATE_ENABLED; 4320ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 4330ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 4340ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final boolean isDayActivated = mActivatedDay == day; 4350ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (isDayActivated) { 4360ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette stateMask |= StateSet.VIEW_STATE_ACTIVATED; 4370ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 4380ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Adjust the circle to be centered on the row. 439ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette canvas.drawCircle(colCenterRtl, rowCenter, mDaySelectorRadius, mDaySelectorPaint); 44060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette } else if (mTouchedItem == day) { 4410ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette stateMask |= StateSet.VIEW_STATE_PRESSED; 4420ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 4435c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (isDayEnabled) { 4445c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette // Adjust the circle to be centered on the row. 4455c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette canvas.drawCircle(colCenterRtl, rowCenter, 4465c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette mDaySelectorRadius, mDayHighlightPaint); 4475c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette } 4480ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 4490ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 4500ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final boolean isDayToday = mToday == day; 4510ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int dayTextColor; 4520ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (isDayToday && !isDayActivated) { 4530ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette dayTextColor = mDaySelectorPaint.getColor(); 4540ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } else { 4550ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int[] stateSet = StateSet.get(stateMask); 4560ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette dayTextColor = mDayTextColor.getColorForState(stateSet, 0); 4570ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 45860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette p.setColor(dayTextColor); 4590ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 4601ea4715cecf8d1a17a21f3d21ea4df56519e5ea6Chet Haase canvas.drawText(mDayFormatter.format(day), colCenterRtl, rowCenter - halfLineHeight, p); 4610ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 46260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette col++; 4630ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 46460b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette if (col == DAYS_IN_WEEK) { 46560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette col = 0; 46660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette rowCenter += rowHeight; 4670ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 4680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 469bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 470bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 4715c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette private boolean isDayEnabled(int day) { 4725c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette return day >= mEnabledDayStart && day <= mEnabledDayEnd; 4735c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette } 4745c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette 4755c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette private boolean isValidDayOfMonth(int day) { 4765c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette return day >= 1 && day <= mDaysInMonth; 4775c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette } 4785c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette 479518ff0de95e64116ecb07706fc564d4c19197ca7Alan Viverette private static boolean isValidDayOfWeek(int day) { 4805878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette return day >= Calendar.SUNDAY && day <= Calendar.SATURDAY; 4815878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette } 4825878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette 4835878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette private static boolean isValidMonth(int month) { 4845878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette return month >= Calendar.JANUARY && month <= Calendar.DECEMBER; 48575b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio } 48675b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio 487bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 4880ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * Sets the selected day. 489bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 4900ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param dayOfMonth the selected day of the month, or {@code -1} to clear 4910ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * the selection 4920ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette */ 4930ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette public void setSelectedDay(int dayOfMonth) { 4940ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mActivatedDay = dayOfMonth; 4950ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 4960ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Invalidate cached accessibility information. 4970ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mTouchHelper.invalidateRoot(); 4980ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 4990ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 5000ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 5010ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** 5020ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * Sets the first day of the week. 5030ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * 5040ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param weekStart which day the week should start on, valid values are 5050ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY} 5060ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette */ 5070ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette public void setFirstDayOfWeek(int weekStart) { 5080ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (isValidDayOfWeek(weekStart)) { 5090ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mWeekStart = weekStart; 5100ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } else { 5110ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mWeekStart = mCalendar.getFirstDayOfWeek(); 5120ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 5130ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 5140ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Invalidate cached accessibility information. 5150ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mTouchHelper.invalidateRoot(); 5160ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette invalidate(); 5170ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 5180ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 5190ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette /** 5200ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * Sets all the parameters for displaying this week. 5210ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * <p> 5220ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * Parameters have a default value and will only update if a new value is 5230ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * included, except for focus month, which will always default to no focus 5240ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * month if no value is passed in. The only required parameter is the week 5250ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * start. 5260ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * 5270ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param selectedDay the selected day of the month, or -1 for no selection 5280ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param month the month 5290ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param year the year 5300ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param weekStart which day the week should start on, valid values are 5310ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY} 5320ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param enabledDayStart the first enabled day 5330ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param enabledDayEnd the last enabled day 534bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 53575b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio void setMonthParams(int selectedDay, int month, int year, int weekStart, int enabledDayStart, 53675b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio int enabledDayEnd) { 537c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mActivatedDay = selectedDay; 538bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 5395878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette if (isValidMonth(month)) { 54075b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mMonth = month; 54175b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio } 54275b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mYear = year; 543bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 544bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mCalendar.set(Calendar.MONTH, mMonth); 545bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mCalendar.set(Calendar.YEAR, mYear); 546bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mCalendar.set(Calendar.DAY_OF_MONTH, 1); 547bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayOfWeekStart = mCalendar.get(Calendar.DAY_OF_WEEK); 548bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 549518ff0de95e64116ecb07706fc564d4c19197ca7Alan Viverette if (isValidDayOfWeek(weekStart)) { 55075b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mWeekStart = weekStart; 551bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } else { 552bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mWeekStart = mCalendar.getFirstDayOfWeek(); 553bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 554bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 5550ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Figure out what day today is. 5560ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final Calendar today = Calendar.getInstance(); 5570ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mToday = -1; 5580ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mDaysInMonth = getDaysInMonth(mMonth, mYear); 5590ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette for (int i = 0; i < mDaysInMonth; i++) { 560bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int day = i + 1; 561bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (sameDay(day, today)) { 562bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mToday = day; 563bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 564bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 5650ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 5665c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette mEnabledDayStart = MathUtils.constrain(enabledDayStart, 1, mDaysInMonth); 5675c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette mEnabledDayEnd = MathUtils.constrain(enabledDayEnd, mEnabledDayStart, mDaysInMonth); 5685c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette 5690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // Invalidate the old title. 5700ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mTitle = null; 571bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 572bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Invalidate cached accessibility information. 573bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.invalidateRoot(); 574bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 575bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 576bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static int getDaysInMonth(int month, int year) { 577bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (month) { 578bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.JANUARY: 579bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.MARCH: 580bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.MAY: 581bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.JULY: 582bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.AUGUST: 583bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.OCTOBER: 584bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.DECEMBER: 585bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return 31; 586bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.APRIL: 587bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.JUNE: 588bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.SEPTEMBER: 589bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.NOVEMBER: 590bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return 30; 591bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.FEBRUARY: 592bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return (year % 4 == 0) ? 29 : 28; 593bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 594bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new IllegalArgumentException("Invalid Month"); 595bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 596bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 597bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 5980ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private boolean sameDay(int day, Calendar today) { 5990ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return mYear == today.get(Calendar.YEAR) && mMonth == today.get(Calendar.MONTH) 6000ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette && day == today.get(Calendar.DAY_OF_MONTH); 601bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 602bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 603bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 604bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 605816aa142023c75cf427401c21831193998bdf233Alan Viverette final int preferredHeight = mDesiredDayHeight * MAX_WEEKS_IN_MONTH 606816aa142023c75cf427401c21831193998bdf233Alan Viverette + mDesiredDayOfWeekHeight + mDesiredMonthHeight 607816aa142023c75cf427401c21831193998bdf233Alan Viverette + getPaddingTop() + getPaddingBottom(); 608f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int preferredWidth = mDesiredCellWidth * DAYS_IN_WEEK 6090ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette + getPaddingStart() + getPaddingEnd(); 6100ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int resolvedWidth = resolveSize(preferredWidth, widthMeasureSpec); 6110ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int resolvedHeight = resolveSize(preferredHeight, heightMeasureSpec); 6120ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette setMeasuredDimension(resolvedWidth, resolvedHeight); 613bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 614bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 615bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 616ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 617ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette super.onRtlPropertiesChanged(layoutDirection); 618ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette 619ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette requestLayout(); 620ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } 621ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette 622ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette @Override 623f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 624f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette if (!changed) { 625f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette return; 626f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette } 627f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette 628f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette // Let's initialize a completely reasonable number of variables. 629f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int w = right - left; 630f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int h = bottom - top; 631f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddingLeft = getPaddingLeft(); 632f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddingTop = getPaddingTop(); 633f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddingRight = getPaddingRight(); 634f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddingBottom = getPaddingBottom(); 635f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddedRight = w - paddingRight; 636f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddedBottom = h - paddingBottom; 637f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddedWidth = paddedRight - paddingLeft; 638f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int paddedHeight = paddedBottom - paddingTop; 639f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette if (paddedWidth == mPaddedWidth || paddedHeight == mPaddedHeight) { 640f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette return; 641f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette } 642f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette 643f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mPaddedWidth = paddedWidth; 644f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mPaddedHeight = paddedHeight; 645f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette 646f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette // We may have been laid out smaller than our preferred size. If so, 647f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette // scale all dimensions to fit. 648f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int measuredPaddedHeight = getMeasuredHeight() - paddingTop - paddingBottom; 649f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final float scaleH = paddedHeight / (float) measuredPaddedHeight; 650f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int monthHeight = (int) (mDesiredMonthHeight * scaleH); 65160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int cellWidth = mPaddedWidth / DAYS_IN_WEEK; 652f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mMonthHeight = monthHeight; 653f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mDayOfWeekHeight = (int) (mDesiredDayOfWeekHeight * scaleH); 654f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mDayHeight = (int) (mDesiredDayHeight * scaleH); 655f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mCellWidth = cellWidth; 656f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette 657f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette // Compute the largest day selector radius that's still within the clip 658f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette // bounds and desired selector radius. 659f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int maxSelectorWidth = cellWidth / 2 + Math.min(paddingLeft, paddingRight); 660f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int maxSelectorHeight = mDayHeight / 2 + paddingBottom; 661f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette mDaySelectorRadius = Math.min(mDesiredDaySelectorRadius, 662f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette Math.min(maxSelectorWidth, maxSelectorHeight)); 66360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 664bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Invalidate cached accessibility information. 665bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.invalidateRoot(); 666bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 667bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 6680ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette private int findDayOffset() { 6690ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int offset = mDayOfWeekStart - mWeekStart; 6700ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (mDayOfWeekStart < mWeekStart) { 6710ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return offset + DAYS_IN_WEEK; 672bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 6730ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return offset; 674bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 675bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 676bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 67778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * Calculates the day of the month at the specified touch position. Returns 67878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * the day of the month or -1 if the position wasn't in a valid day. 6790ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * 6800ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param x the x position of the touch event 6810ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param y the y position of the touch event 68278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * @return the day of the month at (x, y), or -1 if the position wasn't in 68378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * a valid day 684bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 68578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette private int getDayAtLocation(int x, int y) { 68660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int paddedX = x - getPaddingLeft(); 6870ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (paddedX < 0 || paddedX >= mPaddedWidth) { 6880ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return -1; 6890ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 690c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 6910ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int headerHeight = mMonthHeight + mDayOfWeekHeight; 69260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int paddedY = y - getPaddingTop(); 6930ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (paddedY < headerHeight || paddedY >= mPaddedHeight) { 6940ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return -1; 6950ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 696c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 697ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette // Adjust for RTL after applying padding. 698ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette final int paddedXRtl; 699ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette if (isLayoutRtl()) { 700ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette paddedXRtl = mPaddedWidth - paddedX; 701ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } else { 702ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette paddedXRtl = paddedX; 703ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } 704ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette 7050ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int row = (paddedY - headerHeight) / mDayHeight; 706ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette final int col = (paddedXRtl * DAYS_IN_WEEK) / mPaddedWidth; 7070ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int index = col + row * DAYS_IN_WEEK; 7080ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int day = index + 1 - findDayOffset(); 7095c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (!isValidDayOfMonth(day)) { 7100ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return -1; 711bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 712bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 7130ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return day; 714bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 715bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 716bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 7170ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * Calculates the bounds of the specified day. 718bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 71978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * @param id the day of the month 7200ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param outBounds the rect to populate with bounds 721bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 72278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette private boolean getBoundsForDay(int id, Rect outBounds) { 7235c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (!isValidDayOfMonth(id)) { 7240ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return false; 725bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 726bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 72760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int index = id - 1 + findDayOffset(); 72860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 729ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette // Compute left edge, taking into account RTL. 7300ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int col = index % DAYS_IN_WEEK; 731f63757b7a6d06138860640f8e95326dc1ff47646Alan Viverette final int colWidth = mCellWidth; 732ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette final int left; 733ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette if (isLayoutRtl()) { 734ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette left = getWidth() - getPaddingRight() - (col + 1) * colWidth; 735ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } else { 736ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette left = getPaddingLeft() + col * colWidth; 737ddf655c49f4173aa55c9ba1a2622cf75cf5bc2f2Alan Viverette } 7380ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 73960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette // Compute top edge. 74060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int row = index / DAYS_IN_WEEK; 74160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int rowHeight = mDayHeight; 7420ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette final int headerHeight = mMonthHeight + mDayOfWeekHeight; 74360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final int top = getPaddingTop() + headerHeight + row * rowHeight; 7440ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 74560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette outBounds.set(left, top, left + colWidth, top + rowHeight); 746bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 74778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette return true; 74860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette } 74960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 75060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette /** 751bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Called when the user clicks on a day. Handles callbacks to the 752bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link OnDayClickListener} if one is set. 753bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 7540ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette * @param day the day that was clicked 755bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 75660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette private boolean onDayClicked(int day) { 7575c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (!isValidDayOfMonth(day) || !isDayEnabled(day)) { 75860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette return false; 75960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette } 76060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 761bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mOnDayClickListener != null) { 76260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette final Calendar date = Calendar.getInstance(); 763bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio date.set(mYear, mMonth, day); 764bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mOnDayClickListener.onDayClick(this, date); 765bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 766bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 767bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // This is a no-op if accessibility is turned off. 768bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.sendEventForVirtualView(day, AccessibilityEvent.TYPE_VIEW_CLICKED); 76960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette return true; 77060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette } 77160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 77260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette /** 773bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Provides a virtual view hierarchy for interfacing with an accessibility 774bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * service. 775bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 776bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private class MonthViewTouchHelper extends ExploreByTouchHelper { 777bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final String DATE_FORMAT = "dd MMMM yyyy"; 778bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 779bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final Rect mTempRect = new Rect(); 780bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final Calendar mTempCalendar = Calendar.getInstance(); 781bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 782bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public MonthViewTouchHelper(View host) { 783bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio super(host); 784bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 785bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 786bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 787bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected int getVirtualViewAt(float x, float y) { 78878bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final int day = getDayAtLocation((int) (x + 0.5f), (int) (y + 0.5f)); 7895c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (day != -1) { 790bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return day; 791bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 792bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return ExploreByTouchHelper.INVALID_ID; 793bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 794bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 795bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 796ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette protected void getVisibleVirtualViews(IntArray virtualViewIds) { 7970ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette for (int day = 1; day <= mDaysInMonth; day++) { 798bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio virtualViewIds.add(day); 799bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 800bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 801bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 802bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 803bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) { 80478bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette event.setContentDescription(getDayDescription(virtualViewId)); 805bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 806bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 807bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 808bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfo node) { 80978bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette final boolean hasBounds = getBoundsForDay(virtualViewId, mTempRect); 8100ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette 8110ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette if (!hasBounds) { 8120ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette // The day is invalid, kill the node. 8130ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette mTempRect.setEmpty(); 8140ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette node.setContentDescription(""); 8150ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette node.setBoundsInParent(mTempRect); 8160ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette node.setVisibleToUser(false); 8170ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette return; 8180ef59ac0e57e9b99d174d4a53f7d9639357743acAlan Viverette } 819bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 82078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette node.setText(getDayText(virtualViewId)); 82178bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette node.setContentDescription(getDayDescription(virtualViewId)); 822bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setBoundsInParent(mTempRect); 8235c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette 8245c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette final boolean isDayEnabled = isDayEnabled(virtualViewId); 8255c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (isDayEnabled) { 8265c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette node.addAction(AccessibilityAction.ACTION_CLICK); 8275c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette } 8285c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette 8295c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette node.setEnabled(isDayEnabled); 830bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 831c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette if (virtualViewId == mActivatedDay) { 83260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette // TODO: This should use activated once that's supported. 83360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette node.setChecked(true); 834bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 835bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 836bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 837bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 838bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 839bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected boolean onPerformActionForVirtualView(int virtualViewId, int action, 840bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio Bundle arguments) { 841bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (action) { 842bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case AccessibilityNodeInfo.ACTION_CLICK: 84378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette return onDayClicked(virtualViewId); 844bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 845bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 846bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 847bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 848bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 849bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 85060b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette * Generates a description for a given virtual view. 851bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 85278bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * @param id the day to generate a description for 85360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette * @return a description of the virtual view 854bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 85578bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette private CharSequence getDayDescription(int id) { 8565c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (isValidDayOfMonth(id)) { 85760b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette mTempCalendar.set(mYear, mMonth, id); 85860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette return DateFormat.format(DATE_FORMAT, mTempCalendar.getTimeInMillis()); 85960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette } 860bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 86160b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette return ""; 86260b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette } 86360b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette 86460b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette /** 86560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette * Generates displayed text for a given virtual view. 86660b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette * 86778bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette * @param id the day to generate text for 86860b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette * @return the visible text of the virtual view 86960b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette */ 87078bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette private CharSequence getDayText(int id) { 8715c33949d0272c4dfc313cf8b56d28597e2ec2c62Alan Viverette if (isValidDayOfMonth(id)) { 8721ea4715cecf8d1a17a21f3d21ea4df56519e5ea6Chet Haase return mDayFormatter.format(id); 873bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 874bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 87560b674e07bf7346a673abd4a5f40bddeca16e7ffAlan Viverette return null; 876bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 877bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 878bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 879bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 880bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Handles callbacks when the user clicks on a time object. 881bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 882bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public interface OnDayClickListener { 88378bf1d329a4c0210394f846be1fd1390314aefc0Alan Viverette void onDayClick(SimpleMonthView view, Calendar day); 884bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 885bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio} 886