summaryrefslogtreecommitdiff
path: root/src/com/android
diff options
context:
space:
mode:
authorJames Kung <kingkung@google.com>2013-10-04 19:37:26 -0700
committerJames Kung <kingkung@google.com>2013-10-06 10:08:31 -0700
commite668d6b1b77ac4b127f961150e0d0a8a088143d9 (patch)
tree96866e9d5483aedf172a8081b9e4fd4a84412524 /src/com/android
parent16b291818825d611ef14770187616911560dedb4 (diff)
downloaddatetimepicker-e668d6b1b77ac4b127f961150e0d0a8a088143d9.tar.gz
Abstracting date picker classes to allow customization
Change-Id: Iaf4a61fa2c0c975ffabe21658e654939f0f29782
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/datetimepicker/date/DatePickerController.java2
-rw-r--r--src/com/android/datetimepicker/date/DatePickerDialog.java4
-rw-r--r--src/com/android/datetimepicker/date/DayPickerView.java38
-rw-r--r--src/com/android/datetimepicker/date/MonthAdapter.java224
-rw-r--r--src/com/android/datetimepicker/date/MonthView.java688
-rw-r--r--src/com/android/datetimepicker/date/SimpleDayPickerView.java40
-rw-r--r--src/com/android/datetimepicker/date/SimpleMonthAdapter.java200
-rw-r--r--src/com/android/datetimepicker/date/SimpleMonthView.java644
8 files changed, 989 insertions, 851 deletions
diff --git a/src/com/android/datetimepicker/date/DatePickerController.java b/src/com/android/datetimepicker/date/DatePickerController.java
index a4986cc..f89580e 100644
--- a/src/com/android/datetimepicker/date/DatePickerController.java
+++ b/src/com/android/datetimepicker/date/DatePickerController.java
@@ -17,7 +17,7 @@
package com.android.datetimepicker.date;
import com.android.datetimepicker.date.DatePickerDialog.OnDateChangedListener;
-import com.android.datetimepicker.date.SimpleMonthAdapter.CalendarDay;
+import com.android.datetimepicker.date.MonthAdapter.CalendarDay;
/**
* Controller class to communicate among the various components of the date picker dialog.
diff --git a/src/com/android/datetimepicker/date/DatePickerDialog.java b/src/com/android/datetimepicker/date/DatePickerDialog.java
index a9aff7f..14c6b6d 100644
--- a/src/com/android/datetimepicker/date/DatePickerDialog.java
+++ b/src/com/android/datetimepicker/date/DatePickerDialog.java
@@ -38,7 +38,7 @@ import android.widget.TextView;
import com.android.datetimepicker.HapticFeedbackController;
import com.android.datetimepicker.R;
import com.android.datetimepicker.Utils;
-import com.android.datetimepicker.date.SimpleMonthAdapter.CalendarDay;
+import com.android.datetimepicker.date.MonthAdapter.CalendarDay;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@@ -219,7 +219,7 @@ public class DatePickerDialog extends DialogFragment implements
}
final Activity activity = getActivity();
- mDayPickerView = new DayPickerView(activity, this);
+ mDayPickerView = new SimpleDayPickerView(activity, this);
mYearPickerView = new YearPickerView(activity, this);
Resources res = getResources();
diff --git a/src/com/android/datetimepicker/date/DayPickerView.java b/src/com/android/datetimepicker/date/DayPickerView.java
index e57a7fa..b1838da 100644
--- a/src/com/android/datetimepicker/date/DayPickerView.java
+++ b/src/com/android/datetimepicker/date/DayPickerView.java
@@ -33,7 +33,7 @@ import android.widget.ListView;
import com.android.datetimepicker.Utils;
import com.android.datetimepicker.date.DatePickerDialog.OnDateChangedListener;
-import com.android.datetimepicker.date.SimpleMonthAdapter.CalendarDay;
+import com.android.datetimepicker.date.MonthAdapter.CalendarDay;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@@ -42,7 +42,8 @@ import java.util.Locale;
/**
* This displays a list of months in a calendar format with selectable days.
*/
-public class DayPickerView extends ListView implements OnScrollListener, OnDateChangedListener {
+public abstract class DayPickerView extends ListView implements OnScrollListener,
+ OnDateChangedListener {
private static final String TAG = "MonthFragment";
@@ -71,11 +72,10 @@ public class DayPickerView extends ListView implements OnScrollListener, OnDateC
// highlighted time
protected CalendarDay mSelectedDay = new CalendarDay();
- protected SimpleMonthAdapter mAdapter;
+ protected MonthAdapter mAdapter;
protected CalendarDay mTempDay = new CalendarDay();
- private static float mScale = 0;
// When the week starts; numbered like Time.<WEEKDAY> (e.g. SUNDAY=0).
protected int mFirstDayOfWeek;
// The last name announced by accessibility
@@ -106,8 +106,7 @@ public class DayPickerView extends ListView implements OnScrollListener, OnDateC
public void setController(DatePickerController controller) {
mController = controller;
mController.registerOnDateChangedListener(this);
- setUpAdapter();
- setAdapter(mAdapter);
+ refreshAdapter();
onDateChanged();
}
@@ -121,25 +120,26 @@ public class DayPickerView extends ListView implements OnScrollListener, OnDateC
}
public void onChange() {
- setUpAdapter();
- setAdapter(mAdapter);
+ refreshAdapter();
}
/**
* Creates a new adapter if necessary and sets up its parameters. Override
* this method to provide a custom adapter.
*/
- protected void setUpAdapter() {
+ protected void refreshAdapter() {
if (mAdapter == null) {
- mAdapter = new SimpleMonthAdapter(getContext(), mController);
+ mAdapter = createMonthAdapter(getContext(), mController);
} else {
mAdapter.setSelectedDay(mSelectedDay);
- mAdapter.notifyDataSetChanged();
}
// refresh the view with the new parameters
- mAdapter.notifyDataSetChanged();
+ setAdapter(mAdapter);
}
+ public abstract MonthAdapter createMonthAdapter(Context context,
+ DatePickerController controller);
+
/*
* Sets all the required fields for the list view. Override this method to
* set a different list view behavior.
@@ -184,7 +184,7 @@ public class DayPickerView extends ListView implements OnScrollListener, OnDateC
mTempDay.set(day);
final int position = (day.year - mController.getMinYear())
- * SimpleMonthAdapter.MONTHS_IN_YEAR + day.month;
+ * MonthAdapter.MONTHS_IN_YEAR + day.month;
View child;
int i = 0;
@@ -253,7 +253,7 @@ public class DayPickerView extends ListView implements OnScrollListener, OnDateC
@Override
public void onScroll(
AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
- SimpleMonthView child = (SimpleMonthView) view.getChildAt(0);
+ MonthView child = (MonthView) view.getChildAt(0);
if (child == null) {
return;
}
@@ -380,12 +380,12 @@ public class DayPickerView extends ListView implements OnScrollListener, OnDateC
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
- if (child instanceof SimpleMonthView) {
- final CalendarDay focus = ((SimpleMonthView) child).getAccessibilityFocus();
+ if (child instanceof MonthView) {
+ final CalendarDay focus = ((MonthView) child).getAccessibilityFocus();
if (focus != null) {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
// Clear focus to avoid ListView bug in Jelly Bean MR1.
- ((SimpleMonthView) child).clearAccessibilityFocus();
+ ((MonthView) child).clearAccessibilityFocus();
}
return focus;
}
@@ -410,8 +410,8 @@ public class DayPickerView extends ListView implements OnScrollListener, OnDateC
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
- if (child instanceof SimpleMonthView) {
- if (((SimpleMonthView) child).restoreAccessibilityFocus(day)) {
+ if (child instanceof MonthView) {
+ if (((MonthView) child).restoreAccessibilityFocus(day)) {
return true;
}
}
diff --git a/src/com/android/datetimepicker/date/MonthAdapter.java b/src/com/android/datetimepicker/date/MonthAdapter.java
new file mode 100644
index 0000000..098bb9e
--- /dev/null
+++ b/src/com/android/datetimepicker/date/MonthAdapter.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.datetimepicker.date;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.text.format.Time;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView.LayoutParams;
+import android.widget.BaseAdapter;
+
+import com.android.datetimepicker.date.MonthView.OnDayClickListener;
+
+import java.util.Calendar;
+import java.util.HashMap;
+
+/**
+ * An adapter for a list of {@link MonthView} items.
+ */
+public abstract class MonthAdapter extends BaseAdapter implements OnDayClickListener {
+
+ private static final String TAG = "SimpleMonthAdapter";
+
+ private final Context mContext;
+ private final DatePickerController mController;
+
+ private CalendarDay mSelectedDay;
+
+ protected static int WEEK_7_OVERHANG_HEIGHT = 7;
+ protected static final int MONTHS_IN_YEAR = 12;
+
+ /**
+ * A convenience class to represent a specific date.
+ */
+ public static class CalendarDay {
+ private Calendar calendar;
+ private Time time;
+ int year;
+ int month;
+ int day;
+
+ public CalendarDay() {
+ setTime(System.currentTimeMillis());
+ }
+
+ public CalendarDay(long timeInMillis) {
+ setTime(timeInMillis);
+ }
+
+ public CalendarDay(Calendar calendar) {
+ year = calendar.get(Calendar.YEAR);
+ month = calendar.get(Calendar.MONTH);
+ day = calendar.get(Calendar.DAY_OF_MONTH);
+ }
+
+ public CalendarDay(int year, int month, int day) {
+ setDay(year, month, day);
+ }
+
+ public void set(CalendarDay date) {
+ year = date.year;
+ month = date.month;
+ day = date.day;
+ }
+
+ public void setDay(int year, int month, int day) {
+ this.year = year;
+ this.month = month;
+ this.day = day;
+ }
+
+ public synchronized void setJulianDay(int julianDay) {
+ if (time == null) {
+ time = new Time();
+ }
+ time.setJulianDay(julianDay);
+ setTime(time.toMillis(false));
+ }
+
+ private void setTime(long timeInMillis) {
+ if (calendar == null) {
+ calendar = Calendar.getInstance();
+ }
+ calendar.setTimeInMillis(timeInMillis);
+ month = calendar.get(Calendar.MONTH);
+ year = calendar.get(Calendar.YEAR);
+ day = calendar.get(Calendar.DAY_OF_MONTH);
+ }
+ }
+
+ public MonthAdapter(Context context,
+ DatePickerController controller) {
+ mContext = context;
+ mController = controller;
+ init();
+ setSelectedDay(mController.getSelectedDay());
+ }
+
+ /**
+ * Updates the selected day and related parameters.
+ *
+ * @param day The day to highlight
+ */
+ public void setSelectedDay(CalendarDay day) {
+ mSelectedDay = day;
+ notifyDataSetChanged();
+ }
+
+ public CalendarDay getSelectedDay() {
+ return mSelectedDay;
+ }
+
+ /**
+ * Set up the gesture detector and selected time
+ */
+ protected void init() {
+ mSelectedDay = new CalendarDay(System.currentTimeMillis());
+ }
+
+ @Override
+ public int getCount() {
+ return ((mController.getMaxYear() - mController.getMinYear()) + 1) * MONTHS_IN_YEAR;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ @SuppressLint("NewApi")
+ @SuppressWarnings("unchecked")
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ MonthView v;
+ HashMap<String, Integer> drawingParams = null;
+ if (convertView != null) {
+ v = (MonthView) convertView;
+ // We store the drawing parameters in the view so it can be recycled
+ drawingParams = (HashMap<String, Integer>) v.getTag();
+ } else {
+ v = createMonthView(mContext);
+ // Set up the new view
+ LayoutParams params = new LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ v.setLayoutParams(params);
+ v.setClickable(true);
+ v.setOnDayClickListener(this);
+ }
+ if (drawingParams == null) {
+ drawingParams = new HashMap<String, Integer>();
+ }
+ drawingParams.clear();
+
+ final int month = position % MONTHS_IN_YEAR;
+ final int year = position / MONTHS_IN_YEAR + mController.getMinYear();
+
+ int selectedDay = -1;
+ if (isSelectedDayInMonth(year, month)) {
+ selectedDay = mSelectedDay.day;
+ }
+
+ // Invokes requestLayout() to ensure that the recycled view is set with the appropriate
+ // height/number of weeks before being displayed.
+ v.reuse();
+
+ drawingParams.put(MonthView.VIEW_PARAMS_SELECTED_DAY, selectedDay);
+ drawingParams.put(MonthView.VIEW_PARAMS_YEAR, year);
+ drawingParams.put(MonthView.VIEW_PARAMS_MONTH, month);
+ drawingParams.put(MonthView.VIEW_PARAMS_WEEK_START, mController.getFirstDayOfWeek());
+ v.setMonthParams(drawingParams);
+ v.invalidate();
+ return v;
+ }
+
+ public abstract MonthView createMonthView(Context context);
+
+ private boolean isSelectedDayInMonth(int year, int month) {
+ return mSelectedDay.year == year && mSelectedDay.month == month;
+ }
+
+
+ @Override
+ public void onDayClick(MonthView view, CalendarDay day) {
+ if (day != null) {
+ onDayTapped(day);
+ }
+ }
+
+ /**
+ * Maintains the same hour/min/sec but moves the day to the tapped day.
+ *
+ * @param day The day that was tapped
+ */
+ protected void onDayTapped(CalendarDay day) {
+ mController.tryVibrate();
+ mController.onDayOfMonthSelected(day.year, day.month, day.day);
+ setSelectedDay(day);
+ }
+}
diff --git a/src/com/android/datetimepicker/date/MonthView.java b/src/com/android/datetimepicker/date/MonthView.java
new file mode 100644
index 0000000..05e754c
--- /dev/null
+++ b/src/com/android/datetimepicker/date/MonthView.java
@@ -0,0 +1,688 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.datetimepicker.date;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.Paint.Style;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v4.widget.ExploreByTouchHelper;
+import android.text.format.DateFormat;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import com.android.datetimepicker.R;
+import com.android.datetimepicker.Utils;
+import com.android.datetimepicker.date.MonthAdapter.CalendarDay;
+
+import java.security.InvalidParameterException;
+import java.util.Calendar;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * A calendar-like view displaying a specified month and the appropriate selectable day numbers
+ * within the specified month.
+ */
+public abstract class MonthView extends View {
+ private static final String TAG = "MonthView";
+
+ /**
+ * These params can be passed into the view to control how it appears.
+ * {@link #VIEW_PARAMS_WEEK} is the only required field, though the default
+ * values are unlikely to fit most layouts correctly.
+ */
+ /**
+ * This sets the height of this week in pixels
+ */
+ public static final String VIEW_PARAMS_HEIGHT = "height";
+ /**
+ * This specifies the position (or weeks since the epoch) of this week,
+ * calculated using {@link Utils#getWeeksSinceEpochFromJulianDay}
+ */
+ public static final String VIEW_PARAMS_MONTH = "month";
+ /**
+ * This specifies the position (or weeks since the epoch) of this week,
+ * calculated using {@link Utils#getWeeksSinceEpochFromJulianDay}
+ */
+ public static final String VIEW_PARAMS_YEAR = "year";
+ /**
+ * This sets one of the days in this view as selected {@link Time#SUNDAY}
+ * through {@link Time#SATURDAY}.
+ */
+ public static final String VIEW_PARAMS_SELECTED_DAY = "selected_day";
+ /**
+ * Which day the week should start on. {@link Time#SUNDAY} through
+ * {@link Time#SATURDAY}.
+ */
+ public static final String VIEW_PARAMS_WEEK_START = "week_start";
+ /**
+ * How many days to display at a time. Days will be displayed starting with
+ * {@link #mWeekStart}.
+ */
+ public static final String VIEW_PARAMS_NUM_DAYS = "num_days";
+ /**
+ * Which month is currently in focus, as defined by {@link Time#month}
+ * [0-11].
+ */
+ public static final String VIEW_PARAMS_FOCUS_MONTH = "focus_month";
+ /**
+ * If this month should display week numbers. false if 0, true otherwise.
+ */
+ public static final String VIEW_PARAMS_SHOW_WK_NUM = "show_wk_num";
+
+ protected static int DEFAULT_HEIGHT = 32;
+ protected static int MIN_HEIGHT = 10;
+ protected static final int DEFAULT_SELECTED_DAY = -1;
+ protected static final int DEFAULT_WEEK_START = Calendar.SUNDAY;
+ protected static final int DEFAULT_NUM_DAYS = 7;
+ protected static final int DEFAULT_SHOW_WK_NUM = 0;
+ protected static final int DEFAULT_FOCUS_MONTH = -1;
+ protected static final int DEFAULT_NUM_ROWS = 6;
+ protected static final int MAX_NUM_ROWS = 6;
+
+ private static final int SELECTED_CIRCLE_ALPHA = 60;
+
+ protected static int DAY_SEPARATOR_WIDTH = 1;
+ protected static int MINI_DAY_NUMBER_TEXT_SIZE;
+ protected static int MONTH_LABEL_TEXT_SIZE;
+ protected static int MONTH_DAY_LABEL_TEXT_SIZE;
+ protected static int MONTH_HEADER_SIZE;
+ protected static int DAY_SELECTED_CIRCLE_SIZE;
+
+ // used for scaling to the device density
+ protected static float mScale = 0;
+
+ // affects the padding on the sides of this view
+ protected int mPadding = 0;
+
+ private String mDayOfWeekTypeface;
+ private String mMonthTitleTypeface;
+
+ protected Paint mMonthNumPaint;
+ protected Paint mMonthTitlePaint;
+ protected Paint mMonthTitleBGPaint;
+ protected Paint mSelectedCirclePaint;
+ protected Paint mMonthDayLabelPaint;
+
+ private final Formatter mFormatter;
+ private final StringBuilder mStringBuilder;
+
+ // The Julian day of the first day displayed by this item
+ protected int mFirstJulianDay = -1;
+ // The month of the first day in this week
+ protected int mFirstMonth = -1;
+ // The month of the last day in this week
+ protected int mLastMonth = -1;
+
+ protected int mMonth;
+
+ protected int mYear;
+ // Quick reference to the width of this view, matches parent
+ protected int mWidth;
+ // The height this view should draw at in pixels, set by height param
+ protected int mRowHeight = DEFAULT_HEIGHT;
+ // If this view contains the today
+ protected boolean mHasToday = false;
+ // Which day is selected [0-6] or -1 if no day is selected
+ protected int mSelectedDay = -1;
+ // Which day is today [0-6] or -1 if no day is today
+ protected int mToday = DEFAULT_SELECTED_DAY;
+ // Which day of the week to start on [0-6]
+ protected int mWeekStart = DEFAULT_WEEK_START;
+ // How many days to display
+ protected int mNumDays = DEFAULT_NUM_DAYS;
+ // The number of days + a spot for week number if it is displayed
+ protected int mNumCells = mNumDays;
+ // The left edge of the selected day
+ protected int mSelectedLeft = -1;
+ // The right edge of the selected day
+ protected int mSelectedRight = -1;
+
+ private final Calendar mCalendar;
+ private final Calendar mDayLabelCalendar;
+ private final MonthViewTouchHelper mTouchHelper;
+
+ private int mNumRows = DEFAULT_NUM_ROWS;
+
+ // Optional listener for handling day click actions
+ private OnDayClickListener mOnDayClickListener;
+ // Whether to prevent setting the accessibility delegate
+ private boolean mLockAccessibilityDelegate;
+
+ protected int mDayTextColor;
+ protected int mTodayNumberColor;
+ protected int mMonthTitleColor;
+ protected int mMonthTitleBGColor;
+
+ public MonthView(Context context) {
+ super(context);
+
+ Resources res = context.getResources();
+
+ mDayLabelCalendar = Calendar.getInstance();
+ mCalendar = Calendar.getInstance();
+
+ mDayOfWeekTypeface = res.getString(R.string.day_of_week_label_typeface);
+ mMonthTitleTypeface = res.getString(R.string.sans_serif);
+
+ mDayTextColor = res.getColor(R.color.date_picker_text_normal);
+ mTodayNumberColor = res.getColor(R.color.blue);
+ mMonthTitleColor = res.getColor(R.color.white);
+ mMonthTitleBGColor = res.getColor(R.color.circle_background);
+
+ mStringBuilder = new StringBuilder(50);
+ mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
+
+ MINI_DAY_NUMBER_TEXT_SIZE = res.getDimensionPixelSize(R.dimen.day_number_size);
+ MONTH_LABEL_TEXT_SIZE = res.getDimensionPixelSize(R.dimen.month_label_size);
+ MONTH_DAY_LABEL_TEXT_SIZE = res.getDimensionPixelSize(R.dimen.month_day_label_text_size);
+ MONTH_HEADER_SIZE = res.getDimensionPixelOffset(R.dimen.month_list_item_header_height);
+ DAY_SELECTED_CIRCLE_SIZE = res
+ .getDimensionPixelSize(R.dimen.day_number_select_circle_radius);
+
+ mRowHeight = (res.getDimensionPixelOffset(R.dimen.date_picker_view_animator_height)
+ - MONTH_HEADER_SIZE) / MAX_NUM_ROWS;
+
+ // Set up accessibility components.
+ mTouchHelper = new MonthViewTouchHelper(this);
+ ViewCompat.setAccessibilityDelegate(this, mTouchHelper);
+ ViewCompat.setImportantForAccessibility(this, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ mLockAccessibilityDelegate = true;
+
+ // Sets up any standard paints that will be used
+ initView();
+ }
+
+ @Override
+ public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
+ // Workaround for a JB MR1 issue where accessibility delegates on
+ // top-level ListView items are overwritten.
+ if (!mLockAccessibilityDelegate) {
+ super.setAccessibilityDelegate(delegate);
+ }
+ }
+
+ public void setOnDayClickListener(OnDayClickListener listener) {
+ mOnDayClickListener = listener;
+ }
+
+ @Override
+ public boolean dispatchHoverEvent(MotionEvent event) {
+ // First right-of-refusal goes the touch exploration helper.
+ if (mTouchHelper.dispatchHoverEvent(event)) {
+ return true;
+ }
+ return super.dispatchHoverEvent(event);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_UP:
+ final int day = getDayFromLocation(event.getX(), event.getY());
+ if (day >= 0) {
+ onDayClick(day);
+ }
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Sets up the text and style properties for painting. Override this if you
+ * want to use a different paint.
+ */
+ protected void initView() {
+ mMonthTitlePaint = new Paint();
+ mMonthTitlePaint.setFakeBoldText(true);
+ mMonthTitlePaint.setAntiAlias(true);
+ mMonthTitlePaint.setTextSize(MONTH_LABEL_TEXT_SIZE);
+ mMonthTitlePaint.setTypeface(Typeface.create(mMonthTitleTypeface, Typeface.BOLD));
+ mMonthTitlePaint.setColor(mDayTextColor);
+ mMonthTitlePaint.setTextAlign(Align.CENTER);
+ mMonthTitlePaint.setStyle(Style.FILL);
+
+ mMonthTitleBGPaint = new Paint();
+ mMonthTitleBGPaint.setFakeBoldText(true);
+ mMonthTitleBGPaint.setAntiAlias(true);
+ mMonthTitleBGPaint.setColor(mMonthTitleBGColor);
+ mMonthTitleBGPaint.setTextAlign(Align.CENTER);
+ mMonthTitleBGPaint.setStyle(Style.FILL);
+
+ mSelectedCirclePaint = new Paint();
+ mSelectedCirclePaint.setFakeBoldText(true);
+ mSelectedCirclePaint.setAntiAlias(true);
+ mSelectedCirclePaint.setColor(mTodayNumberColor);
+ mSelectedCirclePaint.setTextAlign(Align.CENTER);
+ mSelectedCirclePaint.setStyle(Style.FILL);
+ mSelectedCirclePaint.setAlpha(SELECTED_CIRCLE_ALPHA);
+
+ mMonthDayLabelPaint = new Paint();
+ mMonthDayLabelPaint.setAntiAlias(true);
+ mMonthDayLabelPaint.setTextSize(MONTH_DAY_LABEL_TEXT_SIZE);
+ mMonthDayLabelPaint.setColor(mDayTextColor);
+ mMonthDayLabelPaint.setTypeface(Typeface.create(mDayOfWeekTypeface, Typeface.NORMAL));
+ mMonthDayLabelPaint.setStyle(Style.FILL);
+ mMonthDayLabelPaint.setTextAlign(Align.CENTER);
+ mMonthDayLabelPaint.setFakeBoldText(true);
+
+ mMonthNumPaint = new Paint();
+ mMonthNumPaint.setAntiAlias(true);
+ mMonthNumPaint.setTextSize(MINI_DAY_NUMBER_TEXT_SIZE);
+ mMonthNumPaint.setStyle(Style.FILL);
+ mMonthNumPaint.setTextAlign(Align.CENTER);
+ mMonthNumPaint.setFakeBoldText(false);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ drawMonthTitle(canvas);
+ drawMonthDayLabels(canvas);
+ drawMonthNums(canvas);
+ }
+
+ private int mDayOfWeekStart = 0;
+
+ /**
+ * Sets all the parameters for displaying this week. The only required
+ * parameter is the week number. Other parameters have a default value and
+ * will only update if a new value is included, except for focus month,
+ * which will always default to no focus month if no value is passed in. See
+ * {@link #VIEW_PARAMS_HEIGHT} for more info on parameters.
+ *
+ * @param params A map of the new parameters, see
+ * {@link #VIEW_PARAMS_HEIGHT}
+ */
+ public void setMonthParams(HashMap<String, Integer> params) {
+ if (!params.containsKey(VIEW_PARAMS_MONTH) && !params.containsKey(VIEW_PARAMS_YEAR)) {
+ throw new InvalidParameterException("You must specify month and year for this view");
+ }
+ setTag(params);
+ // We keep the current value for any params not present
+ if (params.containsKey(VIEW_PARAMS_HEIGHT)) {
+ mRowHeight = params.get(VIEW_PARAMS_HEIGHT);
+ if (mRowHeight < MIN_HEIGHT) {
+ mRowHeight = MIN_HEIGHT;
+ }
+ }
+ if (params.containsKey(VIEW_PARAMS_SELECTED_DAY)) {
+ mSelectedDay = params.get(VIEW_PARAMS_SELECTED_DAY);
+ }
+
+ // Allocate space for caching the day numbers and focus values
+ mMonth = params.get(VIEW_PARAMS_MONTH);
+ mYear = params.get(VIEW_PARAMS_YEAR);
+
+ // Figure out what day today is
+ final Time today = new Time(Time.getCurrentTimezone());
+ today.setToNow();
+ mHasToday = false;
+ mToday = -1;
+
+ mCalendar.set(Calendar.MONTH, mMonth);
+ mCalendar.set(Calendar.YEAR, mYear);
+ mCalendar.set(Calendar.DAY_OF_MONTH, 1);
+ mDayOfWeekStart = mCalendar.get(Calendar.DAY_OF_WEEK);
+
+ if (params.containsKey(VIEW_PARAMS_WEEK_START)) {
+ mWeekStart = params.get(VIEW_PARAMS_WEEK_START);
+ } else {
+ mWeekStart = mCalendar.getFirstDayOfWeek();
+ }
+
+ mNumCells = Utils.getDaysInMonth(mMonth, mYear);
+ for (int i = 0; i < mNumCells; i++) {
+ final int day = i + 1;
+ if (sameDay(day, today)) {
+ mHasToday = true;
+ mToday = day;
+ }
+ }
+ mNumRows = calculateNumRows();
+
+ // Invalidate cached accessibility information.
+ mTouchHelper.invalidateRoot();
+ }
+
+ public void reuse() {
+ mNumRows = DEFAULT_NUM_ROWS;
+ requestLayout();
+ }
+
+ private int calculateNumRows() {
+ int offset = findDayOffset();
+ int dividend = (offset + mNumCells) / mNumDays;
+ int remainder = (offset + mNumCells) % mNumDays;
+ return (dividend + (remainder > 0 ? 1 : 0));
+ }
+
+ private boolean sameDay(int day, Time today) {
+ return mYear == today.year &&
+ mMonth == today.month &&
+ day == today.monthDay;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mRowHeight * mNumRows
+ + MONTH_HEADER_SIZE);
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ mWidth = w;
+
+ // Invalidate cached accessibility information.
+ mTouchHelper.invalidateRoot();
+ }
+
+ private String getMonthAndYearString() {
+ int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR
+ | DateUtils.FORMAT_NO_MONTH_DAY;
+ mStringBuilder.setLength(0);
+ long millis = mCalendar.getTimeInMillis();
+ return DateUtils.formatDateRange(getContext(), mFormatter, millis, millis, flags,
+ Time.getCurrentTimezone()).toString();
+ }
+
+ private void drawMonthTitle(Canvas canvas) {
+ int x = (mWidth + 2 * mPadding) / 2;
+ int y = (MONTH_HEADER_SIZE - MONTH_DAY_LABEL_TEXT_SIZE) / 2 + (MONTH_LABEL_TEXT_SIZE / 3);
+ canvas.drawText(getMonthAndYearString(), x, y, mMonthTitlePaint);
+ }
+
+ private void drawMonthDayLabels(Canvas canvas) {
+ int y = MONTH_HEADER_SIZE - (MONTH_DAY_LABEL_TEXT_SIZE / 2);
+ int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2);
+
+ for (int i = 0; i < mNumDays; i++) {
+ int calendarDay = (i + mWeekStart) % mNumDays;
+ int x = (2 * i + 1) * dayWidthHalf + mPadding;
+ mDayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay);
+ canvas.drawText(mDayLabelCalendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT,
+ Locale.getDefault()).toUpperCase(Locale.getDefault()), x, y,
+ mMonthDayLabelPaint);
+ }
+ }
+
+ /**
+ * Draws the week and month day numbers for this week. Override this method
+ * if you need different placement.
+ *
+ * @param canvas The canvas to draw on
+ */
+ protected void drawMonthNums(Canvas canvas) {
+ int y = (((mRowHeight + MINI_DAY_NUMBER_TEXT_SIZE) / 2) - DAY_SEPARATOR_WIDTH)
+ + MONTH_HEADER_SIZE;
+ int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2);
+ int j = findDayOffset();
+ for (int dayNumber = 1; dayNumber <= mNumCells; dayNumber++) {
+ int x = (2 * j + 1) * dayWidthHalf + mPadding;
+
+ int yRelativeToDay = (mRowHeight + MINI_DAY_NUMBER_TEXT_SIZE) / 2 - DAY_SEPARATOR_WIDTH;
+
+ int startX = x - dayWidthHalf;
+ int stopX = x + dayWidthHalf;
+ int startY = y - yRelativeToDay;
+ int stopY = startY + mRowHeight;
+
+ drawMonthDay(canvas, mYear, mMonth, dayNumber, x, y, startX, stopX, startY, stopY);
+
+ j++;
+ if (j == mNumDays) {
+ j = 0;
+ y += mRowHeight;
+ }
+ }
+ }
+
+ /**
+ * This method should draw the month day. Implemented by sub-classes to allow customization.
+ *
+ * @param canvas The canvas to draw on
+ * @param year The year of this month day
+ * @param month The month of this month day
+ * @param day The day number of this month day
+ * @param x The default x position to draw the day number
+ * @param y The default y position to draw the day number
+ * @param startX The left boundary of the day number rect
+ * @param stopX The right boundary of the day number rect
+ * @param startY The top boundary of the day number rect
+ * @param stopY The bottom boundary of the day number rect
+ */
+ public abstract void drawMonthDay(Canvas canvas, int year, int month, int day,
+ int x, int y, int startX, int stopX, int startY, int stopY);
+
+ private int findDayOffset() {
+ return (mDayOfWeekStart < mWeekStart ? (mDayOfWeekStart + mNumDays) : mDayOfWeekStart)
+ - mWeekStart;
+ }
+
+
+ /**
+ * Calculates the day that the given x position is in, accounting for week
+ * number. Returns the day or -1 if the position wasn't in a day.
+ *
+ * @param x The x position of the touch event
+ * @return The day number, or -1 if the position wasn't in a day
+ */
+ public int getDayFromLocation(float x, float y) {
+ int dayStart = mPadding;
+ if (x < dayStart || x > mWidth - mPadding) {
+ return -1;
+ }
+ // Selection is (x - start) / (pixels/day) == (x -s) * day / pixels
+ int row = (int) (y - MONTH_HEADER_SIZE) / mRowHeight;
+ int column = (int) ((x - dayStart) * mNumDays / (mWidth - dayStart - mPadding));
+
+ int day = column - findDayOffset() + 1;
+ day += row * mNumDays;
+ if (day < 1 || day > mNumCells) {
+ return -1;
+ }
+ return day;
+ }
+
+ /**
+ * Called when the user clicks on a day. Handles callbacks to the
+ * {@link OnDayClickListener} if one is set.
+ *
+ * @param day The day that was clicked
+ */
+ private void onDayClick(int day) {
+ if (mOnDayClickListener != null) {
+ mOnDayClickListener.onDayClick(this, new CalendarDay(mYear, mMonth, day));
+ }
+
+ // This is a no-op if accessibility is turned off.
+ mTouchHelper.sendEventForVirtualView(day, AccessibilityEvent.TYPE_VIEW_CLICKED);
+ }
+
+ /**
+ * @return The date that has accessibility focus, or {@code null} if no date
+ * has focus
+ */
+ public CalendarDay getAccessibilityFocus() {
+ final int day = mTouchHelper.getFocusedVirtualView();
+ if (day >= 0) {
+ return new CalendarDay(mYear, mMonth, day);
+ }
+ return null;
+ }
+
+ /**
+ * Clears accessibility focus within the view. No-op if the view does not
+ * contain accessibility focus.
+ */
+ public void clearAccessibilityFocus() {
+ mTouchHelper.clearFocusedVirtualView();
+ }
+
+ /**
+ * Attempts to restore accessibility focus to the specified date.
+ *
+ * @param day The date which should receive focus
+ * @return {@code false} if the date is not valid for this month view, or
+ * {@code true} if the date received focus
+ */
+ public boolean restoreAccessibilityFocus(CalendarDay day) {
+ if ((day.year != mYear) || (day.month != mMonth) || (day.day > mNumCells)) {
+ return false;
+ }
+ mTouchHelper.setFocusedVirtualView(day.day);
+ return true;
+ }
+
+ /**
+ * Provides a virtual view hierarchy for interfacing with an accessibility
+ * service.
+ */
+ private class MonthViewTouchHelper extends ExploreByTouchHelper {
+ private static final String DATE_FORMAT = "dd MMMM yyyy";
+
+ private final Rect mTempRect = new Rect();
+ private final Calendar mTempCalendar = Calendar.getInstance();
+
+ public MonthViewTouchHelper(View host) {
+ super(host);
+ }
+
+ public void setFocusedVirtualView(int virtualViewId) {
+ getAccessibilityNodeProvider(MonthView.this).performAction(
+ virtualViewId, AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS, null);
+ }
+
+ public void clearFocusedVirtualView() {
+ final int focusedVirtualView = getFocusedVirtualView();
+ if (focusedVirtualView != ExploreByTouchHelper.INVALID_ID) {
+ getAccessibilityNodeProvider(MonthView.this).performAction(
+ focusedVirtualView,
+ AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS,
+ null);
+ }
+ }
+
+ @Override
+ protected int getVirtualViewAt(float x, float y) {
+ final int day = getDayFromLocation(x, y);
+ if (day >= 0) {
+ return day;
+ }
+ return ExploreByTouchHelper.INVALID_ID;
+ }
+
+ @Override
+ protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
+ for (int day = 1; day <= mNumCells; day++) {
+ virtualViewIds.add(day);
+ }
+ }
+
+ @Override
+ protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
+ event.setContentDescription(getItemDescription(virtualViewId));
+ }
+
+ @Override
+ protected void onPopulateNodeForVirtualView(int virtualViewId,
+ AccessibilityNodeInfoCompat node) {
+ getItemBounds(virtualViewId, mTempRect);
+
+ node.setContentDescription(getItemDescription(virtualViewId));
+ node.setBoundsInParent(mTempRect);
+ node.addAction(AccessibilityNodeInfo.ACTION_CLICK);
+
+ if (virtualViewId == mSelectedDay) {
+ node.setSelected(true);
+ }
+
+ }
+
+ @Override
+ protected boolean onPerformActionForVirtualView(int virtualViewId, int action,
+ Bundle arguments) {
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_CLICK:
+ onDayClick(virtualViewId);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Calculates the bounding rectangle of a given time object.
+ *
+ * @param day The day to calculate bounds for
+ * @param rect The rectangle in which to store the bounds
+ */
+ private void getItemBounds(int day, Rect rect) {
+ final int offsetX = mPadding;
+ final int offsetY = MONTH_HEADER_SIZE;
+ final int cellHeight = mRowHeight;
+ final int cellWidth = ((mWidth - (2 * mPadding)) / mNumDays);
+ final int index = ((day - 1) + findDayOffset());
+ final int row = (index / mNumDays);
+ final int column = (index % mNumDays);
+ final int x = (offsetX + (column * cellWidth));
+ final int y = (offsetY + (row * cellHeight));
+
+ rect.set(x, y, (x + cellWidth), (y + cellHeight));
+ }
+
+ /**
+ * Generates a description for a given time object. Since this
+ * description will be spoken, the components are ordered by descending
+ * specificity as DAY MONTH YEAR.
+ *
+ * @param day The day to generate a description for
+ * @return A description of the time object
+ */
+ private CharSequence getItemDescription(int day) {
+ mTempCalendar.set(mYear, mMonth, day);
+ final CharSequence date = DateFormat.format(DATE_FORMAT,
+ mTempCalendar.getTimeInMillis());
+
+ if (day == mSelectedDay) {
+ return getContext().getString(R.string.item_is_selected, date);
+ }
+
+ return date;
+ }
+ }
+
+ /**
+ * Handles callbacks when the user clicks on a time object.
+ */
+ public interface OnDayClickListener {
+ public void onDayClick(MonthView view, CalendarDay day);
+ }
+}
diff --git a/src/com/android/datetimepicker/date/SimpleDayPickerView.java b/src/com/android/datetimepicker/date/SimpleDayPickerView.java
new file mode 100644
index 0000000..658c8a2
--- /dev/null
+++ b/src/com/android/datetimepicker/date/SimpleDayPickerView.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.datetimepicker.date;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+/**
+ * A DayPickerView customized for {@link SimpleMonthAdapter}
+ */
+public class SimpleDayPickerView extends DayPickerView {
+
+ public SimpleDayPickerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public SimpleDayPickerView(Context context, DatePickerController controller) {
+ super(context, controller);
+ }
+
+ @Override
+ public MonthAdapter createMonthAdapter(Context context, DatePickerController controller) {
+ return new SimpleMonthAdapter(context, controller);
+ }
+
+}
diff --git a/src/com/android/datetimepicker/date/SimpleMonthAdapter.java b/src/com/android/datetimepicker/date/SimpleMonthAdapter.java
index b8d13d8..b49b135 100644
--- a/src/com/android/datetimepicker/date/SimpleMonthAdapter.java
+++ b/src/com/android/datetimepicker/date/SimpleMonthAdapter.java
@@ -16,209 +16,19 @@
package com.android.datetimepicker.date;
-import android.annotation.SuppressLint;
import android.content.Context;
-import android.text.format.Time;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AbsListView.LayoutParams;
-import android.widget.BaseAdapter;
-
-import com.android.datetimepicker.date.SimpleMonthView.OnDayClickListener;
-
-import java.util.Calendar;
-import java.util.HashMap;
/**
* An adapter for a list of {@link SimpleMonthView} items.
*/
-public class SimpleMonthAdapter extends BaseAdapter implements OnDayClickListener {
-
- private static final String TAG = "SimpleMonthAdapter";
-
- private final Context mContext;
- private final DatePickerController mController;
-
- private CalendarDay mSelectedDay;
-
- protected static int WEEK_7_OVERHANG_HEIGHT = 7;
- protected static final int MONTHS_IN_YEAR = 12;
-
- /**
- * A convenience class to represent a specific date.
- */
- public static class CalendarDay {
- private Calendar calendar;
- private Time time;
- int year;
- int month;
- int day;
-
- public CalendarDay() {
- setTime(System.currentTimeMillis());
- }
-
- public CalendarDay(long timeInMillis) {
- setTime(timeInMillis);
- }
-
- public CalendarDay(Calendar calendar) {
- year = calendar.get(Calendar.YEAR);
- month = calendar.get(Calendar.MONTH);
- day = calendar.get(Calendar.DAY_OF_MONTH);
- }
-
- public CalendarDay(int year, int month, int day) {
- setDay(year, month, day);
- }
-
- public void set(CalendarDay date) {
- year = date.year;
- month = date.month;
- day = date.day;
- }
-
- public void setDay(int year, int month, int day) {
- this.year = year;
- this.month = month;
- this.day = day;
- }
-
- public void setJulianDay(int julianDay) {
- if (time == null) {
- time = new Time();
- }
- time.setJulianDay(julianDay);
- setTime(time.toMillis(false));
- }
-
- private void setTime(long timeInMillis) {
- if (calendar == null) {
- calendar = Calendar.getInstance();
- }
- calendar.setTimeInMillis(timeInMillis);
- month = calendar.get(Calendar.MONTH);
- year = calendar.get(Calendar.YEAR);
- day = calendar.get(Calendar.DAY_OF_MONTH);
- }
- }
-
- public SimpleMonthAdapter(Context context,
- DatePickerController controller) {
- mContext = context;
- mController = controller;
- init();
- setSelectedDay(mController.getSelectedDay());
- }
-
- /**
- * Updates the selected day and related parameters.
- *
- * @param day The day to highlight
- */
- public void setSelectedDay(CalendarDay day) {
- mSelectedDay = day;
- notifyDataSetChanged();
- }
-
- public CalendarDay getSelectedDay() {
- return mSelectedDay;
- }
-
- /**
- * Set up the gesture detector and selected time
- */
- protected void init() {
- mSelectedDay = new CalendarDay(System.currentTimeMillis());
- }
-
- @Override
- public int getCount() {
- return ((mController.getMaxYear() - mController.getMinYear()) + 1) * MONTHS_IN_YEAR;
- }
-
- @Override
- public Object getItem(int position) {
- return null;
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
+public class SimpleMonthAdapter extends MonthAdapter {
- @Override
- public boolean hasStableIds() {
- return true;
+ public SimpleMonthAdapter(Context context, DatePickerController controller) {
+ super(context, controller);
}
- @SuppressLint("NewApi")
- @SuppressWarnings("unchecked")
@Override
- public View getView(int position, View convertView, ViewGroup parent) {
- SimpleMonthView v;
- HashMap<String, Integer> drawingParams = null;
- if (convertView != null) {
- v = (SimpleMonthView) convertView;
- // We store the drawing parameters in the view so it can be recycled
- drawingParams = (HashMap<String, Integer>) v.getTag();
- } else {
- v = new SimpleMonthView(mContext);
- // Set up the new view
- LayoutParams params = new LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
- v.setLayoutParams(params);
- v.setClickable(true);
- v.setOnDayClickListener(this);
- }
- if (drawingParams == null) {
- drawingParams = new HashMap<String, Integer>();
- }
- drawingParams.clear();
-
- final int month = position % MONTHS_IN_YEAR;
- final int year = position / MONTHS_IN_YEAR + mController.getMinYear();
- Log.d(TAG, "Year: " + year + ", Month: " + month);
-
- int selectedDay = -1;
- if (isSelectedDayInMonth(year, month)) {
- selectedDay = mSelectedDay.day;
- }
-
- // Invokes requestLayout() to ensure that the recycled view is set with the appropriate
- // height/number of weeks before being displayed.
- v.reuse();
-
- drawingParams.put(SimpleMonthView.VIEW_PARAMS_SELECTED_DAY, selectedDay);
- drawingParams.put(SimpleMonthView.VIEW_PARAMS_YEAR, year);
- drawingParams.put(SimpleMonthView.VIEW_PARAMS_MONTH, month);
- drawingParams.put(SimpleMonthView.VIEW_PARAMS_WEEK_START, mController.getFirstDayOfWeek());
- v.setMonthParams(drawingParams);
- v.invalidate();
- return v;
- }
-
- private boolean isSelectedDayInMonth(int year, int month) {
- return mSelectedDay.year == year && mSelectedDay.month == month;
- }
-
-
- @Override
- public void onDayClick(SimpleMonthView view, CalendarDay day) {
- if (day != null) {
- onDayTapped(day);
- }
- }
-
- /**
- * Maintains the same hour/min/sec but moves the day to the tapped day.
- *
- * @param day The day that was tapped
- */
- protected void onDayTapped(CalendarDay day) {
- mController.tryVibrate();
- mController.onDayOfMonthSelected(day.year, day.month, day.day);
- setSelectedDay(day);
+ public MonthView createMonthView(Context context) {
+ return new SimpleMonthView(context);
}
}
diff --git a/src/com/android/datetimepicker/date/SimpleMonthView.java b/src/com/android/datetimepicker/date/SimpleMonthView.java
index 9d88117..6939fa8 100644
--- a/src/com/android/datetimepicker/date/SimpleMonthView.java
+++ b/src/com/android/datetimepicker/date/SimpleMonthView.java
@@ -17,651 +17,27 @@
package com.android.datetimepicker.date;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
-import android.graphics.Paint.Style;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.os.Bundle;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.widget.ExploreByTouchHelper;
-import android.text.format.DateFormat;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-import com.android.datetimepicker.R;
-import com.android.datetimepicker.Utils;
-import com.android.datetimepicker.date.SimpleMonthAdapter.CalendarDay;
-
-import java.security.InvalidParameterException;
-import java.util.Calendar;
-import java.util.Formatter;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * A calendar-like view displaying a specified month and the appropriate selectable day numbers
- * within the specified month.
- */
-public class SimpleMonthView extends View {
- private static final String TAG = "SimpleMonthView";
-
- /**
- * These params can be passed into the view to control how it appears.
- * {@link #VIEW_PARAMS_WEEK} is the only required field, though the default
- * values are unlikely to fit most layouts correctly.
- */
- /**
- * This sets the height of this week in pixels
- */
- public static final String VIEW_PARAMS_HEIGHT = "height";
- /**
- * This specifies the position (or weeks since the epoch) of this week,
- * calculated using {@link Utils#getWeeksSinceEpochFromJulianDay}
- */
- public static final String VIEW_PARAMS_MONTH = "month";
- /**
- * This specifies the position (or weeks since the epoch) of this week,
- * calculated using {@link Utils#getWeeksSinceEpochFromJulianDay}
- */
- public static final String VIEW_PARAMS_YEAR = "year";
- /**
- * This sets one of the days in this view as selected {@link Time#SUNDAY}
- * through {@link Time#SATURDAY}.
- */
- public static final String VIEW_PARAMS_SELECTED_DAY = "selected_day";
- /**
- * Which day the week should start on. {@link Time#SUNDAY} through
- * {@link Time#SATURDAY}.
- */
- public static final String VIEW_PARAMS_WEEK_START = "week_start";
- /**
- * How many days to display at a time. Days will be displayed starting with
- * {@link #mWeekStart}.
- */
- public static final String VIEW_PARAMS_NUM_DAYS = "num_days";
- /**
- * Which month is currently in focus, as defined by {@link Time#month}
- * [0-11].
- */
- public static final String VIEW_PARAMS_FOCUS_MONTH = "focus_month";
- /**
- * If this month should display week numbers. false if 0, true otherwise.
- */
- public static final String VIEW_PARAMS_SHOW_WK_NUM = "show_wk_num";
-
- protected static int DEFAULT_HEIGHT = 32;
- protected static int MIN_HEIGHT = 10;
- protected static final int DEFAULT_SELECTED_DAY = -1;
- protected static final int DEFAULT_WEEK_START = Calendar.SUNDAY;
- protected static final int DEFAULT_NUM_DAYS = 7;
- protected static final int DEFAULT_SHOW_WK_NUM = 0;
- protected static final int DEFAULT_FOCUS_MONTH = -1;
- protected static final int DEFAULT_NUM_ROWS = 6;
- protected static final int MAX_NUM_ROWS = 6;
-
- private static final int SELECTED_CIRCLE_ALPHA = 60;
-
- protected static int DAY_SEPARATOR_WIDTH = 1;
- protected static int MINI_DAY_NUMBER_TEXT_SIZE;
- protected static int MONTH_LABEL_TEXT_SIZE;
- protected static int MONTH_DAY_LABEL_TEXT_SIZE;
- protected static int MONTH_HEADER_SIZE;
- protected static int DAY_SELECTED_CIRCLE_SIZE;
-
- // used for scaling to the device density
- protected static float mScale = 0;
-
- // affects the padding on the sides of this view
- protected int mPadding = 0;
-
- private String mDayOfWeekTypeface;
- private String mMonthTitleTypeface;
-
- protected Paint mMonthNumPaint;
- protected Paint mMonthTitlePaint;
- protected Paint mMonthTitleBGPaint;
- protected Paint mSelectedCirclePaint;
- protected Paint mMonthDayLabelPaint;
-
- private final Formatter mFormatter;
- private final StringBuilder mStringBuilder;
-
- // The Julian day of the first day displayed by this item
- protected int mFirstJulianDay = -1;
- // The month of the first day in this week
- protected int mFirstMonth = -1;
- // The month of the last day in this week
- protected int mLastMonth = -1;
-
- protected int mMonth;
-
- protected int mYear;
- // Quick reference to the width of this view, matches parent
- protected int mWidth;
- // The height this view should draw at in pixels, set by height param
- protected int mRowHeight = DEFAULT_HEIGHT;
- // If this view contains the today
- protected boolean mHasToday = false;
- // Which day is selected [0-6] or -1 if no day is selected
- protected int mSelectedDay = -1;
- // Which day is today [0-6] or -1 if no day is today
- protected int mToday = DEFAULT_SELECTED_DAY;
- // Which day of the week to start on [0-6]
- protected int mWeekStart = DEFAULT_WEEK_START;
- // How many days to display
- protected int mNumDays = DEFAULT_NUM_DAYS;
- // The number of days + a spot for week number if it is displayed
- protected int mNumCells = mNumDays;
- // The left edge of the selected day
- protected int mSelectedLeft = -1;
- // The right edge of the selected day
- protected int mSelectedRight = -1;
-
- private final Calendar mCalendar;
- private final Calendar mDayLabelCalendar;
- private final MonthViewTouchHelper mTouchHelper;
-
- private int mNumRows = DEFAULT_NUM_ROWS;
-
- // Optional listener for handling day click actions
- private OnDayClickListener mOnDayClickListener;
- // Whether to prevent setting the accessibility delegate
- private boolean mLockAccessibilityDelegate;
-
- protected int mDayTextColor;
- protected int mTodayNumberColor;
- protected int mMonthTitleColor;
- protected int mMonthTitleBGColor;
+public class SimpleMonthView extends MonthView {
public SimpleMonthView(Context context) {
super(context);
-
- Resources res = context.getResources();
-
- mDayLabelCalendar = Calendar.getInstance();
- mCalendar = Calendar.getInstance();
-
- mDayOfWeekTypeface = res.getString(R.string.day_of_week_label_typeface);
- mMonthTitleTypeface = res.getString(R.string.sans_serif);
-
- mDayTextColor = res.getColor(R.color.date_picker_text_normal);
- mTodayNumberColor = res.getColor(R.color.blue);
- mMonthTitleColor = res.getColor(R.color.white);
- mMonthTitleBGColor = res.getColor(R.color.circle_background);
-
- mStringBuilder = new StringBuilder(50);
- mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
-
- MINI_DAY_NUMBER_TEXT_SIZE = res.getDimensionPixelSize(R.dimen.day_number_size);
- MONTH_LABEL_TEXT_SIZE = res.getDimensionPixelSize(R.dimen.month_label_size);
- MONTH_DAY_LABEL_TEXT_SIZE = res.getDimensionPixelSize(R.dimen.month_day_label_text_size);
- MONTH_HEADER_SIZE = res.getDimensionPixelOffset(R.dimen.month_list_item_header_height);
- DAY_SELECTED_CIRCLE_SIZE = res
- .getDimensionPixelSize(R.dimen.day_number_select_circle_radius);
-
- mRowHeight = (res.getDimensionPixelOffset(R.dimen.date_picker_view_animator_height)
- - MONTH_HEADER_SIZE) / MAX_NUM_ROWS;
-
- // Set up accessibility components.
- mTouchHelper = new MonthViewTouchHelper(this);
- ViewCompat.setAccessibilityDelegate(this, mTouchHelper);
- ViewCompat.setImportantForAccessibility(this, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
- mLockAccessibilityDelegate = true;
-
- // Sets up any standard paints that will be used
- initView();
- }
-
- @Override
- public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
- // Workaround for a JB MR1 issue where accessibility delegates on
- // top-level ListView items are overwritten.
- if (!mLockAccessibilityDelegate) {
- super.setAccessibilityDelegate(delegate);
- }
- }
-
- public void setOnDayClickListener(OnDayClickListener listener) {
- mOnDayClickListener = listener;
}
@Override
- public boolean dispatchHoverEvent(MotionEvent event) {
- // First right-of-refusal goes the touch exploration helper.
- if (mTouchHelper.dispatchHoverEvent(event)) {
- return true;
+ public void drawMonthDay(Canvas canvas, int year, int month, int day,
+ int x, int y, int startX, int stopX, int startY, int stopY) {
+ if (mSelectedDay == day) {
+ canvas.drawCircle(x , y - (MINI_DAY_NUMBER_TEXT_SIZE / 3), DAY_SELECTED_CIRCLE_SIZE,
+ mSelectedCirclePaint);
}
- return super.dispatchHoverEvent(event);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- final int day = getDayFromLocation(event.getX(), event.getY());
- if (day >= 0) {
- onDayClick(day);
- }
- break;
- }
- return true;
- }
-
- /**
- * Sets up the text and style properties for painting. Override this if you
- * want to use a different paint.
- */
- protected void initView() {
- mMonthTitlePaint = new Paint();
- mMonthTitlePaint.setFakeBoldText(true);
- mMonthTitlePaint.setAntiAlias(true);
- mMonthTitlePaint.setTextSize(MONTH_LABEL_TEXT_SIZE);
- mMonthTitlePaint.setTypeface(Typeface.create(mMonthTitleTypeface, Typeface.BOLD));
- mMonthTitlePaint.setColor(mDayTextColor);
- mMonthTitlePaint.setTextAlign(Align.CENTER);
- mMonthTitlePaint.setStyle(Style.FILL);
-
- mMonthTitleBGPaint = new Paint();
- mMonthTitleBGPaint.setFakeBoldText(true);
- mMonthTitleBGPaint.setAntiAlias(true);
- mMonthTitleBGPaint.setColor(mMonthTitleBGColor);
- mMonthTitleBGPaint.setTextAlign(Align.CENTER);
- mMonthTitleBGPaint.setStyle(Style.FILL);
-
- mSelectedCirclePaint = new Paint();
- mSelectedCirclePaint.setFakeBoldText(true);
- mSelectedCirclePaint.setAntiAlias(true);
- mSelectedCirclePaint.setColor(mTodayNumberColor);
- mSelectedCirclePaint.setTextAlign(Align.CENTER);
- mSelectedCirclePaint.setStyle(Style.FILL);
- mSelectedCirclePaint.setAlpha(SELECTED_CIRCLE_ALPHA);
-
- mMonthDayLabelPaint = new Paint();
- mMonthDayLabelPaint.setAntiAlias(true);
- mMonthDayLabelPaint.setTextSize(MONTH_DAY_LABEL_TEXT_SIZE);
- mMonthDayLabelPaint.setColor(mDayTextColor);
- mMonthDayLabelPaint.setTypeface(Typeface.create(mDayOfWeekTypeface, Typeface.NORMAL));
- mMonthDayLabelPaint.setStyle(Style.FILL);
- mMonthDayLabelPaint.setTextAlign(Align.CENTER);
- mMonthDayLabelPaint.setFakeBoldText(true);
-
- mMonthNumPaint = new Paint();
- mMonthNumPaint.setAntiAlias(true);
- mMonthNumPaint.setTextSize(MINI_DAY_NUMBER_TEXT_SIZE);
- mMonthNumPaint.setStyle(Style.FILL);
- mMonthNumPaint.setTextAlign(Align.CENTER);
- mMonthNumPaint.setFakeBoldText(false);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- drawMonthTitle(canvas);
- drawMonthDayLabels(canvas);
- drawMonthNums(canvas);
- }
-
- private int mDayOfWeekStart = 0;
-
- /**
- * Sets all the parameters for displaying this week. The only required
- * parameter is the week number. Other parameters have a default value and
- * will only update if a new value is included, except for focus month,
- * which will always default to no focus month if no value is passed in. See
- * {@link #VIEW_PARAMS_HEIGHT} for more info on parameters.
- *
- * @param params A map of the new parameters, see
- * {@link #VIEW_PARAMS_HEIGHT}
- */
- public void setMonthParams(HashMap<String, Integer> params) {
- if (!params.containsKey(VIEW_PARAMS_MONTH) && !params.containsKey(VIEW_PARAMS_YEAR)) {
- throw new InvalidParameterException("You must specify the month and year for this view");
- }
- setTag(params);
- // We keep the current value for any params not present
- if (params.containsKey(VIEW_PARAMS_HEIGHT)) {
- mRowHeight = params.get(VIEW_PARAMS_HEIGHT);
- if (mRowHeight < MIN_HEIGHT) {
- mRowHeight = MIN_HEIGHT;
- }
- }
- if (params.containsKey(VIEW_PARAMS_SELECTED_DAY)) {
- mSelectedDay = params.get(VIEW_PARAMS_SELECTED_DAY);
- }
-
- // Allocate space for caching the day numbers and focus values
- mMonth = params.get(VIEW_PARAMS_MONTH);
- mYear = params.get(VIEW_PARAMS_YEAR);
-
- // Figure out what day today is
- final Time today = new Time(Time.getCurrentTimezone());
- today.setToNow();
- mHasToday = false;
- mToday = -1;
-
- mCalendar.set(Calendar.MONTH, mMonth);
- mCalendar.set(Calendar.YEAR, mYear);
- mCalendar.set(Calendar.DAY_OF_MONTH, 1);
- mDayOfWeekStart = mCalendar.get(Calendar.DAY_OF_WEEK);
- if (params.containsKey(VIEW_PARAMS_WEEK_START)) {
- mWeekStart = params.get(VIEW_PARAMS_WEEK_START);
+ if (mHasToday && mToday == day) {
+ mMonthNumPaint.setColor(mTodayNumberColor);
} else {
- mWeekStart = mCalendar.getFirstDayOfWeek();
- }
-
- mNumCells = Utils.getDaysInMonth(mMonth, mYear);
- for (int i = 0; i < mNumCells; i++) {
- final int day = i + 1;
- if (sameDay(day, today)) {
- mHasToday = true;
- mToday = day;
- }
- }
- mNumRows = calculateNumRows();
-
- // Invalidate cached accessibility information.
- mTouchHelper.invalidateRoot();
- }
-
- public void reuse() {
- mNumRows = DEFAULT_NUM_ROWS;
- requestLayout();
- }
-
- private int calculateNumRows() {
- int offset = findDayOffset();
- int dividend = (offset + mNumCells) / mNumDays;
- int remainder = (offset + mNumCells) % mNumDays;
- return (dividend + (remainder > 0 ? 1 : 0));
- }
-
- private boolean sameDay(int day, Time today) {
- return mYear == today.year &&
- mMonth == today.month &&
- day == today.monthDay;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mRowHeight * mNumRows
- + MONTH_HEADER_SIZE);
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- mWidth = w;
-
- // Invalidate cached accessibility information.
- mTouchHelper.invalidateRoot();
- }
-
- private String getMonthAndYearString() {
- int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR
- | DateUtils.FORMAT_NO_MONTH_DAY;
- mStringBuilder.setLength(0);
- long millis = mCalendar.getTimeInMillis();
- return DateUtils.formatDateRange(getContext(), mFormatter, millis, millis, flags,
- Time.getCurrentTimezone()).toString();
- }
-
- private void drawMonthTitle(Canvas canvas) {
- int x = (mWidth + 2 * mPadding) / 2;
- int y = (MONTH_HEADER_SIZE - MONTH_DAY_LABEL_TEXT_SIZE) / 2 + (MONTH_LABEL_TEXT_SIZE / 3);
- canvas.drawText(getMonthAndYearString(), x, y, mMonthTitlePaint);
- }
-
- private void drawMonthDayLabels(Canvas canvas) {
- int y = MONTH_HEADER_SIZE - (MONTH_DAY_LABEL_TEXT_SIZE / 2);
- int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2);
-
- for (int i = 0; i < mNumDays; i++) {
- int calendarDay = (i + mWeekStart) % mNumDays;
- int x = (2 * i + 1) * dayWidthHalf + mPadding;
- mDayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay);
- canvas.drawText(mDayLabelCalendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT,
- Locale.getDefault()).toUpperCase(Locale.getDefault()), x, y,
- mMonthDayLabelPaint);
- }
- }
-
- /**
- * Draws the week and month day numbers for this week. Override this method
- * if you need different placement.
- *
- * @param canvas The canvas to draw on
- */
- protected void drawMonthNums(Canvas canvas) {
- int y = (((mRowHeight + MINI_DAY_NUMBER_TEXT_SIZE) / 2) - DAY_SEPARATOR_WIDTH)
- + MONTH_HEADER_SIZE;
- int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2);
- int j = findDayOffset();
- for (int dayNumber = 1; dayNumber <= mNumCells; dayNumber++) {
- int x = (2 * j + 1) * dayWidthHalf + mPadding;
- if (mSelectedDay == dayNumber) {
- canvas.drawCircle(x, y - (MINI_DAY_NUMBER_TEXT_SIZE / 3), DAY_SELECTED_CIRCLE_SIZE,
- mSelectedCirclePaint);
- }
-
- if (mHasToday && mToday == dayNumber) {
- mMonthNumPaint.setColor(mTodayNumberColor);
- } else {
- mMonthNumPaint.setColor(mDayTextColor);
- }
- canvas.drawText(String.format("%d", dayNumber), x, y, mMonthNumPaint);
- j++;
- if (j == mNumDays) {
- j = 0;
- y += mRowHeight;
- }
- }
- }
-
- private int findDayOffset() {
- return (mDayOfWeekStart < mWeekStart ? (mDayOfWeekStart + mNumDays) : mDayOfWeekStart)
- - mWeekStart;
- }
-
-
- /**
- * Calculates the day that the given x position is in, accounting for week
- * number. Returns the day or -1 if the position wasn't in a day.
- *
- * @param x The x position of the touch event
- * @return The day number, or -1 if the position wasn't in a day
- */
- public int getDayFromLocation(float x, float y) {
- int dayStart = mPadding;
- if (x < dayStart || x > mWidth - mPadding) {
- return -1;
- }
- // Selection is (x - start) / (pixels/day) == (x -s) * day / pixels
- int row = (int) (y - MONTH_HEADER_SIZE) / mRowHeight;
- int column = (int) ((x - dayStart) * mNumDays / (mWidth - dayStart - mPadding));
-
- int day = column - findDayOffset() + 1;
- day += row * mNumDays;
- if (day < 1 || day > mNumCells) {
- return -1;
- }
- return day;
- }
-
- /**
- * Called when the user clicks on a day. Handles callbacks to the
- * {@link OnDayClickListener} if one is set.
- *
- * @param day The day that was clicked
- */
- private void onDayClick(int day) {
- if (mOnDayClickListener != null) {
- mOnDayClickListener.onDayClick(this, new CalendarDay(mYear, mMonth, day));
- }
-
- // This is a no-op if accessibility is turned off.
- mTouchHelper.sendEventForVirtualView(day, AccessibilityEvent.TYPE_VIEW_CLICKED);
- }
-
- /**
- * @return The date that has accessibility focus, or {@code null} if no date
- * has focus
- */
- public CalendarDay getAccessibilityFocus() {
- final int day = mTouchHelper.getFocusedVirtualView();
- if (day >= 0) {
- return new CalendarDay(mYear, mMonth, day);
- }
- return null;
- }
-
- /**
- * Clears accessibility focus within the view. No-op if the view does not
- * contain accessibility focus.
- */
- public void clearAccessibilityFocus() {
- mTouchHelper.clearFocusedVirtualView();
- }
-
- /**
- * Attempts to restore accessibility focus to the specified date.
- *
- * @param day The date which should receive focus
- * @return {@code false} if the date is not valid for this month view, or
- * {@code true} if the date received focus
- */
- public boolean restoreAccessibilityFocus(CalendarDay day) {
- if ((day.year != mYear) || (day.month != mMonth) || (day.day > mNumCells)) {
- return false;
- }
- mTouchHelper.setFocusedVirtualView(day.day);
- return true;
- }
-
- /**
- * Provides a virtual view hierarchy for interfacing with an accessibility
- * service.
- */
- private class MonthViewTouchHelper extends ExploreByTouchHelper {
- private static final String DATE_FORMAT = "dd MMMM yyyy";
-
- private final Rect mTempRect = new Rect();
- private final Calendar mTempCalendar = Calendar.getInstance();
-
- public MonthViewTouchHelper(View host) {
- super(host);
- }
-
- public void setFocusedVirtualView(int virtualViewId) {
- getAccessibilityNodeProvider(SimpleMonthView.this).performAction(
- virtualViewId, AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS, null);
- }
-
- public void clearFocusedVirtualView() {
- final int focusedVirtualView = getFocusedVirtualView();
- if (focusedVirtualView != ExploreByTouchHelper.INVALID_ID) {
- getAccessibilityNodeProvider(SimpleMonthView.this).performAction(
- focusedVirtualView, AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
- }
- }
-
- @Override
- protected int getVirtualViewAt(float x, float y) {
- final int day = getDayFromLocation(x, y);
- if (day >= 0) {
- return day;
- }
- return ExploreByTouchHelper.INVALID_ID;
- }
-
- @Override
- protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
- for (int day = 1; day <= mNumCells; day++) {
- virtualViewIds.add(day);
- }
- }
-
- @Override
- protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
- event.setContentDescription(getItemDescription(virtualViewId));
+ mMonthNumPaint.setColor(mDayTextColor);
}
-
- @Override
- protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfoCompat node) {
- getItemBounds(virtualViewId, mTempRect);
-
- node.setContentDescription(getItemDescription(virtualViewId));
- node.setBoundsInParent(mTempRect);
- node.addAction(AccessibilityNodeInfo.ACTION_CLICK);
-
- if (virtualViewId == mSelectedDay) {
- node.setSelected(true);
- }
-
- }
-
- @Override
- protected boolean onPerformActionForVirtualView(int virtualViewId, int action, Bundle arguments) {
- switch (action) {
- case AccessibilityNodeInfo.ACTION_CLICK:
- onDayClick(virtualViewId);
- return true;
- }
-
- return false;
- }
-
- /**
- * Calculates the bounding rectangle of a given time object.
- *
- * @param day The day to calculate bounds for
- * @param rect The rectangle in which to store the bounds
- */
- private void getItemBounds(int day, Rect rect) {
- final int offsetX = mPadding;
- final int offsetY = MONTH_HEADER_SIZE;
- final int cellHeight = mRowHeight;
- final int cellWidth = ((mWidth - (2 * mPadding)) / mNumDays);
- final int index = ((day - 1) + findDayOffset());
- final int row = (index / mNumDays);
- final int column = (index % mNumDays);
- final int x = (offsetX + (column * cellWidth));
- final int y = (offsetY + (row * cellHeight));
-
- rect.set(x, y, (x + cellWidth), (y + cellHeight));
- }
-
- /**
- * Generates a description for a given time object. Since this
- * description will be spoken, the components are ordered by descending
- * specificity as DAY MONTH YEAR.
- *
- * @param day The day to generate a description for
- * @return A description of the time object
- */
- private CharSequence getItemDescription(int day) {
- mTempCalendar.set(mYear, mMonth, day);
- final CharSequence date = DateFormat.format(DATE_FORMAT, mTempCalendar.getTimeInMillis());
-
- if (day == mSelectedDay) {
- return getContext().getString(R.string.item_is_selected, date);
- }
-
- return date;
- }
- }
-
- /**
- * Handles callbacks when the user clicks on a time object.
- */
- public interface OnDayClickListener {
- public void onDayClick(SimpleMonthView view, CalendarDay day);
+ canvas.drawText(String.format("%d", day), x, y, mMonthNumPaint);
}
}