SimpleMonthView.java revision 75b121553f9c7498581a4b10d932f1c499feef25
1bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio/* 2bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Copyright (C) 2014 The Android Open Source Project 3bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 4bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Licensed under the Apache License, Version 2.0 (the "License"); 5bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * you may not use this file except in compliance with the License. 6bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * You may obtain a copy of the License at 7bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 8bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * http://www.apache.org/licenses/LICENSE-2.0 9bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 10bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Unless required by applicable law or agreed to in writing, software 11bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * distributed under the License is distributed on an "AS IS" BASIS, 12bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * See the License for the specific language governing permissions and 14bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * limitations under the License. 15bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 16bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 17bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Megliopackage android.widget; 18bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 19bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.Context; 20bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.res.ColorStateList; 21bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.res.Resources; 22bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.graphics.Canvas; 23bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.graphics.Paint; 24bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.graphics.Paint.Align; 25bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.graphics.Paint.Style; 26bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.graphics.Rect; 27bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.graphics.Typeface; 28bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.os.Bundle; 29bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.text.format.DateFormat; 30bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.text.format.DateUtils; 31bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.text.format.Time; 32bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.util.AttributeSet; 33bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.MotionEvent; 34bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.View; 35bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityEvent; 36bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityNodeInfo; 37bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 38bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport com.android.internal.R; 39bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport com.android.internal.widget.ExploreByTouchHelper; 40bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 41bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.security.InvalidParameterException; 42bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.Calendar; 43bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.Formatter; 44bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.HashMap; 45bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.List; 46bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport java.util.Locale; 47bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 48bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio/** 49bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * A calendar-like view displaying a specified month and the appropriate selectable day numbers 50bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * within the specified month. 51bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 52bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioclass SimpleMonthView extends View { 53bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final String TAG = "SimpleMonthView"; 54bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 55bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static int DEFAULT_HEIGHT = 32; 56bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static 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 66bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static int DAY_SEPARATOR_WIDTH = 1; 67bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 68bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mMiniDayNumberTextSize; 69bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mMonthLabelTextSize; 70bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mMonthDayLabelTextSize; 71bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mMonthHeaderSize; 72bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mDaySelectedCircleSize; 73bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 74bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // used for scaling to the device density 75bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static float mScale = 0; 76bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 77bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // affects the padding on the sides of this view 78bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mPadding = 0; 79bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 80bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private String mDayOfWeekTypeface; 81bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private String mMonthTitleTypeface; 82bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 83bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private Paint mDayNumberPaint; 84bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private Paint mDayNumberDisabledPaint; 85bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private Paint mDayNumberSelectedPaint; 86bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 87bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private Paint mMonthTitlePaint; 88bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private Paint mMonthDayLabelPaint; 89bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 90bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final Formatter mFormatter; 91bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final StringBuilder mStringBuilder; 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 153bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public SimpleMonthView(Context context, AttributeSet attrs, int defStyle) { 154bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio super(context, attrs); 155bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 156bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final Resources res = context.getResources(); 157bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 158bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayOfWeekTypeface = res.getString(R.string.day_of_week_label_typeface); 159bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthTitleTypeface = res.getString(R.string.sans_serif); 160bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 161bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mStringBuilder = new StringBuilder(50); 162bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mFormatter = new Formatter(mStringBuilder, Locale.getDefault()); 163bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 164bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMiniDayNumberTextSize = res.getDimensionPixelSize(R.dimen.datepicker_day_number_size); 165bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthLabelTextSize = res.getDimensionPixelSize(R.dimen.datepicker_month_label_size); 166bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthDayLabelTextSize = res.getDimensionPixelSize( 167bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio R.dimen.datepicker_month_day_label_text_size); 168bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthHeaderSize = res.getDimensionPixelOffset( 169bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio R.dimen.datepicker_month_list_item_header_height); 170bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDaySelectedCircleSize = res.getDimensionPixelSize( 171bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio R.dimen.datepicker_day_number_select_circle_radius); 172bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 173bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mRowHeight = (res.getDimensionPixelOffset(R.dimen.datepicker_view_animator_height) 174bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio - mMonthHeaderSize) / MAX_NUM_ROWS; 175bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 176bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Set up accessibility components. 177bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper = new MonthViewTouchHelper(this); 178bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setAccessibilityDelegate(mTouchHelper); 179bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 180bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mLockAccessibilityDelegate = true; 181bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 182bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Sets up any standard paints that will be used 183bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio initView(); 184bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 185bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 186bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio void setTextColor(ColorStateList colors) { 187bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final Resources res = getContext().getResources(); 188bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 189bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mNormalTextColor = colors.getColorForState(ENABLED_STATE_SET, 190bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio res.getColor(R.color.datepicker_default_normal_text_color_holo_light)); 191bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthTitlePaint.setColor(mNormalTextColor); 192bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthDayLabelPaint.setColor(mNormalTextColor); 193bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 194bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDisabledTextColor = colors.getColorForState(EMPTY_STATE_SET, 195bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio res.getColor(R.color.datepicker_default_disabled_text_color_holo_light)); 196bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberDisabledPaint.setColor(mDisabledTextColor); 197bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 198bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mSelectedDayColor = colors.getColorForState(ENABLED_SELECTED_STATE_SET, 199bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio res.getColor(R.color.holo_blue_light)); 200bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberSelectedPaint.setColor(mSelectedDayColor); 201bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberSelectedPaint.setAlpha(SELECTED_CIRCLE_ALPHA); 202bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 203bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 204bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 205bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void setAccessibilityDelegate(AccessibilityDelegate delegate) { 206bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Workaround for a JB MR1 issue where accessibility delegates on 207bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // top-level ListView items are overwritten. 208bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (!mLockAccessibilityDelegate) { 209bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio super.setAccessibilityDelegate(delegate); 210bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 211bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 212bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 213bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void setOnDayClickListener(OnDayClickListener listener) { 214bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mOnDayClickListener = listener; 215bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 216bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 217bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 218bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public boolean dispatchHoverEvent(MotionEvent event) { 219bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // First right-of-refusal goes the touch exploration helper. 220bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mTouchHelper.dispatchHoverEvent(event)) { 221bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 222bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 223bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return super.dispatchHoverEvent(event); 224bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 225bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 226bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 227bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public boolean onTouchEvent(MotionEvent event) { 228bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (event.getAction()) { 229bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case MotionEvent.ACTION_UP: 230bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int day = getDayFromLocation(event.getX(), event.getY()); 231bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (day >= 0) { 232bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio onDayClick(day); 233bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 234bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio break; 235bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 236bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 237bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 238bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 239bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 240bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Sets up the text and style properties for painting. 241bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 242bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private void initView() { 243bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthTitlePaint = new Paint(); 244bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthTitlePaint.setAntiAlias(true); 245bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthTitlePaint.setColor(mNormalTextColor); 246bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthTitlePaint.setTextSize(mMonthLabelTextSize); 247bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthTitlePaint.setTypeface(Typeface.create(mMonthTitleTypeface, Typeface.BOLD)); 248bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthTitlePaint.setTextAlign(Align.CENTER); 249bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthTitlePaint.setStyle(Style.FILL); 250bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthTitlePaint.setFakeBoldText(true); 251bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 252bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthDayLabelPaint = new Paint(); 253bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthDayLabelPaint.setAntiAlias(true); 254bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthDayLabelPaint.setColor(mNormalTextColor); 255bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthDayLabelPaint.setTextSize(mMonthDayLabelTextSize); 256bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthDayLabelPaint.setTypeface(Typeface.create(mDayOfWeekTypeface, Typeface.NORMAL)); 257bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthDayLabelPaint.setTextAlign(Align.CENTER); 258bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthDayLabelPaint.setStyle(Style.FILL); 259bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthDayLabelPaint.setFakeBoldText(true); 260bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 261bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberSelectedPaint = new Paint(); 262bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberSelectedPaint.setAntiAlias(true); 263bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberSelectedPaint.setColor(mSelectedDayColor); 264bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberSelectedPaint.setAlpha(SELECTED_CIRCLE_ALPHA); 265bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberSelectedPaint.setTextAlign(Align.CENTER); 266bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberSelectedPaint.setStyle(Style.FILL); 267bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberSelectedPaint.setFakeBoldText(true); 268bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 269bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberPaint = new Paint(); 270bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberPaint.setAntiAlias(true); 271bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberPaint.setTextSize(mMiniDayNumberTextSize); 272bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberPaint.setTextAlign(Align.CENTER); 273bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberPaint.setStyle(Style.FILL); 274bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberPaint.setFakeBoldText(false); 275bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 276bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberDisabledPaint = new Paint(); 277bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberDisabledPaint.setAntiAlias(true); 278bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberDisabledPaint.setColor(mDisabledTextColor); 279bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberDisabledPaint.setTextSize(mMiniDayNumberTextSize); 280bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberDisabledPaint.setTextAlign(Align.CENTER); 281bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberDisabledPaint.setStyle(Style.FILL); 282bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberDisabledPaint.setFakeBoldText(false); 283bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 284bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 285bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 286bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onDraw(Canvas canvas) { 287bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio drawMonthTitle(canvas); 288bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio drawWeekDayLabels(canvas); 289bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio drawDays(canvas); 290bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 291bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 29275b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio private static boolean isValidDay(int day) { 29375b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio return (day >= Time.SUNDAY && day <= Time.SATURDAY); 29475b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio } 29575b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio 296bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 29775b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * Sets all the parameters for displaying this week. Parameters have a default value and 29875b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * will only update if a new value is included, except for focus month, which will always 29975b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * default to no focus month if no value is passed in. The only required parameter is the 30075b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * week start. 301bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 30275b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * @param selectedDay the selected day. 30375b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * @param month the month. 30475b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * @param year the year. 30575b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * @param weekStart which day the week should start on. {@link Time#SUNDAY} through 30675b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * {@link Time#SATURDAY}. 30775b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * @param enabledDayStart the first enabled day. 30875b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio * @param enabledDayEnd the last enabled day. 309bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 31075b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio void setMonthParams(int selectedDay, int month, int year, int weekStart, int enabledDayStart, 31175b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio int enabledDayEnd) { 31275b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio if (mRowHeight < MIN_HEIGHT) { 31375b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mRowHeight = MIN_HEIGHT; 314bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 31575b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio 31675b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio if (isValidDay(selectedDay)) { 31775b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mSelectedDay = selectedDay; 318bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 319bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 32075b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio if (month >= Calendar.JANUARY && month <= Calendar.DECEMBER) { 32175b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mMonth = month; 32275b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio } 32375b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mYear = year; 324bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 325bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Figure out what day today is 326bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final Time today = new Time(Time.getCurrentTimezone()); 327bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio today.setToNow(); 328bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mHasToday = false; 329bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mToday = -1; 330bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 331bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mCalendar.set(Calendar.MONTH, mMonth); 332bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mCalendar.set(Calendar.YEAR, mYear); 333bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mCalendar.set(Calendar.DAY_OF_MONTH, 1); 334bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayOfWeekStart = mCalendar.get(Calendar.DAY_OF_WEEK); 335bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 33675b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio if (isValidDay(weekStart)) { 33775b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mWeekStart = weekStart; 338bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } else { 339bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mWeekStart = mCalendar.getFirstDayOfWeek(); 340bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 341bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 34275b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio if (enabledDayStart > 0 && enabledDayEnd < 32) { 34375b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mEnabledDayStart = enabledDayStart; 344bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 34575b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio if (enabledDayEnd > 0 && enabledDayEnd < 32 && enabledDayEnd >= enabledDayStart) { 34675b121553f9c7498581a4b10d932f1c499feef25Fabrice Di Meglio mEnabledDayEnd = enabledDayEnd; 347bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 348bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 349bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mNumCells = getDaysInMonth(mMonth, mYear); 350bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio for (int i = 0; i < mNumCells; i++) { 351bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int day = i + 1; 352bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (sameDay(day, today)) { 353bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mHasToday = true; 354bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mToday = day; 355bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 356bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 357bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mNumRows = calculateNumRows(); 358bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 359bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Invalidate cached accessibility information. 360bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.invalidateRoot(); 361bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 362bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 363bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static int getDaysInMonth(int month, int year) { 364bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (month) { 365bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.JANUARY: 366bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.MARCH: 367bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.MAY: 368bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.JULY: 369bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.AUGUST: 370bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.OCTOBER: 371bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.DECEMBER: 372bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return 31; 373bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.APRIL: 374bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.JUNE: 375bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.SEPTEMBER: 376bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.NOVEMBER: 377bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return 30; 378bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case Calendar.FEBRUARY: 379bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return (year % 4 == 0) ? 29 : 28; 380bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 381bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new IllegalArgumentException("Invalid Month"); 382bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 383bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 384bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 385bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void reuse() { 386bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mNumRows = DEFAULT_NUM_ROWS; 387bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio requestLayout(); 388bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 389bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 390bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int calculateNumRows() { 391bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int offset = findDayOffset(); 392bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int dividend = (offset + mNumCells) / mNumDays; 393bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int remainder = (offset + mNumCells) % mNumDays; 394bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return (dividend + (remainder > 0 ? 1 : 0)); 395bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 396bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 397bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean sameDay(int day, Time today) { 398bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return mYear == today.year && 399bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonth == today.month && 400bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio day == today.monthDay; 401bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 402bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 403bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 404bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 405bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mRowHeight * mNumRows 406bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio + mMonthHeaderSize); 407bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 408bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 409bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 410bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onSizeChanged(int w, int h, int oldw, int oldh) { 411bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mWidth = w; 412bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 413bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Invalidate cached accessibility information. 414bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.invalidateRoot(); 415bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 416bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 417bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private String getMonthAndYearString() { 418bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR 419bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio | DateUtils.FORMAT_NO_MONTH_DAY; 420bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mStringBuilder.setLength(0); 421bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio long millis = mCalendar.getTimeInMillis(); 422bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return DateUtils.formatDateRange(getContext(), mFormatter, millis, millis, flags, 423bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio Time.getCurrentTimezone()).toString(); 424bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 425bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 426bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private void drawMonthTitle(Canvas canvas) { 427bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int x = (mWidth + 2 * mPadding) / 2; 428bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int y = (mMonthHeaderSize - mMonthDayLabelTextSize) / 2 + (mMonthLabelTextSize / 3); 429bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio canvas.drawText(getMonthAndYearString(), x, y, mMonthTitlePaint); 430bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 431bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 432bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private void drawWeekDayLabels(Canvas canvas) { 433bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int y = mMonthHeaderSize - (mMonthDayLabelTextSize / 2); 434bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2); 435bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 436bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio for (int i = 0; i < mNumDays; i++) { 437bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int calendarDay = (i + mWeekStart) % mNumDays; 438bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int x = (2 * i + 1) * dayWidthHalf + mPadding; 439bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay); 440bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio canvas.drawText(mDayLabelCalendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, 441bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio Locale.getDefault()).toUpperCase(Locale.getDefault()), x, y, 442bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mMonthDayLabelPaint); 443bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 444bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 445bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 446bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 447bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Draws the month days. 448bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 449bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private void drawDays(Canvas canvas) { 450bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int y = (((mRowHeight + mMiniDayNumberTextSize) / 2) - DAY_SEPARATOR_WIDTH) 451bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio + mMonthHeaderSize; 452bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2); 453bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int j = findDayOffset(); 454bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio for (int day = 1; day <= mNumCells; day++) { 455bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int x = (2 * j + 1) * dayWidthHalf + mPadding; 456bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mSelectedDay == day) { 457bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio canvas.drawCircle(x, y - (mMiniDayNumberTextSize / 3), mDaySelectedCircleSize, 458bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberSelectedPaint); 459bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 460bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 461bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mHasToday && mToday == day) { 462bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberPaint.setColor(mSelectedDayColor); 463bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } else { 464bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberPaint.setColor(mNormalTextColor); 465bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 466bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final Paint paint = (day < mEnabledDayStart || day > mEnabledDayEnd) ? 467bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mDayNumberDisabledPaint : mDayNumberPaint; 468bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio canvas.drawText(String.format("%d", day), x, y, paint); 469bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio j++; 470bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (j == mNumDays) { 471bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio j = 0; 472bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio y += mRowHeight; 473bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 474bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 475bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 476bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 477bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int findDayOffset() { 478bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return (mDayOfWeekStart < mWeekStart ? (mDayOfWeekStart + mNumDays) : mDayOfWeekStart) 479bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio - mWeekStart; 480bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 481bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 482bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 483bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Calculates the day that the given x position is in, accounting for week 484bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * number. Returns the day or -1 if the position wasn't in a day. 485bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 486bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param x The x position of the touch event 487bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return The day number, or -1 if the position wasn't in a day 488bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 489bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int getDayFromLocation(float x, float y) { 490bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int dayStart = mPadding; 491bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (x < dayStart || x > mWidth - mPadding) { 492bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return -1; 493bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 494bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Selection is (x - start) / (pixels/day) == (x -s) * day / pixels 495bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int row = (int) (y - mMonthHeaderSize) / mRowHeight; 496bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int column = (int) ((x - dayStart) * mNumDays / (mWidth - dayStart - mPadding)); 497bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 498bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int day = column - findDayOffset() + 1; 499bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio day += row * mNumDays; 500bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (day < 1 || day > mNumCells) { 501bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return -1; 502bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 503bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return day; 504bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 505bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 506bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 507bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Called when the user clicks on a day. Handles callbacks to the 508bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link OnDayClickListener} if one is set. 509bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 510bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param day The day that was clicked 511bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 512bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private void onDayClick(int day) { 513bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mOnDayClickListener != null) { 514bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio Calendar date = Calendar.getInstance(); 515bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio date.set(mYear, mMonth, day); 516bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mOnDayClickListener.onDayClick(this, date); 517bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 518bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 519bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // This is a no-op if accessibility is turned off. 520bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.sendEventForVirtualView(day, AccessibilityEvent.TYPE_VIEW_CLICKED); 521bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 522bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 523bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 524bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return The date that has accessibility focus, or {@code null} if no date 525bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * has focus 526bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 527bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio Calendar getAccessibilityFocus() { 528bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int day = mTouchHelper.getFocusedVirtualView(); 529bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio Calendar date = null; 530bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (day >= 0) { 531bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio date = Calendar.getInstance(); 532bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio date.set(mYear, mMonth, day); 533bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 534bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return date; 535bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 536bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 537bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 538bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Clears accessibility focus within the view. No-op if the view does not 539bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * contain accessibility focus. 540bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 541bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void clearAccessibilityFocus() { 542bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.clearFocusedVirtualView(); 543bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 544bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 545bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 546bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Attempts to restore accessibility focus to the specified date. 547bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 548bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param day The date which should receive focus 549bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return {@code false} if the date is not valid for this month view, or 550bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@code true} if the date received focus 551bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 552bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio boolean restoreAccessibilityFocus(Calendar day) { 553bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if ((day.get(Calendar.YEAR) != mYear) || (day.get(Calendar.MONTH) != mMonth) || 554bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio (day.get(Calendar.DAY_OF_MONTH) > mNumCells)) { 555bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 556bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 557bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTouchHelper.setFocusedVirtualView(day.get(Calendar.DAY_OF_MONTH)); 558bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 559bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 560bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 561bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 562bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Provides a virtual view hierarchy for interfacing with an accessibility 563bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * service. 564bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 565bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private class MonthViewTouchHelper extends ExploreByTouchHelper { 566bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final String DATE_FORMAT = "dd MMMM yyyy"; 567bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 568bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final Rect mTempRect = new Rect(); 569bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final Calendar mTempCalendar = Calendar.getInstance(); 570bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 571bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public MonthViewTouchHelper(View host) { 572bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio super(host); 573bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 574bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 575bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void setFocusedVirtualView(int virtualViewId) { 576bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio getAccessibilityNodeProvider(SimpleMonthView.this).performAction( 577bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio virtualViewId, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); 578bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 579bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 580bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void clearFocusedVirtualView() { 581bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int focusedVirtualView = getFocusedVirtualView(); 582bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (focusedVirtualView != ExploreByTouchHelper.INVALID_ID) { 583bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio getAccessibilityNodeProvider(SimpleMonthView.this).performAction( 584bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio focusedVirtualView, 585bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, 586bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio null); 587bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 588bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 589bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 590bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 591bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected int getVirtualViewAt(float x, float y) { 592bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int day = getDayFromLocation(x, y); 593bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (day >= 0) { 594bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return day; 595bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 596bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return ExploreByTouchHelper.INVALID_ID; 597bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 598bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 599bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 600bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void getVisibleVirtualViews(List<Integer> virtualViewIds) { 601bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio for (int day = 1; day <= mNumCells; day++) { 602bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio virtualViewIds.add(day); 603bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 604bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 605bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 606bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 607bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) { 608bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio event.setContentDescription(getItemDescription(virtualViewId)); 609bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 610bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 611bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 612bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfo node) { 613bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio getItemBounds(virtualViewId, mTempRect); 614bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 615bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setContentDescription(getItemDescription(virtualViewId)); 616bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setBoundsInParent(mTempRect); 617bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.addAction(AccessibilityNodeInfo.ACTION_CLICK); 618bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 619bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (virtualViewId == mSelectedDay) { 620bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setSelected(true); 621bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 622bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 623bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 624bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 625bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 626bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected boolean onPerformActionForVirtualView(int virtualViewId, int action, 627bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio Bundle arguments) { 628bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (action) { 629bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case AccessibilityNodeInfo.ACTION_CLICK: 630bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio onDayClick(virtualViewId); 631bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 632bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 633bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 634bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 635bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 636bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 637bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 638bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Calculates the bounding rectangle of a given time object. 639bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 640bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param day The day to calculate bounds for 641bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param rect The rectangle in which to store the bounds 642bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 643bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private void getItemBounds(int day, Rect rect) { 644bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int offsetX = mPadding; 645bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int offsetY = mMonthHeaderSize; 646bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int cellHeight = mRowHeight; 647bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int cellWidth = ((mWidth - (2 * mPadding)) / mNumDays); 648bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int index = ((day - 1) + findDayOffset()); 649bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int row = (index / mNumDays); 650bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int column = (index % mNumDays); 651bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int x = (offsetX + (column * cellWidth)); 652bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int y = (offsetY + (row * cellHeight)); 653bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 654bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio rect.set(x, y, (x + cellWidth), (y + cellHeight)); 655bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 656bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 657bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 658bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Generates a description for a given time object. Since this 659bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * description will be spoken, the components are ordered by descending 660bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * specificity as DAY MONTH YEAR. 661bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 662bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param day The day to generate a description for 663bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return A description of the time object 664bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 665bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private CharSequence getItemDescription(int day) { 666bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTempCalendar.set(mYear, mMonth, day); 667bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final CharSequence date = DateFormat.format(DATE_FORMAT, 668bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mTempCalendar.getTimeInMillis()); 669bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 670bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (day == mSelectedDay) { 671bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return getContext().getString(R.string.item_is_selected, date); 672bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 673bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 674bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return date; 675bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 676bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 677bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 678bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 679bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Handles callbacks when the user clicks on a time object. 680bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 681bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public interface OnDayClickListener { 682bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void onDayClick(SimpleMonthView view, Calendar day); 683bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 684bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio} 685