MonthView.java revision 529542558544a0e6d78424e33c60934adc143804
1e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung/* 2e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Copyright (C) 2013 The Android Open Source Project 3e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * 4e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Licensed under the Apache License, Version 2.0 (the "License"); 5e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * you may not use this file except in compliance with the License. 6e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * You may obtain a copy of the License at 7e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * 8e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * http://www.apache.org/licenses/LICENSE-2.0 9e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * 10e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Unless required by applicable law or agreed to in writing, software 11e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * distributed under the License is distributed on an "AS IS" BASIS, 12e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * See the License for the specific language governing permissions and 14e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * limitations under the License. 15e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 16e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 17e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungpackage com.android.datetimepicker.date; 18e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 19e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.content.Context; 20e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.content.res.Resources; 21e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.graphics.Canvas; 22e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.graphics.Paint; 23e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.graphics.Paint.Align; 24e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.graphics.Paint.Style; 25e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.graphics.Rect; 26e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.graphics.Typeface; 27e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.os.Bundle; 28e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.support.v4.view.ViewCompat; 29e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 30e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.support.v4.widget.ExploreByTouchHelper; 31e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.text.format.DateFormat; 32e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.text.format.DateUtils; 33e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.text.format.Time; 34e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.view.MotionEvent; 35e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.view.View; 36e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.view.accessibility.AccessibilityEvent; 37e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport android.view.accessibility.AccessibilityNodeInfo; 38e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 39e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport com.android.datetimepicker.R; 40e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport com.android.datetimepicker.Utils; 41e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport com.android.datetimepicker.date.MonthAdapter.CalendarDay; 42e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 43e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport java.security.InvalidParameterException; 44e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport java.util.Calendar; 45e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport java.util.Formatter; 46e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport java.util.HashMap; 47e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport java.util.List; 48e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungimport java.util.Locale; 49e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 50e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung/** 51e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * A calendar-like view displaying a specified month and the appropriate selectable day numbers 52e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * within the specified month. 53e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 54e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kungpublic abstract class MonthView extends View { 55e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private static final String TAG = "MonthView"; 56e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 57e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 58e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * These params can be passed into the view to control how it appears. 59e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * {@link #VIEW_PARAMS_WEEK} is the only required field, though the default 60e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * values are unlikely to fit most layouts correctly. 61e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 62e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 63e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * This sets the height of this week in pixels 64e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 65e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public static final String VIEW_PARAMS_HEIGHT = "height"; 66e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 67e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * This specifies the position (or weeks since the epoch) of this week, 68e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * calculated using {@link Utils#getWeeksSinceEpochFromJulianDay} 69e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 70e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public static final String VIEW_PARAMS_MONTH = "month"; 71e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 72e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * This specifies the position (or weeks since the epoch) of this week, 73e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * calculated using {@link Utils#getWeeksSinceEpochFromJulianDay} 74e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 75e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public static final String VIEW_PARAMS_YEAR = "year"; 76e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 77e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * This sets one of the days in this view as selected {@link Time#SUNDAY} 78e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * through {@link Time#SATURDAY}. 79e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 80e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public static final String VIEW_PARAMS_SELECTED_DAY = "selected_day"; 81e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 82e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Which day the week should start on. {@link Time#SUNDAY} through 83e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * {@link Time#SATURDAY}. 84e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 85e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public static final String VIEW_PARAMS_WEEK_START = "week_start"; 86e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 87e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * How many days to display at a time. Days will be displayed starting with 88e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * {@link #mWeekStart}. 89e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 90e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public static final String VIEW_PARAMS_NUM_DAYS = "num_days"; 91e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 92e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Which month is currently in focus, as defined by {@link Time#month} 93e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * [0-11]. 94e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 95e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public static final String VIEW_PARAMS_FOCUS_MONTH = "focus_month"; 96e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 97e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * If this month should display week numbers. false if 0, true otherwise. 98e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 99e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public static final String VIEW_PARAMS_SHOW_WK_NUM = "show_wk_num"; 100e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 101e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static int DEFAULT_HEIGHT = 32; 102e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static int MIN_HEIGHT = 10; 103e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static final int DEFAULT_SELECTED_DAY = -1; 104e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static final int DEFAULT_WEEK_START = Calendar.SUNDAY; 105e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static final int DEFAULT_NUM_DAYS = 7; 106e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static final int DEFAULT_SHOW_WK_NUM = 0; 107e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static final int DEFAULT_FOCUS_MONTH = -1; 108e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static final int DEFAULT_NUM_ROWS = 6; 109e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static final int MAX_NUM_ROWS = 6; 110e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 111e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private static final int SELECTED_CIRCLE_ALPHA = 60; 112e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 113e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static int DAY_SEPARATOR_WIDTH = 1; 114e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static int MINI_DAY_NUMBER_TEXT_SIZE; 115e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static int MONTH_LABEL_TEXT_SIZE; 116e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static int MONTH_DAY_LABEL_TEXT_SIZE; 117e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static int MONTH_HEADER_SIZE; 118e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static int DAY_SELECTED_CIRCLE_SIZE; 119e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 120e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // used for scaling to the device density 121e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected static float mScale = 0; 122e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 123e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // affects the padding on the sides of this view 124e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mPadding = 0; 125e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 126e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private String mDayOfWeekTypeface; 127e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private String mMonthTitleTypeface; 128e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 129e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected Paint mMonthNumPaint; 130e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected Paint mMonthTitlePaint; 131e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected Paint mMonthTitleBGPaint; 132e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected Paint mSelectedCirclePaint; 133e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected Paint mMonthDayLabelPaint; 134e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 135e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private final Formatter mFormatter; 136e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private final StringBuilder mStringBuilder; 137e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 138e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // The Julian day of the first day displayed by this item 139e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mFirstJulianDay = -1; 140e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // The month of the first day in this week 141e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mFirstMonth = -1; 142e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // The month of the last day in this week 143e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mLastMonth = -1; 144e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 145e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mMonth; 146e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 147e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mYear; 148e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // Quick reference to the width of this view, matches parent 149e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mWidth; 150e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // The height this view should draw at in pixels, set by height param 151e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mRowHeight = DEFAULT_HEIGHT; 152e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // If this view contains the today 153e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected boolean mHasToday = false; 154e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // Which day is selected [0-6] or -1 if no day is selected 155e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mSelectedDay = -1; 156e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // Which day is today [0-6] or -1 if no day is today 157e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mToday = DEFAULT_SELECTED_DAY; 158e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // Which day of the week to start on [0-6] 159e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mWeekStart = DEFAULT_WEEK_START; 160e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // How many days to display 161e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mNumDays = DEFAULT_NUM_DAYS; 162e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // The number of days + a spot for week number if it is displayed 163e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mNumCells = mNumDays; 164e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // The left edge of the selected day 165e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mSelectedLeft = -1; 166e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // The right edge of the selected day 167e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mSelectedRight = -1; 168e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 169e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private final Calendar mCalendar; 170e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private final Calendar mDayLabelCalendar; 171e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private final MonthViewTouchHelper mTouchHelper; 172e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 173e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private int mNumRows = DEFAULT_NUM_ROWS; 174e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 175e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // Optional listener for handling day click actions 176e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private OnDayClickListener mOnDayClickListener; 177e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // Whether to prevent setting the accessibility delegate 178e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private boolean mLockAccessibilityDelegate; 179e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 180e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mDayTextColor; 181e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mTodayNumberColor; 182e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mMonthTitleColor; 183e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int mMonthTitleBGColor; 184e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 185e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public MonthView(Context context) { 186e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung super(context); 187e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 188e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung Resources res = context.getResources(); 189e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 190e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mDayLabelCalendar = Calendar.getInstance(); 191e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mCalendar = Calendar.getInstance(); 192e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 193e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mDayOfWeekTypeface = res.getString(R.string.day_of_week_label_typeface); 194e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitleTypeface = res.getString(R.string.sans_serif); 195e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 196e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mDayTextColor = res.getColor(R.color.date_picker_text_normal); 197e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mTodayNumberColor = res.getColor(R.color.blue); 198e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitleColor = res.getColor(R.color.white); 199e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitleBGColor = res.getColor(R.color.circle_background); 200e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 201e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mStringBuilder = new StringBuilder(50); 202e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mFormatter = new Formatter(mStringBuilder, Locale.getDefault()); 203e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 204e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung MINI_DAY_NUMBER_TEXT_SIZE = res.getDimensionPixelSize(R.dimen.day_number_size); 205e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung MONTH_LABEL_TEXT_SIZE = res.getDimensionPixelSize(R.dimen.month_label_size); 206e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung MONTH_DAY_LABEL_TEXT_SIZE = res.getDimensionPixelSize(R.dimen.month_day_label_text_size); 207e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung MONTH_HEADER_SIZE = res.getDimensionPixelOffset(R.dimen.month_list_item_header_height); 208e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung DAY_SELECTED_CIRCLE_SIZE = res 209e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung .getDimensionPixelSize(R.dimen.day_number_select_circle_radius); 210e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 211e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mRowHeight = (res.getDimensionPixelOffset(R.dimen.date_picker_view_animator_height) 212e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung - MONTH_HEADER_SIZE) / MAX_NUM_ROWS; 213e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 214e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // Set up accessibility components. 215529542558544a0e6d78424e33c60934adc143804Ruben mTouchHelper = getMonthViewTouchHelper(); 216e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung ViewCompat.setAccessibilityDelegate(this, mTouchHelper); 217e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung ViewCompat.setImportantForAccessibility(this, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); 218e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mLockAccessibilityDelegate = true; 219e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 220e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // Sets up any standard paints that will be used 221e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung initView(); 222e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 223e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 224529542558544a0e6d78424e33c60934adc143804Ruben protected MonthViewTouchHelper getMonthViewTouchHelper() { 225529542558544a0e6d78424e33c60934adc143804Ruben return new MonthViewTouchHelper(this); 226529542558544a0e6d78424e33c60934adc143804Ruben } 227529542558544a0e6d78424e33c60934adc143804Ruben 228e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung @Override 229e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public void setAccessibilityDelegate(AccessibilityDelegate delegate) { 230e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // Workaround for a JB MR1 issue where accessibility delegates on 231e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // top-level ListView items are overwritten. 232e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (!mLockAccessibilityDelegate) { 233e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung super.setAccessibilityDelegate(delegate); 234e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 235e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 236e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 237e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public void setOnDayClickListener(OnDayClickListener listener) { 238e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mOnDayClickListener = listener; 239e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 240e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 241e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung @Override 242e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public boolean dispatchHoverEvent(MotionEvent event) { 243e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // First right-of-refusal goes the touch exploration helper. 244e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (mTouchHelper.dispatchHoverEvent(event)) { 245e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return true; 246e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 247e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return super.dispatchHoverEvent(event); 248e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 249e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 250e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung @Override 251e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public boolean onTouchEvent(MotionEvent event) { 252e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung switch (event.getAction()) { 253e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung case MotionEvent.ACTION_UP: 254e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final int day = getDayFromLocation(event.getX(), event.getY()); 255e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (day >= 0) { 256e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung onDayClick(day); 257e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 258e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung break; 259e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 260e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return true; 261e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 262e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 263e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 264e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Sets up the text and style properties for painting. Override this if you 265e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * want to use a different paint. 266e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 267e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected void initView() { 268e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitlePaint = new Paint(); 269e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitlePaint.setFakeBoldText(true); 270e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitlePaint.setAntiAlias(true); 271e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitlePaint.setTextSize(MONTH_LABEL_TEXT_SIZE); 272e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitlePaint.setTypeface(Typeface.create(mMonthTitleTypeface, Typeface.BOLD)); 273e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitlePaint.setColor(mDayTextColor); 274e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitlePaint.setTextAlign(Align.CENTER); 275e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitlePaint.setStyle(Style.FILL); 276e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 277e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitleBGPaint = new Paint(); 278e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitleBGPaint.setFakeBoldText(true); 279e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitleBGPaint.setAntiAlias(true); 280e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitleBGPaint.setColor(mMonthTitleBGColor); 281e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitleBGPaint.setTextAlign(Align.CENTER); 282e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthTitleBGPaint.setStyle(Style.FILL); 283e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 284e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mSelectedCirclePaint = new Paint(); 285e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mSelectedCirclePaint.setFakeBoldText(true); 286e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mSelectedCirclePaint.setAntiAlias(true); 287e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mSelectedCirclePaint.setColor(mTodayNumberColor); 288e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mSelectedCirclePaint.setTextAlign(Align.CENTER); 289e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mSelectedCirclePaint.setStyle(Style.FILL); 290e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mSelectedCirclePaint.setAlpha(SELECTED_CIRCLE_ALPHA); 291e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 292e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthDayLabelPaint = new Paint(); 293e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthDayLabelPaint.setAntiAlias(true); 294e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthDayLabelPaint.setTextSize(MONTH_DAY_LABEL_TEXT_SIZE); 295e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthDayLabelPaint.setColor(mDayTextColor); 296e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthDayLabelPaint.setTypeface(Typeface.create(mDayOfWeekTypeface, Typeface.NORMAL)); 297e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthDayLabelPaint.setStyle(Style.FILL); 298e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthDayLabelPaint.setTextAlign(Align.CENTER); 299e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthDayLabelPaint.setFakeBoldText(true); 300e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 301e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthNumPaint = new Paint(); 302e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthNumPaint.setAntiAlias(true); 303e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthNumPaint.setTextSize(MINI_DAY_NUMBER_TEXT_SIZE); 304e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthNumPaint.setStyle(Style.FILL); 305e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthNumPaint.setTextAlign(Align.CENTER); 306e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthNumPaint.setFakeBoldText(false); 307e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 308e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 309e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung @Override 310e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected void onDraw(Canvas canvas) { 311e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung drawMonthTitle(canvas); 312e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung drawMonthDayLabels(canvas); 313e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung drawMonthNums(canvas); 314e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 315e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 316e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private int mDayOfWeekStart = 0; 317e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 318e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 319e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Sets all the parameters for displaying this week. The only required 320e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * parameter is the week number. Other parameters have a default value and 321e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * will only update if a new value is included, except for focus month, 322e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * which will always default to no focus month if no value is passed in. See 323e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * {@link #VIEW_PARAMS_HEIGHT} for more info on parameters. 324e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * 325e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param params A map of the new parameters, see 326e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * {@link #VIEW_PARAMS_HEIGHT} 327e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 328e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public void setMonthParams(HashMap<String, Integer> params) { 329e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (!params.containsKey(VIEW_PARAMS_MONTH) && !params.containsKey(VIEW_PARAMS_YEAR)) { 330e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung throw new InvalidParameterException("You must specify month and year for this view"); 331e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 332e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung setTag(params); 333e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // We keep the current value for any params not present 334e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (params.containsKey(VIEW_PARAMS_HEIGHT)) { 335e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mRowHeight = params.get(VIEW_PARAMS_HEIGHT); 336e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (mRowHeight < MIN_HEIGHT) { 337e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mRowHeight = MIN_HEIGHT; 338e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 339e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 340e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (params.containsKey(VIEW_PARAMS_SELECTED_DAY)) { 341e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mSelectedDay = params.get(VIEW_PARAMS_SELECTED_DAY); 342e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 343e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 344e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // Allocate space for caching the day numbers and focus values 345e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonth = params.get(VIEW_PARAMS_MONTH); 346e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mYear = params.get(VIEW_PARAMS_YEAR); 347e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 348e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // Figure out what day today is 349e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final Time today = new Time(Time.getCurrentTimezone()); 350e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung today.setToNow(); 351e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mHasToday = false; 352e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mToday = -1; 353e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 354e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mCalendar.set(Calendar.MONTH, mMonth); 355e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mCalendar.set(Calendar.YEAR, mYear); 356e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mCalendar.set(Calendar.DAY_OF_MONTH, 1); 357e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mDayOfWeekStart = mCalendar.get(Calendar.DAY_OF_WEEK); 358e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 359e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (params.containsKey(VIEW_PARAMS_WEEK_START)) { 360e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mWeekStart = params.get(VIEW_PARAMS_WEEK_START); 361e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } else { 362e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mWeekStart = mCalendar.getFirstDayOfWeek(); 363e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 364e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 365e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mNumCells = Utils.getDaysInMonth(mMonth, mYear); 366e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung for (int i = 0; i < mNumCells; i++) { 367e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final int day = i + 1; 368e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (sameDay(day, today)) { 369e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mHasToday = true; 370e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mToday = day; 371e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 372e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 373e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mNumRows = calculateNumRows(); 374e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 375e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // Invalidate cached accessibility information. 376e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mTouchHelper.invalidateRoot(); 377e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 378e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 3795cfe197091de6e7b5550fc2503e00fe554bef5cdSam Blitzstein public void setSelectedDay(int day) { 3805cfe197091de6e7b5550fc2503e00fe554bef5cdSam Blitzstein mSelectedDay = day; 3815cfe197091de6e7b5550fc2503e00fe554bef5cdSam Blitzstein } 3825cfe197091de6e7b5550fc2503e00fe554bef5cdSam Blitzstein 383e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public void reuse() { 384e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mNumRows = DEFAULT_NUM_ROWS; 385e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung requestLayout(); 386e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 387e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 388e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private int calculateNumRows() { 389e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int offset = findDayOffset(); 390e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int dividend = (offset + mNumCells) / mNumDays; 391e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int remainder = (offset + mNumCells) % mNumDays; 392e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return (dividend + (remainder > 0 ? 1 : 0)); 393e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 394e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 395e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private boolean sameDay(int day, Time today) { 396e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return mYear == today.year && 397e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonth == today.month && 398e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung day == today.monthDay; 399e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 400e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 401e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung @Override 402e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 403e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mRowHeight * mNumRows 404e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung + MONTH_HEADER_SIZE); 405e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 406e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 407e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung @Override 408e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected void onSizeChanged(int w, int h, int oldw, int oldh) { 409e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mWidth = w; 410e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 411e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // Invalidate cached accessibility information. 412e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mTouchHelper.invalidateRoot(); 413e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 414e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 4155cfe197091de6e7b5550fc2503e00fe554bef5cdSam Blitzstein public int getMonth() { 4165cfe197091de6e7b5550fc2503e00fe554bef5cdSam Blitzstein return mMonth; 4175cfe197091de6e7b5550fc2503e00fe554bef5cdSam Blitzstein } 4185cfe197091de6e7b5550fc2503e00fe554bef5cdSam Blitzstein 4195cfe197091de6e7b5550fc2503e00fe554bef5cdSam Blitzstein public int getYear() { 4205cfe197091de6e7b5550fc2503e00fe554bef5cdSam Blitzstein return mYear; 4215cfe197091de6e7b5550fc2503e00fe554bef5cdSam Blitzstein } 4225cfe197091de6e7b5550fc2503e00fe554bef5cdSam Blitzstein 423e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private String getMonthAndYearString() { 424e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR 425e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung | DateUtils.FORMAT_NO_MONTH_DAY; 426e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mStringBuilder.setLength(0); 427e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung long millis = mCalendar.getTimeInMillis(); 428e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return DateUtils.formatDateRange(getContext(), mFormatter, millis, millis, flags, 429e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung Time.getCurrentTimezone()).toString(); 430e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 431e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 432e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private void drawMonthTitle(Canvas canvas) { 433e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int x = (mWidth + 2 * mPadding) / 2; 434e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int y = (MONTH_HEADER_SIZE - MONTH_DAY_LABEL_TEXT_SIZE) / 2 + (MONTH_LABEL_TEXT_SIZE / 3); 435e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung canvas.drawText(getMonthAndYearString(), x, y, mMonthTitlePaint); 436e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 437e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 438e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private void drawMonthDayLabels(Canvas canvas) { 439e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int y = MONTH_HEADER_SIZE - (MONTH_DAY_LABEL_TEXT_SIZE / 2); 440e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2); 441e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 442e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung for (int i = 0; i < mNumDays; i++) { 443e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int calendarDay = (i + mWeekStart) % mNumDays; 444e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int x = (2 * i + 1) * dayWidthHalf + mPadding; 445e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mDayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay); 446e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung canvas.drawText(mDayLabelCalendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, 447e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung Locale.getDefault()).toUpperCase(Locale.getDefault()), x, y, 448e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mMonthDayLabelPaint); 449e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 450e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 451e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 452e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 453e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Draws the week and month day numbers for this week. Override this method 454e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * if you need different placement. 455e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * 456e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param canvas The canvas to draw on 457e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 458e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected void drawMonthNums(Canvas canvas) { 459e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int y = (((mRowHeight + MINI_DAY_NUMBER_TEXT_SIZE) / 2) - DAY_SEPARATOR_WIDTH) 460e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung + MONTH_HEADER_SIZE; 461e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2); 462e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int j = findDayOffset(); 463e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung for (int dayNumber = 1; dayNumber <= mNumCells; dayNumber++) { 464e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int x = (2 * j + 1) * dayWidthHalf + mPadding; 465e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 466e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int yRelativeToDay = (mRowHeight + MINI_DAY_NUMBER_TEXT_SIZE) / 2 - DAY_SEPARATOR_WIDTH; 467e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 468e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int startX = x - dayWidthHalf; 469e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int stopX = x + dayWidthHalf; 470e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int startY = y - yRelativeToDay; 471e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int stopY = startY + mRowHeight; 472e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 473e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung drawMonthDay(canvas, mYear, mMonth, dayNumber, x, y, startX, stopX, startY, stopY); 474e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 475e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung j++; 476e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (j == mNumDays) { 477e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung j = 0; 478e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung y += mRowHeight; 479e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 480e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 481e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 482e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 483e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 484e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * This method should draw the month day. Implemented by sub-classes to allow customization. 485e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * 486e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param canvas The canvas to draw on 487e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param year The year of this month day 488e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param month The month of this month day 489e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param day The day number of this month day 490e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param x The default x position to draw the day number 491e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param y The default y position to draw the day number 492e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param startX The left boundary of the day number rect 493e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param stopX The right boundary of the day number rect 494e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param startY The top boundary of the day number rect 495e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param stopY The bottom boundary of the day number rect 496e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 497e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public abstract void drawMonthDay(Canvas canvas, int year, int month, int day, 498e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int x, int y, int startX, int stopX, int startY, int stopY); 499e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 500e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private int findDayOffset() { 501e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return (mDayOfWeekStart < mWeekStart ? (mDayOfWeekStart + mNumDays) : mDayOfWeekStart) 502e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung - mWeekStart; 503e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 504e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 505e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 506e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 507e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Calculates the day that the given x position is in, accounting for week 508e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * number. Returns the day or -1 if the position wasn't in a day. 509e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * 510e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param x The x position of the touch event 511e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @return The day number, or -1 if the position wasn't in a day 512e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 513e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public int getDayFromLocation(float x, float y) { 514e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int dayStart = mPadding; 515e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (x < dayStart || x > mWidth - mPadding) { 516e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return -1; 517e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 518e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // Selection is (x - start) / (pixels/day) == (x -s) * day / pixels 519e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int row = (int) (y - MONTH_HEADER_SIZE) / mRowHeight; 520e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int column = (int) ((x - dayStart) * mNumDays / (mWidth - dayStart - mPadding)); 521e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 522e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung int day = column - findDayOffset() + 1; 523e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung day += row * mNumDays; 524e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (day < 1 || day > mNumCells) { 525e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return -1; 526e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 527e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return day; 528e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 529e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 530e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 531e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Called when the user clicks on a day. Handles callbacks to the 532e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * {@link OnDayClickListener} if one is set. 533e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * 534e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param day The day that was clicked 535e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 536e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private void onDayClick(int day) { 537e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (mOnDayClickListener != null) { 538e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mOnDayClickListener.onDayClick(this, new CalendarDay(mYear, mMonth, day)); 539e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 540e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 541e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung // This is a no-op if accessibility is turned off. 542e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mTouchHelper.sendEventForVirtualView(day, AccessibilityEvent.TYPE_VIEW_CLICKED); 543e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 544e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 545e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 546e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @return The date that has accessibility focus, or {@code null} if no date 547e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * has focus 548e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 549e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public CalendarDay getAccessibilityFocus() { 550e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final int day = mTouchHelper.getFocusedVirtualView(); 551e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (day >= 0) { 552e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return new CalendarDay(mYear, mMonth, day); 553e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 554e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return null; 555e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 556e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 557e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 558e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Clears accessibility focus within the view. No-op if the view does not 559e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * contain accessibility focus. 560e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 561e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public void clearAccessibilityFocus() { 562e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mTouchHelper.clearFocusedVirtualView(); 563e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 564e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 565e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 566e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Attempts to restore accessibility focus to the specified date. 567e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * 568e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param day The date which should receive focus 569e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @return {@code false} if the date is not valid for this month view, or 570e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * {@code true} if the date received focus 571e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 572e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public boolean restoreAccessibilityFocus(CalendarDay day) { 573e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if ((day.year != mYear) || (day.month != mMonth) || (day.day > mNumCells)) { 574e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return false; 575e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 576e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mTouchHelper.setFocusedVirtualView(day.day); 577e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return true; 578e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 579e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 580e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 581e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Provides a virtual view hierarchy for interfacing with an accessibility 582e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * service. 583e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 584529542558544a0e6d78424e33c60934adc143804Ruben protected class MonthViewTouchHelper extends ExploreByTouchHelper { 585e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private static final String DATE_FORMAT = "dd MMMM yyyy"; 586e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 587e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private final Rect mTempRect = new Rect(); 588e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private final Calendar mTempCalendar = Calendar.getInstance(); 589e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 590e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public MonthViewTouchHelper(View host) { 591e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung super(host); 592e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 593e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 594e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public void setFocusedVirtualView(int virtualViewId) { 595e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung getAccessibilityNodeProvider(MonthView.this).performAction( 596e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung virtualViewId, AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS, null); 597e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 598e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 599e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public void clearFocusedVirtualView() { 600e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final int focusedVirtualView = getFocusedVirtualView(); 601e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (focusedVirtualView != ExploreByTouchHelper.INVALID_ID) { 602e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung getAccessibilityNodeProvider(MonthView.this).performAction( 603e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung focusedVirtualView, 604e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS, 605e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung null); 606e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 607e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 608e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 609e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung @Override 610e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected int getVirtualViewAt(float x, float y) { 611e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final int day = getDayFromLocation(x, y); 612e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (day >= 0) { 613e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return day; 614e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 615e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return ExploreByTouchHelper.INVALID_ID; 616e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 617e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 618e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung @Override 619e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected void getVisibleVirtualViews(List<Integer> virtualViewIds) { 620e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung for (int day = 1; day <= mNumCells; day++) { 621e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung virtualViewIds.add(day); 622e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 623e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 624e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 625e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung @Override 626e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) { 627e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung event.setContentDescription(getItemDescription(virtualViewId)); 628e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 629e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 630e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung @Override 631e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected void onPopulateNodeForVirtualView(int virtualViewId, 632e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung AccessibilityNodeInfoCompat node) { 633e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung getItemBounds(virtualViewId, mTempRect); 634e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 635e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung node.setContentDescription(getItemDescription(virtualViewId)); 636e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung node.setBoundsInParent(mTempRect); 637e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung node.addAction(AccessibilityNodeInfo.ACTION_CLICK); 638e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 639e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (virtualViewId == mSelectedDay) { 640e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung node.setSelected(true); 641e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 642e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 643e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 644e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 645e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung @Override 646e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung protected boolean onPerformActionForVirtualView(int virtualViewId, int action, 647e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung Bundle arguments) { 648e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung switch (action) { 649e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung case AccessibilityNodeInfo.ACTION_CLICK: 650e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung onDayClick(virtualViewId); 651e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return true; 652e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 653e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 654e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return false; 655e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 656e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 657e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 658e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Calculates the bounding rectangle of a given time object. 659e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * 660e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param day The day to calculate bounds for 661e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param rect The rectangle in which to store the bounds 662e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 663e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung private void getItemBounds(int day, Rect rect) { 664e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final int offsetX = mPadding; 665e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final int offsetY = MONTH_HEADER_SIZE; 666e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final int cellHeight = mRowHeight; 667e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final int cellWidth = ((mWidth - (2 * mPadding)) / mNumDays); 668e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final int index = ((day - 1) + findDayOffset()); 669e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final int row = (index / mNumDays); 670e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final int column = (index % mNumDays); 671e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final int x = (offsetX + (column * cellWidth)); 672e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final int y = (offsetY + (row * cellHeight)); 673e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 674e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung rect.set(x, y, (x + cellWidth), (y + cellHeight)); 675e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 676e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 677e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 678e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Generates a description for a given time object. Since this 679e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * description will be spoken, the components are ordered by descending 680e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * specificity as DAY MONTH YEAR. 681e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * 682e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @param day The day to generate a description for 683e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * @return A description of the time object 684e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 685529542558544a0e6d78424e33c60934adc143804Ruben protected CharSequence getItemDescription(int day) { 686e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mTempCalendar.set(mYear, mMonth, day); 687e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung final CharSequence date = DateFormat.format(DATE_FORMAT, 688e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung mTempCalendar.getTimeInMillis()); 689e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 690e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung if (day == mSelectedDay) { 691e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return getContext().getString(R.string.item_is_selected, date); 692e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 693e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 694e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung return date; 695e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 696e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 697e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung 698e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung /** 699e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung * Handles callbacks when the user clicks on a time object. 700e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung */ 701e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public interface OnDayClickListener { 702e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung public void onDayClick(MonthView view, CalendarDay day); 703e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung } 704e668d6b1b77ac4b127f961150e0d0a8a088143d9James Kung} 705