Commit e668d6b1 authored by James Kung's avatar James Kung
Browse files

Abstracting date picker classes to allow customization

Change-Id: Iaf4a61fa2c0c975ffabe21658e654939f0f29782
parent 16b29181
......@@ -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.
......
......@@ -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();
......
......@@ -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;
}
}
......
/*
* 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);
}
}
This diff is collapsed.
/*
* 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);
}
}
......@@ -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);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment