SimpleMonthView.java revision c5b95c20b6fd3f4e63147efb22dd19c657b17001
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; 21fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viveretteimport android.content.res.Configuration; 22bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.res.Resources; 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; 30bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.text.format.DateFormat; 31bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.text.format.DateUtils; 32bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.text.format.Time; 33bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.util.AttributeSet; 34ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viveretteimport android.util.IntArray; 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; 40bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 41bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport com.android.internal.R; 42bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport com.android.internal.widget.ExploreByTouchHelper; 43bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 44fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viveretteimport java.text.SimpleDateFormat; 45bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.Calendar; 46bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.Formatter; 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 { 54c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private static final int MIN_ROW_HEIGHT = 10; 55bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 56bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final int DEFAULT_SELECTED_DAY = -1; 57bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final int DEFAULT_WEEK_START = Calendar.SUNDAY; 58bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final int DEFAULT_NUM_DAYS = 7; 59bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final int DEFAULT_NUM_ROWS = 6; 60bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final int MAX_NUM_ROWS = 6; 61bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 62518ff0de95e64116ecb07706fc564d4c19197ca7Alan Viverette private static final int DAY_SEPARATOR_WIDTH = 1; 63bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 6450eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette private final Formatter mFormatter; 6550eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette private final StringBuilder mStringBuilder; 6650eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette 67c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private final int mMonthTextSize; 68c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private final int mDayOfWeekTextSize; 69c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private final int mDayTextSize; 70c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 71c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private final int mMonthHeaderHeight; 72c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 73c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private final Paint mMonthPaint = new Paint(); 74c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private final Paint mDayOfWeekPaint = new Paint(); 75c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private final Paint mDayPaint = new Paint(); 76c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private final Paint mDayBackgroundPaint = new Paint(); 77bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 78fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette /** Single-letter (when available) formatter for the day of week label. */ 79fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette private SimpleDateFormat mDayFormatter = new SimpleDateFormat("EEEEE", Locale.getDefault()); 80fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette 81bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // affects the padding on the sides of this view 82bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mPadding = 0; 83bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 84bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private String mDayOfWeekTypeface; 85c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private String mMonthTypeface; 86bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 87bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mMonth; 88bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mYear; 89bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 90bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Quick reference to the width of this view, matches parent 91bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mWidth; 92bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 93bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // The height this view should draw at in pixels, set by height param 94c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private final int mRowHeight; 95bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 96bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // If this view contains the today 97bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean mHasToday = false; 98bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 99bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Which day is selected [0-6] or -1 if no day is selected 100c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private int mActivatedDay = -1; 101bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 102bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Which day is today [0-6] or -1 if no day is today 103bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mToday = DEFAULT_SELECTED_DAY; 104bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 105bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Which day of the week to start on [0-6] 106bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mWeekStart = DEFAULT_WEEK_START; 107bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 108bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // How many days to display 109bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mNumDays = DEFAULT_NUM_DAYS; 110bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 111bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // The number of days + a spot for week number if it is displayed 112bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mNumCells = mNumDays; 113bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 114bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mDayOfWeekStart = 0; 115bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 116bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // First enabled day 117bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mEnabledDayStart = 1; 118bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 119bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Last enabled day 120bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mEnabledDayEnd = 31; 121bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 122bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final Calendar mCalendar = Calendar.getInstance(); 123bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final Calendar mDayLabelCalendar = Calendar.getInstance(); 124bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 125bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final MonthViewTouchHelper mTouchHelper; 126bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 127bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mNumRows = DEFAULT_NUM_ROWS; 128bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 129bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Optional listener for handling day click actions 130bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private OnDayClickListener mOnDayClickListener; 131bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 132bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Whether to prevent setting the accessibility delegate 133bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean mLockAccessibilityDelegate; 134bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 135bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mNormalTextColor; 136bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mDisabledTextColor; 137bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mSelectedDayColor; 138bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 139c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private ColorStateList mDayTextColor; 140c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 141bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public SimpleMonthView(Context context) { 142bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio this(context, null); 143bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 144bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 145bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public SimpleMonthView(Context context, AttributeSet attrs) { 146bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio this(context, attrs, R.attr.datePickerStyle); 147bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 148bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 14950eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette public SimpleMonthView(Context context, AttributeSet attrs, int defStyleAttr) { 15050eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette this(context, attrs, defStyleAttr, 0); 15150eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette } 152bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 15350eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette public SimpleMonthView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 15450eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette super(context, attrs, defStyleAttr, defStyleRes); 155bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 15650eb025c2fea7e364e0be951ce8ba6ca605f901aAlan Viverette final Resources res = context.getResources(); 157bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayOfWeekTypeface = res.getString(R.string.day_of_week_label_typeface); 158c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthTypeface = res.getString(R.string.sans_serif); 159bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 160bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mStringBuilder = new StringBuilder(50); 161bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mFormatter = new Formatter(mStringBuilder, Locale.getDefault()); 162bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 163c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayTextSize = res.getDimensionPixelSize(R.dimen.datepicker_day_number_size); 164c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthTextSize = res.getDimensionPixelSize(R.dimen.datepicker_month_label_size); 165c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekTextSize = res.getDimensionPixelSize( 166bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio R.dimen.datepicker_month_day_label_text_size); 167c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthHeaderHeight = res.getDimensionPixelOffset( 168bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio R.dimen.datepicker_month_list_item_header_height); 169bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 170c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mRowHeight = Math.max(MIN_ROW_HEIGHT, 171c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette (res.getDimensionPixelOffset(R.dimen.datepicker_view_animator_height) 172c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette - mMonthHeaderHeight) / MAX_NUM_ROWS); 173bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 174bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Set up accessibility components. 175bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper = new MonthViewTouchHelper(this); 176bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setAccessibilityDelegate(mTouchHelper); 177bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 178bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mLockAccessibilityDelegate = true; 179bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 180c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette initPaints(); 181c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette } 182c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 183c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette /** 184c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette * Sets up the text and style properties for painting. 185c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette */ 186c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette private void initPaints() { 187c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthPaint.setAntiAlias(true); 188c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthPaint.setTextSize(mMonthTextSize); 189c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthPaint.setTypeface(Typeface.create(mMonthTypeface, Typeface.BOLD)); 190c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthPaint.setTextAlign(Align.CENTER); 191c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthPaint.setStyle(Style.FILL); 192c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 193c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekPaint.setAntiAlias(true); 194c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekPaint.setTextSize(mDayOfWeekTextSize); 195c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekPaint.setTypeface(Typeface.create(mDayOfWeekTypeface, Typeface.BOLD)); 196c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekPaint.setTextAlign(Align.CENTER); 197c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekPaint.setStyle(Style.FILL); 198c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 199c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayBackgroundPaint.setAntiAlias(true); 200c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayBackgroundPaint.setStyle(Style.FILL); 201c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 202c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayPaint.setAntiAlias(true); 203c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayPaint.setTextSize(mDayTextSize); 204c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayPaint.setTextAlign(Align.CENTER); 205c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayPaint.setStyle(Style.FILL); 206bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 207bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 208fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette @Override 209fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette protected void onConfigurationChanged(Configuration newConfig) { 210fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette super.onConfigurationChanged(newConfig); 211fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette 212fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette mDayFormatter = new SimpleDateFormat("EEEEE", newConfig.locale); 213fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette } 214fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette 215c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette void setMonthTextColor(ColorStateList monthTextColor) { 216c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final int enabledColor = monthTextColor.getColorForState(ENABLED_STATE_SET, 0); 217c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mMonthPaint.setColor(enabledColor); 218c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette invalidate(); 219c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette } 220bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 221c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette void setDayOfWeekTextColor(ColorStateList dayOfWeekTextColor) { 222c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final int enabledColor = dayOfWeekTextColor.getColorForState(ENABLED_STATE_SET, 0); 223c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayOfWeekPaint.setColor(enabledColor); 224c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette invalidate(); 225c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette } 226bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 227c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette void setDayTextColor(ColorStateList dayTextColor) { 228c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayTextColor = dayTextColor; 229c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette invalidate(); 230c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette } 231bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 232c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette void setDayBackgroundColor(ColorStateList daySelectorColor) { 233c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final int activatedColor = daySelectorColor.getColorForState( 234c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0); 235c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayBackgroundPaint.setColor(activatedColor); 236c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette invalidate(); 237bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 238bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 239bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 240bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void setAccessibilityDelegate(AccessibilityDelegate delegate) { 241bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Workaround for a JB MR1 issue where accessibility delegates on 242bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // top-level ListView items are overwritten. 243bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (!mLockAccessibilityDelegate) { 244bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio super.setAccessibilityDelegate(delegate); 245bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 246bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 247bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 248bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void setOnDayClickListener(OnDayClickListener listener) { 249bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mOnDayClickListener = listener; 250bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 251bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 252bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 253bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public boolean dispatchHoverEvent(MotionEvent event) { 254bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // First right-of-refusal goes the touch exploration helper. 255bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mTouchHelper.dispatchHoverEvent(event)) { 256bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 257bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 258bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return super.dispatchHoverEvent(event); 259bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 260bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 261bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 262bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public boolean onTouchEvent(MotionEvent event) { 263bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (event.getAction()) { 264bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case MotionEvent.ACTION_UP: 265bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int day = getDayFromLocation(event.getX(), event.getY()); 266bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (day >= 0) { 267bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio onDayClick(day); 268bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 269bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio break; 270bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 271bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 272bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 273bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 274bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 275bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onDraw(Canvas canvas) { 276bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio drawMonthTitle(canvas); 277bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio drawWeekDayLabels(canvas); 278bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio drawDays(canvas); 279bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 280bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 281518ff0de95e64116ecb07706fc564d4c19197ca7Alan Viverette private static boolean isValidDayOfWeek(int day) { 2825878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette return day >= Calendar.SUNDAY && day <= Calendar.SATURDAY; 2835878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette } 2845878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette 2855878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette private static boolean isValidMonth(int month) { 2865878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette return month >= Calendar.JANUARY && month <= Calendar.DECEMBER; 28775b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio } 28875b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio 289bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 29075b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * Sets all the parameters for displaying this week. Parameters have a default value and 29175b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * will only update if a new value is included, except for focus month, which will always 29275b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * default to no focus month if no value is passed in. The only required parameter is the 29375b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * week start. 294bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 295518ff0de95e64116ecb07706fc564d4c19197ca7Alan Viverette * @param selectedDay the selected day of the month, or -1 for no selection. 29675b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * @param month the month. 29775b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * @param year the year. 2985878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette * @param weekStart which day the week should start on. {@link Calendar#SUNDAY} through 2995878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette * {@link Calendar#SATURDAY}. 30075b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * @param enabledDayStart the first enabled day. 30175b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * @param enabledDayEnd the last enabled day. 302bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 30375b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio void setMonthParams(int selectedDay, int month, int year, int weekStart, int enabledDayStart, 30475b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio int enabledDayEnd) { 305c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mActivatedDay = selectedDay; 306bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 3075878076456a2eb510c03b6160a0cfb99a54e0cfdAlan Viverette if (isValidMonth(month)) { 30875b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mMonth = month; 30975b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio } 31075b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mYear = year; 311bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 312bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Figure out what day today is 313bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final Time today = new Time(Time.getCurrentTimezone()); 314bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio today.setToNow(); 315bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mHasToday = false; 316bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mToday = -1; 317bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 318bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mCalendar.set(Calendar.MONTH, mMonth); 319bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mCalendar.set(Calendar.YEAR, mYear); 320bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mCalendar.set(Calendar.DAY_OF_MONTH, 1); 321bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayOfWeekStart = mCalendar.get(Calendar.DAY_OF_WEEK); 322bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 323518ff0de95e64116ecb07706fc564d4c19197ca7Alan Viverette if (isValidDayOfWeek(weekStart)) { 32475b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mWeekStart = weekStart; 325bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } else { 326bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mWeekStart = mCalendar.getFirstDayOfWeek(); 327bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 328bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 32975b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio if (enabledDayStart > 0 && enabledDayEnd < 32) { 33075b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mEnabledDayStart = enabledDayStart; 331bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 33275b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio if (enabledDayEnd > 0 && enabledDayEnd < 32 && enabledDayEnd >= enabledDayStart) { 33375b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mEnabledDayEnd = enabledDayEnd; 334bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 335bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 336bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mNumCells = getDaysInMonth(mMonth, mYear); 337bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio for (int i = 0; i < mNumCells; i++) { 338bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int day = i + 1; 339bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (sameDay(day, today)) { 340bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mHasToday = true; 341bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mToday = day; 342bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 343bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 344bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mNumRows = calculateNumRows(); 345bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 346bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Invalidate cached accessibility information. 347bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.invalidateRoot(); 348bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 349bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 350bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static int getDaysInMonth(int month, int year) { 351bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (month) { 352bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.JANUARY: 353bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.MARCH: 354bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.MAY: 355bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.JULY: 356bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.AUGUST: 357bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.OCTOBER: 358bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.DECEMBER: 359bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return 31; 360bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.APRIL: 361bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.JUNE: 362bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.SEPTEMBER: 363bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.NOVEMBER: 364bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return 30; 365bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.FEBRUARY: 366bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return (year % 4 == 0) ? 29 : 28; 367bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 368bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new IllegalArgumentException("Invalid Month"); 369bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 370bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 371bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 372bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void reuse() { 373bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mNumRows = DEFAULT_NUM_ROWS; 374bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio requestLayout(); 375bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 376bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 377bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int calculateNumRows() { 378bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int offset = findDayOffset(); 379bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int dividend = (offset + mNumCells) / mNumDays; 380bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int remainder = (offset + mNumCells) % mNumDays; 381bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return (dividend + (remainder > 0 ? 1 : 0)); 382bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 383bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 384bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean sameDay(int day, Time today) { 385bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return mYear == today.year && 386bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonth == today.month && 387bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio day == today.monthDay; 388bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 389bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 390bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 391bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 392bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mRowHeight * mNumRows 393c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette + mMonthHeaderHeight); 394bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 395bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 396bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 397bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onSizeChanged(int w, int h, int oldw, int oldh) { 398bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mWidth = w; 399bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 400bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Invalidate cached accessibility information. 401bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.invalidateRoot(); 402bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 403bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 404bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private String getMonthAndYearString() { 405bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR 406bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio | DateUtils.FORMAT_NO_MONTH_DAY; 407bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mStringBuilder.setLength(0); 408bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio long millis = mCalendar.getTimeInMillis(); 409bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return DateUtils.formatDateRange(getContext(), mFormatter, millis, millis, flags, 410bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio Time.getCurrentTimezone()).toString(); 411bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 412bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 413bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private void drawMonthTitle(Canvas canvas) { 414518ff0de95e64116ecb07706fc564d4c19197ca7Alan Viverette final float x = (mWidth + 2 * mPadding) / 2f; 415c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final float y = (mMonthHeaderHeight - mDayOfWeekTextSize) / 2f; 416c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette canvas.drawText(getMonthAndYearString(), x, y, mMonthPaint); 417bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 418bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 419bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private void drawWeekDayLabels(Canvas canvas) { 420c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final int y = mMonthHeaderHeight - (mDayOfWeekTextSize / 2); 421fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette final int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2); 422bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 423bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio for (int i = 0; i < mNumDays; i++) { 424fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette final int calendarDay = (i + mWeekStart) % mNumDays; 425bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay); 426fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette 427fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette final String dayLabel = mDayFormatter.format(mDayLabelCalendar.getTime()); 428fd2dd208d9b0957657589b26c14c48b8e2b7f387Alan Viverette final int x = (2 * i + 1) * dayWidthHalf + mPadding; 429c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette canvas.drawText(dayLabel, x, y, mDayOfWeekPaint); 430bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 431bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 432bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 433bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 434bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Draws the month days. 435bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 436bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private void drawDays(Canvas canvas) { 437c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2); 438c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette int y = (((mRowHeight + mDayTextSize) / 2) - DAY_SEPARATOR_WIDTH) 439c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette + mMonthHeaderHeight; 440bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int j = findDayOffset(); 441c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 442bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio for (int day = 1; day <= mNumCells; day++) { 443c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final int x = (2 * j + 1) * dayWidthHalf + mPadding; 444c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette int stateMask = 0; 445c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 446c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette if (day >= mEnabledDayStart && day <= mEnabledDayEnd) { 447c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette stateMask |= StateSet.VIEW_STATE_ENABLED; 448bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 449bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 450c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette if (mActivatedDay == day) { 451c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette stateMask |= StateSet.VIEW_STATE_ACTIVATED; 452c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 453c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette canvas.drawCircle(x, y - (mDayTextSize / 3), mRowHeight / 2, 454c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayBackgroundPaint); 455bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 456c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 457c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final int[] stateSet = StateSet.get(stateMask); 458c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final int dayTextColor = mDayTextColor.getColorForState(stateSet, 0); 459c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayPaint.setColor(dayTextColor); 460c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 461c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final boolean isDayToday = mHasToday && mToday == day; 462c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette mDayPaint.setFakeBoldText(isDayToday); 463c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 464c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette canvas.drawText(String.format("%d", day), x, y, mDayPaint); 465c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 466bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio j++; 467c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette 468bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (j == mNumDays) { 469bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio j = 0; 470bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio y += mRowHeight; 471bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 472bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 473bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 474bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 475bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int findDayOffset() { 476bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return (mDayOfWeekStart < mWeekStart ? (mDayOfWeekStart + mNumDays) : mDayOfWeekStart) 477bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio - mWeekStart; 478bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 479bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 480bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 481bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Calculates the day that the given x position is in, accounting for week 482bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * number. Returns the day or -1 if the position wasn't in a day. 483bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 484bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param x The x position of the touch event 485bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return The day number, or -1 if the position wasn't in a day 486bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 487bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int getDayFromLocation(float x, float y) { 488bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int dayStart = mPadding; 489bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (x < dayStart || x > mWidth - mPadding) { 490bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return -1; 491bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 492bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Selection is (x - start) / (pixels/day) == (x -s) * day / pixels 493c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette int row = (int) (y - mMonthHeaderHeight) / mRowHeight; 494bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int column = (int) ((x - dayStart) * mNumDays / (mWidth - dayStart - mPadding)); 495bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 496bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int day = column - findDayOffset() + 1; 497bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio day += row * mNumDays; 498bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (day < 1 || day > mNumCells) { 499bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return -1; 500bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 501bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return day; 502bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 503bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 504bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 505bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Called when the user clicks on a day. Handles callbacks to the 506bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link OnDayClickListener} if one is set. 507bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 508bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param day The day that was clicked 509bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 510bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private void onDayClick(int day) { 511bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mOnDayClickListener != null) { 512bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio Calendar date = Calendar.getInstance(); 513bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio date.set(mYear, mMonth, day); 514bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mOnDayClickListener.onDayClick(this, date); 515bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 516bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 517bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // This is a no-op if accessibility is turned off. 518bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.sendEventForVirtualView(day, AccessibilityEvent.TYPE_VIEW_CLICKED); 519bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 520bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 521bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 522bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return The date that has accessibility focus, or {@code null} if no date 523bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * has focus 524bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 525bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio Calendar getAccessibilityFocus() { 526bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int day = mTouchHelper.getFocusedVirtualView(); 527bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio Calendar date = null; 528bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (day >= 0) { 529bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio date = Calendar.getInstance(); 530bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio date.set(mYear, mMonth, day); 531bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 532bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return date; 533bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 534bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 535bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 536bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Clears accessibility focus within the view. No-op if the view does not 537bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * contain accessibility focus. 538bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 539bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void clearAccessibilityFocus() { 540bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.clearFocusedVirtualView(); 541bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 542bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 543bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 544bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Attempts to restore accessibility focus to the specified date. 545bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 546bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param day The date which should receive focus 547bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return {@code false} if the date is not valid for this month view, or 548bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@code true} if the date received focus 549bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 550bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio boolean restoreAccessibilityFocus(Calendar day) { 551bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if ((day.get(Calendar.YEAR) != mYear) || (day.get(Calendar.MONTH) != mMonth) || 552bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio (day.get(Calendar.DAY_OF_MONTH) > mNumCells)) { 553bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 554bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 555bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.setFocusedVirtualView(day.get(Calendar.DAY_OF_MONTH)); 556bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 557bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 558bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 559bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 560bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Provides a virtual view hierarchy for interfacing with an accessibility 561bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * service. 562bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 563bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private class MonthViewTouchHelper extends ExploreByTouchHelper { 564bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final String DATE_FORMAT = "dd MMMM yyyy"; 565bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 566bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final Rect mTempRect = new Rect(); 567bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final Calendar mTempCalendar = Calendar.getInstance(); 568bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 569bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public MonthViewTouchHelper(View host) { 570bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio super(host); 571bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 572bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 573bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void setFocusedVirtualView(int virtualViewId) { 574bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio getAccessibilityNodeProvider(SimpleMonthView.this).performAction( 575bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio virtualViewId, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); 576bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 577bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 578bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void clearFocusedVirtualView() { 579bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int focusedVirtualView = getFocusedVirtualView(); 580bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (focusedVirtualView != ExploreByTouchHelper.INVALID_ID) { 581bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio getAccessibilityNodeProvider(SimpleMonthView.this).performAction( 582bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio focusedVirtualView, 583bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, 584bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio null); 585bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 586bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 587bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 588bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 589bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected int getVirtualViewAt(float x, float y) { 590bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int day = getDayFromLocation(x, y); 591bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (day >= 0) { 592bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return day; 593bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 594bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return ExploreByTouchHelper.INVALID_ID; 595bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 596bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 597bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 598ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette protected void getVisibleVirtualViews(IntArray virtualViewIds) { 599bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio for (int day = 1; day <= mNumCells; day++) { 600bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio virtualViewIds.add(day); 601bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 602bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 603bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 604bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 605bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) { 606bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio event.setContentDescription(getItemDescription(virtualViewId)); 607bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 608bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 609bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 610bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfo node) { 611bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio getItemBounds(virtualViewId, mTempRect); 612bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 613bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setContentDescription(getItemDescription(virtualViewId)); 614bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setBoundsInParent(mTempRect); 615bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.addAction(AccessibilityNodeInfo.ACTION_CLICK); 616bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 617c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette if (virtualViewId == mActivatedDay) { 618bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setSelected(true); 619bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 620bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 621bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 622bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 623bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 624bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected boolean onPerformActionForVirtualView(int virtualViewId, int action, 625bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio Bundle arguments) { 626bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (action) { 627bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case AccessibilityNodeInfo.ACTION_CLICK: 628bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio onDayClick(virtualViewId); 629bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 630bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 631bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 632bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 633bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 634bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 635bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 636bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Calculates the bounding rectangle of a given time object. 637bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 638bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param day The day to calculate bounds for 639bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param rect The rectangle in which to store the bounds 640bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 641bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private void getItemBounds(int day, Rect rect) { 642bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int offsetX = mPadding; 643c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette final int offsetY = mMonthHeaderHeight; 644bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int cellHeight = mRowHeight; 645bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int cellWidth = ((mWidth - (2 * mPadding)) / mNumDays); 646bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int index = ((day - 1) + findDayOffset()); 647bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int row = (index / mNumDays); 648bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int column = (index % mNumDays); 649bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int x = (offsetX + (column * cellWidth)); 650bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int y = (offsetY + (row * cellHeight)); 651bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 652bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio rect.set(x, y, (x + cellWidth), (y + cellHeight)); 653bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 654bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 655bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 656bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Generates a description for a given time object. Since this 657bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * description will be spoken, the components are ordered by descending 658bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * specificity as DAY MONTH YEAR. 659bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 660bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param day The day to generate a description for 661bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return A description of the time object 662bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 663bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private CharSequence getItemDescription(int day) { 664bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTempCalendar.set(mYear, mMonth, day); 665bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final CharSequence date = DateFormat.format(DATE_FORMAT, 666bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTempCalendar.getTimeInMillis()); 667bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 668c5b95c20b6fd3f4e63147efb22dd19c657b17001Alan Viverette if (day == mActivatedDay) { 669bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return getContext().getString(R.string.item_is_selected, date); 670bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 671bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 672bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return date; 673bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 674bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 675bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 676bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 677bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Handles callbacks when the user clicks on a time object. 678bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 679bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public interface OnDayClickListener { 680bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void onDayClick(SimpleMonthView view, Calendar day); 681bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 682bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio} 683