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