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