Merge "Add Wi-Fi stress tests."
diff --git a/api/current.xml b/api/current.xml
index e63e82c..cdb6964 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -184323,6 +184323,19 @@
<parameter name="gmtoff" type="long">
</parameter>
</method>
+<method name="getJulianMondayFromWeeksSinceEpoch"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="week" type="int">
+</parameter>
+</method>
<method name="getWeekNumber"
return="int"
abstract="false"
@@ -184334,6 +184347,21 @@
visibility="public"
>
</method>
+<method name="getWeeksSinceEpochFromJulianDay"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="julianDay" type="int">
+</parameter>
+<parameter name="firstDayOfWeek" type="int">
+</parameter>
+</method>
<method name="isEpoch"
return="boolean"
abstract="false"
@@ -184557,6 +184585,17 @@
visibility="public"
>
</field>
+<field name="MONDAY_BEFORE_JULIAN_EPOCH"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2440585"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MONTH"
type="int"
transient="false"
@@ -234482,7 +234521,7 @@
>
<parameter name="year" type="int">
</parameter>
-<parameter name="monthOfYear" type="int">
+<parameter name="month" type="int">
</parameter>
<parameter name="dayOfMonth" type="int">
</parameter>
@@ -234534,6 +234573,172 @@
</parameter>
</method>
</interface>
+<class name="DayPicker"
+ extends="android.widget.FrameLayout"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="DayPicker"
+ type="android.widget.DayPicker"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<constructor name="DayPicker"
+ type="android.widget.DayPicker"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+</constructor>
+<constructor name="DayPicker"
+ type="android.widget.DayPicker"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+<parameter name="defStyle" type="int">
+</parameter>
+</constructor>
+<method name="getSelectedDay"
+ return="java.util.Calendar"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="goTo"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="year" type="int">
+</parameter>
+<parameter name="month" type="int">
+</parameter>
+<parameter name="dayOfMonth" type="int">
+</parameter>
+<parameter name="animate" type="boolean">
+</parameter>
+<parameter name="setSelected" type="boolean">
+</parameter>
+<parameter name="forceScroll" type="boolean">
+</parameter>
+</method>
+<method name="goTo"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="date" type="java.util.Calendar">
+</parameter>
+<parameter name="animate" type="boolean">
+</parameter>
+<parameter name="setSelected" type="boolean">
+</parameter>
+<parameter name="forceScroll" type="boolean">
+</parameter>
+</method>
+<method name="setOnDateChangeListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.widget.DayPicker.OnSelectedDayChangeListener">
+</parameter>
+</method>
+<method name="setRange"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startRangeDate" type="java.util.Calendar">
+</parameter>
+<parameter name="endRangeDate" type="java.util.Calendar">
+</parameter>
+</method>
+<method name="setSelectedDay"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="selectedDay" type="java.util.Calendar">
+</parameter>
+</method>
+</class>
+<interface name="DayPicker.OnSelectedDayChangeListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onSelectedDayChange"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.widget.DayPicker">
+</parameter>
+<parameter name="year" type="int">
+</parameter>
+<parameter name="month" type="int">
+</parameter>
+<parameter name="dayOfMonth" type="int">
+</parameter>
+</method>
+</interface>
<class name="DialerFilter"
extends="android.widget.RelativeLayout"
abstract="false"
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 37f8738..efe527f 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -16,23 +16,18 @@
package android.app;
+import com.android.internal.R;
+
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Build;
import android.os.Bundle;
-import android.text.TextUtils.TruncateAt;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.DatePicker;
-import android.widget.TextView;
import android.widget.DatePicker.OnDateChangedListener;
-import com.android.internal.R;
-
-import java.text.DateFormatSymbols;
-import java.util.Calendar;
-
/**
* A simple dialog containing an {@link android.widget.DatePicker}.
*
@@ -48,13 +43,6 @@
private final DatePicker mDatePicker;
private final OnDateSetListener mCallBack;
- private final Calendar mCalendar;
- private final java.text.DateFormat mTitleDateFormat;
- private final String[] mWeekDays;
-
- private int mInitialYear;
- private int mInitialMonth;
- private int mInitialDay;
/**
* The callback used to indicate the user is done filling in the date.
@@ -106,40 +94,18 @@
super(context, theme);
mCallBack = callBack;
- mInitialYear = year;
- mInitialMonth = monthOfYear;
- mInitialDay = dayOfMonth;
- DateFormatSymbols symbols = new DateFormatSymbols();
- mWeekDays = symbols.getShortWeekdays();
-
- mTitleDateFormat = java.text.DateFormat.
- getDateInstance(java.text.DateFormat.FULL);
- mCalendar = Calendar.getInstance();
- updateTitle(mInitialYear, mInitialMonth, mInitialDay);
setButton(BUTTON_POSITIVE, context.getText(R.string.date_time_set), this);
setButton(BUTTON_NEGATIVE, context.getText(R.string.cancel), (OnClickListener) null);
- setIcon(R.drawable.ic_dialog_time);
+ setIcon(0);
+ setTitle(R.string.date_picker_dialog_title);
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.date_picker_dialog, null);
setView(view);
mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
- mDatePicker.init(mInitialYear, mInitialMonth, mInitialDay, this);
- }
-
- @Override
- public void show() {
- super.show();
-
- /* Sometimes the full month is displayed causing the title
- * to be very long, in those cases ensure it doesn't wrap to
- * 2 lines (as that looks jumpy) and ensure we ellipsize the end.
- */
- TextView title = (TextView) findViewById(R.id.alertTitle);
- title.setSingleLine();
- title.setEllipsize(TruncateAt.END);
+ mDatePicker.init(year, monthOfYear, dayOfMonth, this);
}
public void onClick(DialogInterface dialog, int which) {
@@ -152,23 +118,13 @@
public void onDateChanged(DatePicker view, int year,
int month, int day) {
- updateTitle(year, month, day);
+ mDatePicker.init(year, month, day, null);
}
public void updateDate(int year, int monthOfYear, int dayOfMonth) {
- mInitialYear = year;
- mInitialMonth = monthOfYear;
- mInitialDay = dayOfMonth;
mDatePicker.updateDate(year, monthOfYear, dayOfMonth);
}
- private void updateTitle(int year, int month, int day) {
- mCalendar.set(Calendar.YEAR, year);
- mCalendar.set(Calendar.MONTH, month);
- mCalendar.set(Calendar.DAY_OF_MONTH, day);
- setTitle(mTitleDateFormat.format(mCalendar.getTime()));
- }
-
@Override
public Bundle onSaveInstanceState() {
Bundle state = super.onSaveInstanceState();
@@ -185,6 +141,5 @@
int month = savedInstanceState.getInt(MONTH);
int day = savedInstanceState.getInt(DAY);
mDatePicker.init(year, month, day, this);
- updateTitle(year, month, day);
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ed71da2..1e80da7 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -977,6 +977,9 @@
public static float getFloat(ContentResolver cr, String name)
throws SettingNotFoundException {
String v = getString(cr, name);
+ if (v == null) {
+ throw new SettingNotFoundException(name);
+ }
try {
return Float.parseFloat(v);
} catch (NumberFormatException e) {
@@ -1577,7 +1580,7 @@
* Default screen rotation when no other policy applies.
* When {@link #ACCELEROMETER_ROTATION} is zero and no on-screen Activity expresses a
* preference, this rotation value will be used. Must be one of the
- * {@link android.view.Surface#ROTATION_0 Surface rotation constants}.
+ * {@link android.view.Surface#ROTATION_0 Surface rotation constants}.
*
* @see Display#getRotation
*/
@@ -2296,6 +2299,9 @@
public static float getFloat(ContentResolver cr, String name)
throws SettingNotFoundException {
String v = getString(cr, name);
+ if (v == null) {
+ throw new SettingNotFoundException(name);
+ }
try {
return Float.parseFloat(v);
} catch (NumberFormatException e) {
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index c05a8fe..c6ffe58 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -42,6 +42,12 @@
public static final int EPOCH_JULIAN_DAY = 2440588;
/**
+ * The Julian day of the Monday in the week of the epoch, December 29, 1969
+ * on the Gregorian calendar.
+ */
+ public static final int MONDAY_BEFORE_JULIAN_EPOCH = EPOCH_JULIAN_DAY - 3;
+
+ /**
* True if this is an allDay event. The hour, minute, second fields are
* all zero, and the date is displayed the same in all time zones.
*/
@@ -770,4 +776,39 @@
millis = normalize(true);
return millis;
}
+
+ /**
+ * Returns the week since {@link #EPOCH_JULIAN_DAY} (Jan 1, 1970) adjusted
+ * for first day of week. This takes a julian day and the week start day and
+ * calculates which week since {@link #EPOCH_JULIAN_DAY} that day occurs in,
+ * starting at 0. *Do not* use this to compute the ISO week number for the
+ * year.
+ *
+ * @param julianDay The julian day to calculate the week number for
+ * @param firstDayOfWeek Which week day is the first day of the week, see
+ * {@link #SUNDAY}
+ * @return Weeks since the epoch
+ */
+ public static int getWeeksSinceEpochFromJulianDay(int julianDay, int firstDayOfWeek) {
+ int diff = THURSDAY - firstDayOfWeek;
+ if (diff < 0) {
+ diff += 7;
+ }
+ int refDay = EPOCH_JULIAN_DAY - diff;
+ return (julianDay - refDay) / 7;
+ }
+
+ /**
+ * Takes a number of weeks since the epoch and calculates the Julian day of
+ * the Monday for that week. This assumes that the week containing the
+ * {@link #EPOCH_JULIAN_DAY} is considered week 0. It returns the Julian day
+ * for the Monday week weeks after the Monday of the week containing the
+ * epoch.
+ *
+ * @param week Number of weeks since the epoch
+ * @return The julian day for the Monday of the given week since the epoch
+ */
+ public static int getJulianMondayFromWeeksSinceEpoch(int week) {
+ return MONDAY_BEFORE_JULIAN_EPOCH + week * 7;
+ }
}
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 595b487..9a451cc 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -16,6 +16,8 @@
package android.widget;
+import com.android.internal.R;
+
import android.annotation.Widget;
import android.content.Context;
import android.content.res.TypedArray;
@@ -26,50 +28,44 @@
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.LayoutInflater;
-import android.widget.NumberPicker;
-import android.widget.NumberPicker.OnChangedListener;
+import android.widget.NumberPicker.OnChangeListener;
-import com.android.internal.R;
-
-import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
/**
* A view for selecting a month / year / day based on a calendar like layout.
- *
- * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date Picker
- * tutorial</a>.</p>
- *
+ * <p>
+ * See the <a href="{@docRoot}
+ * resources/tutorials/views/hello-datepicker.html">Date Picker tutorial</a>.
+ * </p>
* For a dialog using this view, see {@link android.app.DatePickerDialog}.
*/
@Widget
public class DatePicker extends FrameLayout {
private static final int DEFAULT_START_YEAR = 1900;
+
private static final int DEFAULT_END_YEAR = 2100;
- // This ignores Undecimber, but we only support real Gregorian calendars.
- private static final int NUMBER_OF_MONTHS = 12;
-
- /* UI Components */
private final NumberPicker mDayPicker;
+
private final NumberPicker mMonthPicker;
+
private final NumberPicker mYearPicker;
- /**
- * How we notify users the date has changed.
- */
- private OnDateChangedListener mOnDateChangedListener;
-
- private int mDay;
- private int mMonth;
- private int mYear;
+ private final DayPicker mMiniMonthDayPicker;
- private Object mMonthUpdateLock = new Object();
- private volatile Locale mMonthLocale;
- private String[] mShortMonths;
+ private OnDateChangedListener mOnDateChangedListener;
+
+ private Locale mMonthLocale;
+
+ private final Calendar mTempCalendar = Calendar.getInstance();
+
+ private final int mNumberOfMonths = mTempCalendar.getActualMaximum(Calendar.MONTH) + 1;
+
+ private final String[] mShortMonths = new String[mNumberOfMonths];
/**
* The callback used to indicate the user changes the date.
@@ -80,7 +76,7 @@
* @param view The view associated with this listener.
* @param year The year that was set.
* @param monthOfYear The month that was set (0-11) for compatibility
- * with {@link java.util.Calendar}.
+ * with {@link java.util.Calendar}.
* @param dayOfMonth The day of the month that was set.
*/
void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth);
@@ -89,7 +85,7 @@
public DatePicker(Context context) {
this(context, null);
}
-
+
public DatePicker(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -97,103 +93,85 @@
public DatePicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.date_picker, this, true);
+ OnChangeListener onChangeListener = new OnChangeListener() {
+ public void onChanged(NumberPicker picker, int oldVal, int newVal) {
+ notifyDateChanged();
+ updateMiniMonth();
+ }
+ };
+
+ // day
mDayPicker = (NumberPicker) findViewById(R.id.day);
mDayPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
mDayPicker.setSpeed(100);
- mDayPicker.setOnChangeListener(new OnChangedListener() {
- public void onChanged(NumberPicker picker, int oldVal, int newVal) {
- mDay = newVal;
- notifyDateChanged();
- }
- });
+ mDayPicker.setOnChangeListener(onChangeListener);
+
+ // month
mMonthPicker = (NumberPicker) findViewById(R.id.month);
- mMonthPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
- final String[] months = getShortMonths();
-
- /*
- * If the user is in a locale where the month names are numeric,
- * use just the number instead of the "month" character for
- * consistency with the other fields.
- */
- if (months[0].startsWith("1")) {
- for (int i = 0; i < months.length; i++) {
- months[i] = String.valueOf(i + 1);
- }
- mMonthPicker.setRange(1, NUMBER_OF_MONTHS);
- } else {
- mMonthPicker.setRange(1, NUMBER_OF_MONTHS, months);
- }
-
+ mMonthPicker.setRange(0, mNumberOfMonths - 1, getShortMonths());
mMonthPicker.setSpeed(200);
- mMonthPicker.setOnChangeListener(new OnChangedListener() {
- public void onChanged(NumberPicker picker, int oldVal, int newVal) {
-
- /* We display the month 1-12 but store it 0-11 so always
- * subtract by one to ensure our internal state is always 0-11
- */
- mMonth = newVal - 1;
- // Adjust max day of the month
- adjustMaxDay();
- notifyDateChanged();
- updateDaySpinner();
- }
- });
+ mMonthPicker.setOnChangeListener(onChangeListener);
+
+ // year
mYearPicker = (NumberPicker) findViewById(R.id.year);
mYearPicker.setSpeed(100);
- mYearPicker.setOnChangeListener(new OnChangedListener() {
- public void onChanged(NumberPicker picker, int oldVal, int newVal) {
- mYear = newVal;
- // Adjust max day for leap years if needed
- adjustMaxDay();
- notifyDateChanged();
- updateDaySpinner();
- }
- });
-
- // attributes
+ mYearPicker.setOnChangeListener(onChangeListener);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker);
-
int mStartYear = a.getInt(R.styleable.DatePicker_startYear, DEFAULT_START_YEAR);
int mEndYear = a.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
mYearPicker.setRange(mStartYear, mEndYear);
-
a.recycle();
+
+ // mini-month day-picker
+ mMiniMonthDayPicker = (DayPicker) findViewById(R.id.mini_month_day_picker);
+ mTempCalendar.clear();
+ mTempCalendar.set(mStartYear, 0, 1);
+ Calendar endRangeDate = (Calendar) mTempCalendar.clone();
+ endRangeDate.set(mEndYear, 11, 31);
+ mMiniMonthDayPicker.setRange(mTempCalendar, endRangeDate);
+ mMiniMonthDayPicker.setOnDateChangeListener(new DayPicker.OnSelectedDayChangeListener() {
+ public void onSelectedDayChange(DayPicker view, int year, int month, int monthDay) {
+ updateDate(year, month, monthDay);
+ }
+ });
// initialize to current date
- Calendar cal = Calendar.getInstance();
- init(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), null);
-
+ mTempCalendar.setTimeInMillis(System.currentTimeMillis());
+ init(mTempCalendar.get(Calendar.YEAR), mTempCalendar.get(Calendar.MONTH),
+ mTempCalendar.get(Calendar.DAY_OF_MONTH), null);
+
// re-order the number pickers to match the current date format
- reorderPickers(months);
-
- if (!isEnabled()) {
- setEnabled(false);
- }
+ reorderPickers();
}
-
+
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
mDayPicker.setEnabled(enabled);
mMonthPicker.setEnabled(enabled);
mYearPicker.setEnabled(enabled);
+ mMiniMonthDayPicker.setEnabled(enabled);
}
- private void reorderPickers(String[] months) {
+ /**
+ * Reorders the pickers according to the date format in the current locale.
+ */
+ private void reorderPickers() {
java.text.DateFormat format;
String order;
/*
- * If the user is in a locale where the medium date format is
- * still numeric (Japanese and Czech, for example), respect
- * the date format order setting. Otherwise, use the order
- * that the locale says is appropriate for a spelled-out date.
+ * If the user is in a locale where the medium date format is still
+ * numeric (Japanese and Czech, for example), respect the date format
+ * order setting. Otherwise, use the order that the locale says is
+ * appropriate for a spelled-out date.
*/
- if (months[0].startsWith("1")) {
+ if (getShortMonths()[0].startsWith("1")) {
format = DateFormat.getDateFormat(getContext());
} else {
format = DateFormat.getMediumDateFormat(getContext());
@@ -206,10 +184,11 @@
order = new String(DateFormat.getDateFormatOrder(getContext()));
}
- /* Remove the 3 pickers from their parent and then add them back in the
+ /*
+ * Remove the 3 pickers from their parent and then add them back in the
* required order.
*/
- LinearLayout parent = (LinearLayout) findViewById(R.id.parent);
+ LinearLayout parent = (LinearLayout) findViewById(R.id.pickers);
parent.removeAllViews();
boolean quoted = false;
@@ -230,7 +209,7 @@
parent.addView(mMonthPicker);
didMonth = true;
} else if (c == DateFormat.YEAR && !didYear) {
- parent.addView (mYearPicker);
+ parent.addView(mYearPicker);
didYear = true;
}
}
@@ -248,40 +227,145 @@
}
}
- public void updateDate(int year, int monthOfYear, int dayOfMonth) {
- if (mYear != year || mMonth != monthOfYear || mDay != dayOfMonth) {
- mYear = year;
- mMonth = monthOfYear;
- mDay = dayOfMonth;
- updateSpinners();
- reorderPickers(getShortMonths());
+ /**
+ * Updates the current date.
+ *
+ * @param year The year.
+ * @param month The month which is <strong>starting from zero</strong>.
+ * @param dayOfMonth The day of the month.
+ */
+ public void updateDate(int year, int month, int dayOfMonth) {
+ if (mYearPicker.getCurrent() != year
+ || mDayPicker.getCurrent() != dayOfMonth
+ || mMonthPicker.getCurrent() != month) {
+ updatePickers(year, month, dayOfMonth);
+ updateMiniMonth();
notifyDateChanged();
}
}
+ /**
+ * @return The short month abbreviations.
+ */
private String[] getShortMonths() {
final Locale currentLocale = Locale.getDefault();
- if (currentLocale.equals(mMonthLocale) && mShortMonths != null) {
+ if (currentLocale.equals(mMonthLocale)) {
return mShortMonths;
} else {
- synchronized (mMonthUpdateLock) {
- if (!currentLocale.equals(mMonthLocale)) {
- mShortMonths = new String[NUMBER_OF_MONTHS];
- for (int i = 0; i < NUMBER_OF_MONTHS; i++) {
- mShortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i,
- DateUtils.LENGTH_MEDIUM);
- }
- mMonthLocale = currentLocale;
- }
+ for (int i = 0; i < mNumberOfMonths; i++) {
+ mShortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i,
+ DateUtils.LENGTH_MEDIUM);
}
+ mMonthLocale = currentLocale;
return mShortMonths;
}
}
+ // Override so we are in complete control of save / restore for this widget.
+ @Override
+ protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
+ dispatchThawSelfOnly(container);
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ Parcelable superState = super.onSaveInstanceState();
+ return new SavedState(superState, mYearPicker.getCurrent(), mMonthPicker.getCurrent(),
+ mDayPicker.getCurrent());
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ SavedState ss = (SavedState) state;
+ super.onRestoreInstanceState(ss.getSuperState());
+ updatePickers(ss.mYear, ss.mMonth, ss.mDay);
+ }
+
+ /**
+ * Initialize the state. If the provided values designate an inconsistent
+ * date the values are normalized before updating the pickers.
+ *
+ * @param year The initial year.
+ * @param monthOfYear The initial month <strong>starting from zero</strong>.
+ * @param dayOfMonth The initial day of the month.
+ * @param onDateChangedListener How user is notified date is changed by
+ * user, can be null.
+ */
+ public void init(int year, int monthOfYear, int dayOfMonth,
+ OnDateChangedListener onDateChangedListener) {
+ mOnDateChangedListener = onDateChangedListener;
+ updateDate(year, monthOfYear, dayOfMonth);
+ }
+
+ /**
+ * Updates the pickers with the given <code>year</code>, <code>month</code>,
+ * and <code>dayOfMonth</code>. If the provided values designate an inconsistent
+ * date the values are normalized before updating the pickers.
+ */
+ private void updatePickers(int year, int month, int dayOfMonth) {
+ // make sure the date is normalized
+ mTempCalendar.clear();
+ mTempCalendar.set(year, month, dayOfMonth);
+ mYearPicker.setCurrent(mTempCalendar.get(Calendar.YEAR));
+ mMonthPicker.setCurrent(mTempCalendar.get(Calendar.MONTH));
+ mDayPicker.setRange(1, mTempCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));
+ mDayPicker.setCurrent(mTempCalendar.get(Calendar.DAY_OF_MONTH));
+ }
+
+ /**
+ * Updates the mini-month with the given year, month, and day selected by the
+ * number pickers.
+ */
+ private void updateMiniMonth() {
+ Calendar selectedDay = mMiniMonthDayPicker.getSelectedDay();
+ if (selectedDay.get(Calendar.YEAR) != mYearPicker.getCurrent()
+ || selectedDay.get(Calendar.MONTH) != mMonthPicker.getCurrent()
+ || selectedDay.get(Calendar.DAY_OF_MONTH) != mDayPicker.getCurrent()) {
+ mMiniMonthDayPicker.goTo(mYearPicker.getCurrent(), mMonthPicker.getCurrent(),
+ mDayPicker.getCurrent(), false, true, false);
+ }
+ }
+
+ /**
+ * @return The selected year.
+ */
+ public int getYear() {
+ return mYearPicker.getCurrent();
+ }
+
+ /**
+ * @return The selected month.
+ */
+ public int getMonth() {
+ return mMonthPicker.getCurrent();
+ }
+
+ /**
+ * @return The selected day of month.
+ */
+ public int getDayOfMonth() {
+ return mDayPicker.getCurrent();
+ }
+
+ /**
+ * Notifies the listener, if such, for a change in the selected date.
+ */
+ private void notifyDateChanged() {
+ if (mOnDateChangedListener != null) {
+ mOnDateChangedListener.onDateChanged(DatePicker.this, mYearPicker.getCurrent(),
+ mMonthPicker.getCurrent(), mDayPicker.getCurrent());
+ }
+ }
+
+ /**
+ * Class for managing state storing/restoring.
+ */
private static class SavedState extends BaseSavedState {
private final int mYear;
+
private final int mMonth;
+
private final int mDay;
/**
@@ -293,7 +377,7 @@
mMonth = month;
mDay = day;
}
-
+
/**
* Constructor called from {@link #CREATOR}
*/
@@ -304,18 +388,6 @@
mDay = in.readInt();
}
- public int getYear() {
- return mYear;
- }
-
- public int getMonth() {
- return mMonth;
- }
-
- public int getDay() {
- return mDay;
- }
-
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
@@ -324,104 +396,17 @@
dest.writeInt(mDay);
}
- public static final Parcelable.Creator<SavedState> CREATOR =
- new Creator<SavedState>() {
+ @SuppressWarnings("all")
+ // suppress unused and hiding
+ public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-
-
- /**
- * Override so we are in complete control of save / restore for this widget.
- */
- @Override
- protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
- dispatchThawSelfOnly(container);
- }
-
- @Override
- protected Parcelable onSaveInstanceState() {
- Parcelable superState = super.onSaveInstanceState();
-
- return new SavedState(superState, mYear, mMonth, mDay);
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- SavedState ss = (SavedState) state;
- super.onRestoreInstanceState(ss.getSuperState());
- mYear = ss.getYear();
- mMonth = ss.getMonth();
- mDay = ss.getDay();
- updateSpinners();
- }
-
- /**
- * Initialize the state.
- * @param year The initial year.
- * @param monthOfYear The initial month.
- * @param dayOfMonth The initial day of the month.
- * @param onDateChangedListener How user is notified date is changed by user, can be null.
- */
- public void init(int year, int monthOfYear, int dayOfMonth,
- OnDateChangedListener onDateChangedListener) {
- mYear = year;
- mMonth = monthOfYear;
- mDay = dayOfMonth;
- mOnDateChangedListener = onDateChangedListener;
- updateSpinners();
- }
-
- private void updateSpinners() {
- updateDaySpinner();
- mYearPicker.setCurrent(mYear);
-
- /* The month display uses 1-12 but our internal state stores it
- * 0-11 so add one when setting the display.
- */
- mMonthPicker.setCurrent(mMonth + 1);
- }
-
- private void updateDaySpinner() {
- Calendar cal = Calendar.getInstance();
- cal.set(mYear, mMonth, mDay);
- int max = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
- mDayPicker.setRange(1, max);
- mDayPicker.setCurrent(mDay);
- }
-
- public int getYear() {
- return mYear;
- }
-
- public int getMonth() {
- return mMonth;
- }
-
- public int getDayOfMonth() {
- return mDay;
- }
-
- private void adjustMaxDay(){
- Calendar cal = Calendar.getInstance();
- cal.set(Calendar.YEAR, mYear);
- cal.set(Calendar.MONTH, mMonth);
- int max = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
- if (mDay > max) {
- mDay = max;
- }
- }
-
- private void notifyDateChanged() {
- if (mOnDateChangedListener != null) {
- mOnDateChangedListener.onDateChanged(DatePicker.this, mYear, mMonth, mDay);
- }
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
}
}
diff --git a/core/java/android/widget/DayPicker.java b/core/java/android/widget/DayPicker.java
new file mode 100644
index 0000000..11c23ab
--- /dev/null
+++ b/core/java/android/widget/DayPicker.java
@@ -0,0 +1,1474 @@
+/*
+ * Copyright (C) 2010 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 android.widget;
+
+import com.android.internal.R;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.database.DataSetObserver;
+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.drawable.Drawable;
+import android.text.format.DateFormat;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.GestureDetector;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView.OnScrollListener;
+
+import java.security.InvalidParameterException;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Locale;
+
+import libcore.icu.LocaleData;
+
+/**
+ * Displays a day picker in the form of a calendar. The calendar
+ * is represented as a list where each row depicts a week. Each week is
+ * composed of items that are selectable days.
+ */
+public class DayPicker extends FrameLayout {
+
+ /**
+ * The number of milliseconds in a day.
+ *
+ * @hide
+ */
+ protected static final long MILLIS_IN_DAY = 86400000L;
+
+ /**
+ * The number of day in a week.
+ *
+ * @hide
+ */
+ protected static final int DAYS_PER_WEEK = 7;
+
+ /**
+ * The number of milliseconds in a week.
+ *
+ * @hide
+ */
+ protected static final long MILLIS_IN_WEEK = DAYS_PER_WEEK * MILLIS_IN_DAY;
+
+ /**
+ * Affects when the month selection will change while scrolling up
+ *
+ * @hide
+ */
+ protected static final int SCROLL_HYST_WEEKS = 2;
+
+ /**
+ * How long the GoTo fling animation should last.
+ *
+ * @hide
+ */
+ protected static final int GOTO_SCROLL_DURATION = 1000;
+
+ /**
+ * The duration of the adjustment upon a user scroll in milliseconds.
+ *
+ * @hide
+ */
+ protected static final int ADJUSTMENT_SCROLL_DURATION = 500;
+
+ /**
+ * How long to wait after receiving an onScrollStateChanged notification
+ * before acting on it.
+ *
+ * @hide
+ */
+ protected static final int SCROLL_CHANGE_DELAY = 40;
+
+ /**
+ * The scale used to compensate for different screen density.
+ *
+ * @hide
+ */
+ protected static float sScale;
+
+ /**
+ * The top offset of the weeks list.
+ *
+ * @hide
+ */
+ protected static int mListTopOffset = 2;
+
+ /**
+ * The visible height of a week view.
+ *
+ * @hide
+ */
+ protected int mWeekMinVisibleHeight = 12;
+
+
+ /**
+ * The visible height of a week view.
+ *
+ * @hide
+ */
+ protected int mBottomBuffer = 20;
+
+ /**
+ * The number of shown weeks.
+ *
+ * @hide
+ */
+ protected int mShownWeekCount = 6;
+
+ /**
+ * Flag whether to show the week number.
+ *
+ * @hide
+ */
+ protected boolean mShowWeekNumber = true;
+
+ /**
+ * The number of day per week to be shown
+ *
+ * @hide
+ */
+ protected int mDaysPerWeek = 7;
+
+ /**
+ * The friction of the week list while flinging.
+ *
+ * @hide
+ */
+ protected float mFriction = .05f;
+
+ /**
+ * Scale for adjusting velocity of the week list while flinging.
+ *
+ * @hide
+ */
+ protected float mVelocityScale = 0.333f;
+
+ /**
+ * The adapter for the weeks list.
+ *
+ * @hide
+ */
+ protected WeeksAdapter mAdapter;
+
+ /**
+ * The weeks list.
+ *
+ * @hide
+ */
+ protected ListView mListView;
+
+ /**
+ * The name of the month to display.
+ *
+ * @hide
+ */
+ protected TextView mMonthName;
+
+ /**
+ * The header with week day names.
+ *
+ * @hide
+ */
+ protected ViewGroup mDayNamesHeader;
+
+ /**
+ * Cached labels for the week names header.
+ *
+ * @hide
+ */
+ protected String[] mDayLabels;
+
+ /**
+ * Temporary instance to avoid multiple instantiations.
+ *
+ * @hide
+ */
+ protected Calendar mTempCalendar = Calendar.getInstance();
+
+ /**
+ * The first day of the week based on the current locale.
+ *
+ * @hide
+ */
+ protected int mFirstDayOfWeek = LocaleData.get(Locale.getDefault()).firstDayOfWeek;
+
+ /**
+ * The first day of the focused month.
+ *
+ * @hide
+ */
+ protected Calendar mFirstDayOfMonth = Calendar.getInstance();
+
+ /**
+ * Which month should be displayed/highlighted [0-11]
+ *
+ * @hide
+ */
+ protected int mCurrentMonthDisplayed;
+
+ /**
+ * Used for tracking during a scroll.
+ *
+ * @hide
+ */
+ protected long mPreviousScrollPosition;
+
+ /**
+ * Used for tracking which direction the view is scrolling.
+ *
+ * @hide
+ */
+ protected boolean mIsScrollingUp = false;
+
+ /**
+ * The previous scroll state of the weeks ListView.
+ *
+ * @hide
+ */
+ protected int mPreviousScrollState = OnScrollListener.SCROLL_STATE_IDLE;
+
+ /**
+ * The current scroll state of the weeks ListView.
+ *
+ * @hide
+ */
+ protected int mCurrentScrollState = OnScrollListener.SCROLL_STATE_IDLE;
+
+ /**
+ * Listener for changes in the selected day.
+ *
+ * @hide
+ */
+ protected OnSelectedDayChangeListener mOnChangeListener;
+
+ /**
+ * Command for adjusting the position after a scroll/fling.
+ *
+ * @hide
+ */
+ protected ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable();
+
+ /**
+ * The start date of the range supported by this picker.
+ *
+ * @hide
+ */
+ protected Calendar mStartRangeDate = Calendar.getInstance();
+
+ /**
+ * The end date of the range supported by this picker.
+ *
+ * @hide
+ */
+ protected Calendar mEndRangeDate = Calendar.getInstance();
+
+ /**
+ * String for formatting the month name in the title text view.
+ *
+ * @hide
+ */
+ protected String mMonthNameFormatSrting = "MMMM, yyyy";
+
+ /**
+ * The callback used to indicate the user changes the date.
+ */
+ public interface OnSelectedDayChangeListener {
+
+ /**
+ * Called upon change of the selected day.
+ *
+ * @param view The view associated with this listener.
+ * @param year The year that was set.
+ * @param month The month that was set [0-11].
+ * @param dayOfMonth The day of the month that was set.
+ */
+ public void onSelectedDayChange(DayPicker view, int year, int month, int dayOfMonth);
+ }
+
+ public DayPicker(Context context) {
+ this(context, null);
+ }
+
+ public DayPicker(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public DayPicker(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, 0);
+
+ LayoutInflater layoutInflater = (LayoutInflater) mContext
+ .getSystemService(Service.LAYOUT_INFLATER_SERVICE);
+ View content = layoutInflater.inflate(R.layout.day_picker, null, false);
+ addView(content);
+
+ mListView = (ListView) findViewById(R.id.list);
+ mDayNamesHeader = (ViewGroup) content.findViewById(com.android.internal.R.id.day_names);
+ mMonthName = (TextView) content.findViewById(com.android.internal.R.id.month_name);
+
+ // Adjust sizes for screen density
+ if (sScale == 0) {
+ sScale = mContext.getResources().getDisplayMetrics().density;
+ if (sScale != 1) {
+ mWeekMinVisibleHeight *= sScale;
+ mBottomBuffer *= sScale;
+ mListTopOffset *= sScale;
+ }
+ }
+
+ // set default range
+ mStartRangeDate.clear();
+ mStartRangeDate.set(1900, 0, 1);
+ mEndRangeDate.clear();
+ mEndRangeDate.set(2100, 0, 1);
+
+ setUpHeader();
+ updateHeader();
+ setUpListView();
+ setUpAdapter();
+
+ // go to today now
+ mTempCalendar.setTimeInMillis(System.currentTimeMillis());
+ goTo(mTempCalendar, false, true, true);
+ invalidate();
+ }
+
+ /**
+ * Sets the range supported by this day picker. This is the picker will not
+ * support dates before <code>startRangeDate</code> and <code>endRangeDate
+ * </code>.
+ *
+ * @param startRangeDate The start date.
+ * @param endRangeDate The end date.
+ */
+ public void setRange(Calendar startRangeDate, Calendar endRangeDate) {
+ boolean doSetupAdapter = false;
+ if (mStartRangeDate.get(Calendar.DAY_OF_YEAR) != startRangeDate.get(Calendar.DAY_OF_YEAR)
+ || mStartRangeDate.get(Calendar.YEAR) != startRangeDate.get(Calendar.YEAR)) {
+ mStartRangeDate = startRangeDate;
+ doSetupAdapter = true;
+ }
+ if (mEndRangeDate.get(Calendar.DAY_OF_YEAR) != endRangeDate.get(Calendar.DAY_OF_YEAR)
+ || mEndRangeDate.get(Calendar.YEAR) != endRangeDate.get(Calendar.YEAR)) {
+ mEndRangeDate = endRangeDate;
+ doSetupAdapter = true;
+
+ }
+ if (doSetupAdapter) {
+ setUpAdapter();
+ }
+ }
+
+ /**
+ * Sets the listener to be notified upon day selection changes.
+ *
+ * @param listener The listener to be called back.
+ */
+ public void setOnDateChangeListener(OnSelectedDayChangeListener listener) {
+ mOnChangeListener = listener;
+ }
+
+ /**
+ * Gets the selected day.
+ *
+ * @return The selected day.
+ */
+ public Calendar getSelectedDay() {
+ return mAdapter.mSelectedDay;
+ }
+
+ /**
+ * Sets the selected day. This is equivalent to a call to
+ * {@link #goTo(Calendar, boolean, boolean, boolean)} with
+ * the arguments <code>selectedDay</code>, <code>false</code>,
+ * <code>true</code>, <code>false</code> respectively.
+ *
+ * @param selectedDay The selected day.
+ */
+ public void setSelectedDay(Calendar selectedDay) {
+ goTo(selectedDay, false, true, false);
+ }
+
+ /**
+ * Creates a new adapter if necessary and sets up its parameters. Override
+ * this method to provide a custom adapter.
+ *
+ * @hide
+ */
+ protected void setUpAdapter() {
+ if (mAdapter == null) {
+ mAdapter = new WeeksAdapter(getContext());
+ mAdapter.registerDataSetObserver(new DataSetObserver() {
+ @Override
+ public void onChanged() {
+ if (mOnChangeListener != null) {
+ Calendar selectedDay = mAdapter.getSelectedDay();
+ mOnChangeListener.onSelectedDayChange(DayPicker.this,
+ selectedDay.get(Calendar.YEAR),
+ selectedDay.get(Calendar.MONTH),
+ selectedDay.get(Calendar.DAY_OF_MONTH));
+ }
+ }
+ });
+ mListView.setAdapter(mAdapter);
+ }
+
+ // refresh the view with the new parameters
+ mAdapter.notifyDataSetChanged();
+ }
+
+ /**
+ * Sets up the strings to be used by the header. Override this method to use
+ * different strings or modify the view params.
+ *
+ * @hide
+ */
+ protected void setUpHeader() {
+ mDayLabels = new String[mDaysPerWeek];
+ for (int i = mFirstDayOfWeek, count = mFirstDayOfWeek + mDaysPerWeek; i < count; i++) {
+ int calendarDay = (i < mDaysPerWeek) ? i : 1; // Calendar.MONDAY is
+ // 1
+ mDayLabels[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay,
+ DateUtils.LENGTH_SHORTEST);
+ }
+ }
+
+ /**
+ * Sets all the required fields for the list view. Override this method to
+ * set a different list view behavior.
+ *
+ * @hide
+ */
+ protected void setUpListView() {
+ // Configure the listview
+ mListView.setDivider(null);
+ mListView.setItemsCanFocus(true);
+ mListView.setVerticalScrollBarEnabled(false);
+ mListView.setOnScrollListener(new OnScrollListener() {
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ DayPicker.this.onScrollStateChanged(view, scrollState);
+ }
+
+ public void onScroll(
+ AbsListView view, int firstVisibleItem, int visibleItemCount,
+ int totalItemCount) {
+ DayPicker.this.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
+ }
+ });
+ // Make the scrolling behavior nicer
+ mListView.setFriction(mFriction);
+ mListView.setVelocityScale(mVelocityScale);
+ }
+
+ /**
+ * Fixes the day names header to provide correct spacing and updates the
+ * label text. Override this to set up a custom header.
+ *
+ * @hide
+ */
+ protected void updateHeader() {
+ TextView label = (TextView) mDayNamesHeader.getChildAt(0);
+ if (mShowWeekNumber) {
+ label.setVisibility(View.VISIBLE);
+ } else {
+ label.setVisibility(View.GONE);
+ }
+ for (int i = 1, count = mDayNamesHeader.getChildCount(); i < count; i++) {
+ label = (TextView) mDayNamesHeader.getChildAt(i);
+ if (i < mDaysPerWeek + 1) {
+ label.setText(mDayLabels[i - 1]);
+ label.setVisibility(View.VISIBLE);
+ } else {
+ label.setVisibility(View.GONE);
+ }
+ }
+ mDayNamesHeader.invalidate();
+ }
+
+ /**
+ * This moves to the specified time in the view. If the time is not already
+ * in range it will move the list so that the first of the month containing
+ * the time is at the top of the view. If the new time is already in view
+ * the list will not be scrolled unless forceScroll is true. This time may
+ * optionally be highlighted as selected as well.
+ *
+ * @param year The year to move to.
+ * @param month The month to move to <strong>starting from zero<strong>.
+ * @param dayOfMonth The month day to move to.
+ * @param animate Whether to scroll to the given time or just redraw at the
+ * new location.
+ * @param setSelected Whether to set the given time as selected
+ * @param forceScroll Whether to recenter even if the time is already
+ * visible.
+ */
+ public void goTo(int year, int month, int dayOfMonth, boolean animate, boolean setSelected,
+ boolean forceScroll) {
+ mTempCalendar.clear();
+ mTempCalendar.set(year, month, dayOfMonth);
+ goTo(mTempCalendar, animate, setSelected, forceScroll);
+ }
+
+ /**
+ * This moves to the specified time in the view. If the time is not already
+ * in range it will move the list so that the first of the month containing
+ * the time is at the top of the view. If the new time is already in view
+ * the list will not be scrolled unless forceScroll is true. This time may
+ * optionally be highlighted as selected as well.
+ *
+ * @param date The time to move to.
+ * @param animate Whether to scroll to the given time or just redraw at the
+ * new location.
+ * @param setSelected Whether to set the given time as selected.
+ * @param forceScroll Whether to recenter even if the time is already
+ * visible.
+ */
+ public void goTo(Calendar date, boolean animate, boolean setSelected, boolean forceScroll) {
+ long timeInMillis = date.getTimeInMillis();
+ if (timeInMillis < mStartRangeDate.getTimeInMillis()
+ || timeInMillis > mEndRangeDate.getTimeInMillis()) {
+ throw new IllegalArgumentException("Time not between " + mStartRangeDate.getTime()
+ + " and " + mEndRangeDate.getTime());
+ }
+ // Find the first and last entirely visible weeks
+ int firstFullyVisiblePosition = mListView.getFirstVisiblePosition();
+ View firstChild = mListView.getChildAt(0);
+ if (firstChild != null && firstChild.getTop() < 0) {
+ firstFullyVisiblePosition++;
+ }
+ int lastFullyVisiblePosition = firstFullyVisiblePosition + mShownWeekCount - 1;
+ if (firstChild != null && firstChild.getTop() > mBottomBuffer) {
+ lastFullyVisiblePosition--;
+ }
+ if (setSelected) {
+ mAdapter.setSelectedDay(date);
+ }
+ // Get the week we're going to
+ int position = getWeeksDelta(date);
+
+ // Check if the selected day is now outside of our visible range
+ // and if so scroll to the month that contains it
+ if (position < firstFullyVisiblePosition || position > lastFullyVisiblePosition
+ || forceScroll) {
+ mFirstDayOfMonth.setTimeInMillis(date.getTimeInMillis());
+ mFirstDayOfMonth.setTimeZone(date.getTimeZone());
+ mFirstDayOfMonth.set(Calendar.DAY_OF_MONTH, 1);
+
+ setMonthDisplayed(mFirstDayOfMonth);
+ position = getWeeksDelta(mFirstDayOfMonth);
+
+ mPreviousScrollState = OnScrollListener.SCROLL_STATE_FLING;
+ if (animate) {
+ mListView.smoothScrollToPositionFromTop(position, mListTopOffset,
+ GOTO_SCROLL_DURATION);
+ } else {
+ mListView.setSelectionFromTop(position, mListTopOffset);
+ // Perform any after scroll operations that are needed
+ onScrollStateChanged(mListView, OnScrollListener.SCROLL_STATE_IDLE);
+ }
+ } else if (setSelected) {
+ // Otherwise just set the selection
+ setMonthDisplayed(date);
+ }
+ }
+
+ /**
+ * Called when a <code>view</code> transitions to a new <code>scrollState
+ * </code>.
+ *
+ * @hide
+ */
+ protected void onScrollStateChanged(AbsListView view, int scrollState) {
+ mScrollStateChangedRunnable.doScrollStateChange(view, scrollState);
+ }
+
+ /**
+ * Updates the title and selected month if the <code>view</code> has moved to a new
+ * month.
+ *
+ * @hide
+ */
+ protected void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+ int totalItemCount) {
+ WeekView child = (WeekView) view.getChildAt(0);
+ if (child == null) {
+ return;
+ }
+
+ // Figure out where we are
+ int offset = child.getBottom() < mWeekMinVisibleHeight ? 1 : 0;
+ long currScroll = view.getFirstVisiblePosition() * child.getHeight() - child.getBottom();
+
+ // If we have moved since our last call update the direction
+ if (currScroll < mPreviousScrollPosition) {
+ mIsScrollingUp = true;
+ } else if (currScroll > mPreviousScrollPosition) {
+ mIsScrollingUp = false;
+ } else {
+ return;
+ }
+
+ // Use some hysteresis for checking which month to highlight. This
+ // causes the month to transition when two full weeks of a month are
+ // visible when scrolling up, and when the first day in a month reaches
+ // the top of the screen when scrolling down.
+ if (mIsScrollingUp) {
+ child = (WeekView) view.getChildAt(SCROLL_HYST_WEEKS + offset);
+ } else if (offset != 0) {
+ child = (WeekView) view.getChildAt(offset);
+ }
+
+ // Find out which month we're moving into
+ int month;
+ if (mIsScrollingUp) {
+ month = child.getMonthOfFirstWeekDay();
+ } else {
+ month = child.getMonthOfLastWeekDay();
+ }
+
+ // And how it relates to our current highlighted month
+ int monthDiff;
+ if (mCurrentMonthDisplayed == 11 && month == 0) {
+ monthDiff = 1;
+ } else if (mCurrentMonthDisplayed == 0 && month == 11) {
+ monthDiff = -1;
+ } else {
+ monthDiff = month - mCurrentMonthDisplayed;
+ }
+
+ // Only switch months if we're scrolling away from the currently
+ // selected month
+ if ((!mIsScrollingUp && monthDiff > 0) || (mIsScrollingUp && monthDiff < 0)) {
+ Calendar firstDay = child.getFirstDay();
+ if (mIsScrollingUp) {
+ firstDay.add(Calendar.DAY_OF_MONTH, -DAYS_PER_WEEK);
+ } else {
+ firstDay.add(Calendar.DAY_OF_MONTH, DAYS_PER_WEEK);
+ }
+ setMonthDisplayed(firstDay);
+ }
+ mPreviousScrollPosition = currScroll;
+ mPreviousScrollState = mCurrentScrollState;
+ }
+
+ /**
+ * Sets the month displayed at the top of this view based on time. Override
+ * to add custom events when the title is changed.
+ *
+ * @param calendar A day in the new focus month.
+ *
+ * @hide
+ */
+ protected void setMonthDisplayed(Calendar calendar) {
+ mMonthName.setText(DateFormat.format(mMonthNameFormatSrting, calendar));
+ mMonthName.invalidate();
+ mCurrentMonthDisplayed = calendar.get(Calendar.MONTH);
+ mAdapter.setFocusMonth(mCurrentMonthDisplayed);
+ // TODO Send Accessibility Event
+ }
+
+ /**
+ * @return Returns the number of weeks between the current week day of the
+ * <code>fromDate</code> and the first day of week of
+ * <code>toDate</code>.
+ *
+ * @hide
+ */
+ protected int getWeeksDelta(Calendar toDate) {
+ if (toDate.before(mStartRangeDate)) {
+ throw new IllegalArgumentException("fromDate: " + mStartRangeDate.getTime()
+ + " does not precede toDate: " + toDate.getTime());
+ }
+ int fromDateDayOfWeek = mStartRangeDate.get(Calendar.DAY_OF_WEEK);
+ long diff = (fromDateDayOfWeek - toDate.getFirstDayOfWeek()) * MILLIS_IN_DAY;
+ if (diff < 0) {
+ diff = diff + MILLIS_IN_WEEK;
+ }
+ long refDay = mStartRangeDate.getTimeInMillis() - diff;
+ return (int) ((toDate.getTimeInMillis() - refDay) / MILLIS_IN_WEEK);
+ }
+
+ /**
+ * Command responsible for acting upon scroll state changes.
+ *
+ * @hide
+ */
+ protected class ScrollStateRunnable implements Runnable {
+ private AbsListView mView;
+
+ private int mNewState;
+
+ /**
+ * Sets up the runnable with a short delay in case the scroll state
+ * immediately changes again.
+ *
+ * @param view The list view that changed state
+ * @param scrollState The new state it changed to
+ */
+ public void doScrollStateChange(AbsListView view, int scrollState) {
+ removeCallbacks(this);
+ mView = view;
+ mNewState = scrollState;
+ removeCallbacks(this);
+ postDelayed(this, SCROLL_CHANGE_DELAY);
+ }
+
+ public void run() {
+ mCurrentScrollState = mNewState;
+ // Fix the position after a scroll or a fling ends
+ if (mNewState == OnScrollListener.SCROLL_STATE_IDLE
+ && mPreviousScrollState != OnScrollListener.SCROLL_STATE_IDLE) {
+ mPreviousScrollState = mNewState;
+ View child = mView.getChildAt(0);
+ if (child == null) {
+ // The view is no longer visible, just return
+ return;
+ }
+ int dist = child.getBottom() - mListTopOffset;
+ if (dist > mListTopOffset) {
+ if (mIsScrollingUp) {
+ mView.smoothScrollBy(dist - child.getHeight(), ADJUSTMENT_SCROLL_DURATION);
+ } else {
+ mView.smoothScrollBy(dist, ADJUSTMENT_SCROLL_DURATION);
+ }
+ }
+ } else {
+ mPreviousScrollState = mNewState;
+ }
+ }
+ }
+
+ /**
+ * <p>
+ * This is a specialized adapter for creating a list of weeks with
+ * selectable days. It can be configured to display the week number, start
+ * the week on a given day, show a reduced number of days, or display an
+ * arbitrary number of weeks at a time.
+ * </p>
+ *
+ * @hide
+ */
+ public class WeeksAdapter extends BaseAdapter implements OnTouchListener {
+
+ /**
+ * The default maximum year supported by the Date Time Picker.
+ */
+ public static final int DEFAULT_MAX_CALENDAR_YEAR = 2100;
+
+ /**
+ * The default minimum year supported by the Date Time Picker.
+ */
+ public static final int DEFAULT_MIN_CALENDAR_YEAR = 1900;
+
+ /**
+ * The number of weeks to display at a time.
+ */
+ public static final String WEEK_PARAMS_NUM_WEEKS = "num_weeks";
+
+ /**
+ * Which month should be in focus currently.
+ */
+ public static final String WEEK_PARAMS_FOCUS_MONTH = "focus_month";
+
+ /**
+ * Whether the week number should be shown. Non-zero to show them.
+ */
+ public static final String WEEK_PARAMS_SHOW_WEEK = "week_numbers";
+
+ /**
+ * Which day the week should start on. {@link Time#SUNDAY} through
+ * {@link Time#SATURDAY}.
+ */
+ public static final String WEEK_PARAMS_WEEK_START = "week_start";
+
+ /**
+ * The year of the highlighted day.
+ */
+ public static final String WEEK_PARAMS_YEAR = "selected_year";
+
+ /**
+ * The month of the highlighted day.
+ */
+ public static final String WEEK_PARAMS_MONTH = "selected_month";
+
+ /**
+ * The year of the highlighted day.
+ */
+ public static final String WEEK_PARAMS_DAY_OF_MONTH = "selected_day_of_month";
+
+ /**
+ * The start date of the supported interval.
+ */
+ public static final String WEEK_PARAMS_START_DATE_RANGE_MILLIS = "start_date_gange_millis";
+
+ /**
+ * The end date of the supported interval.
+ */
+ public static final String WEEK_PARAMS_END_DATE_RANGE_MILLIS = "end_date_gange_millis";
+
+ /**
+ * How many days of the week to display [1-7].
+ */
+ public static final String WEEK_PARAMS_DAYS_PER_WEEK = "days_per_week";
+
+ protected int WEEK_7_OVERHANG_HEIGHT = 7;
+
+ protected int mSelectedWeek;
+
+ protected GestureDetector mGestureDetector;
+
+ protected int mFocusMonth = 0;
+
+ private final Calendar mSelectedDay = Calendar.getInstance();
+
+ private int mTotalWeekCount = -1;
+
+ public WeeksAdapter(Context context) {
+ mContext = context;
+
+ if (sScale == 0) {
+ sScale = context.getResources().getDisplayMetrics().density;
+ if (sScale != 1) {
+ WEEK_7_OVERHANG_HEIGHT *= sScale;
+ }
+ }
+ init();
+ }
+
+ /**
+ * Set up the gesture detector and selected time
+ */
+ protected void init() {
+ mGestureDetector = new GestureDetector(mContext, new CalendarGestureListener());
+ mSelectedWeek = getWeeksDelta(mSelectedDay);
+ mTotalWeekCount = getWeeksDelta(mEndRangeDate);
+ }
+
+ /**
+ * Updates the selected day and related parameters.
+ *
+ * @param selectedDay The time to highlight
+ */
+ public void setSelectedDay(Calendar selectedDay) {
+ if (selectedDay.get(Calendar.DAY_OF_YEAR) == mSelectedDay.get(Calendar.DAY_OF_YEAR)
+ && selectedDay.get(Calendar.YEAR) == mSelectedDay.get(Calendar.YEAR)) {
+ return;
+ }
+ mSelectedDay.setTimeInMillis(selectedDay.getTimeInMillis());
+ mSelectedDay.setTimeZone(selectedDay.getTimeZone());
+ mSelectedWeek = getWeeksDelta(mSelectedDay);
+ mFocusMonth = mSelectedDay.get(Calendar.MONTH);
+ notifyDataSetChanged();
+ invalidate(); // Test
+ }
+
+ /**
+ * @return The selected day of month.
+ */
+ public Calendar getSelectedDay() {
+ return mSelectedDay;
+ }
+
+ /**
+ * updates any config options that may have changed and refreshes the
+ * view
+ */
+ public void refresh() {
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return mTotalWeekCount;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ WeekView v;
+ HashMap<String, Object> drawingParams = null;
+ if (convertView != null) {
+ v = (WeekView) convertView;
+ // We store the drawing parameters in the view so it can be
+ // recycled
+ drawingParams = (HashMap<String, Object>) v.getTag();
+ } else {
+ v = getNewView();
+ // Set up the new view
+ android.widget.AbsListView.LayoutParams params =
+ new android.widget.AbsListView.LayoutParams(
+ LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ v.setLayoutParams(params);
+ v.setClickable(true);
+ v.setOnTouchListener(this);
+
+ drawingParams = new HashMap<String, Object>();
+ }
+
+ // pass in all the view parameters
+ putDrawingParementer(drawingParams, WeekView.VIEW_PARAMS_SHOW_WK_NUM,
+ mShowWeekNumber ? 1 : 0);
+ putDrawingParementer(drawingParams, WeekView.VIEW_PARAMS_WEEK_START, mFirstDayOfWeek);
+ putDrawingParementer(drawingParams, WeekView.VIEW_PARAMS_NUM_DAYS, mDaysPerWeek);
+ putDrawingParementer(drawingParams, WeekView.VIEW_PARAMS_WEEK, position);
+ putDrawingParementer(drawingParams, WeekView.VIEW_PARAMS_FOCUS_MONTH, mFocusMonth);
+ putDrawingParementer(drawingParams, WeekView.VIEW_PARAMS_SELECTED_DAY,
+ (mSelectedWeek == position) ? mSelectedDay.get(Calendar.DAY_OF_WEEK) : -1);
+ v.setWeekParams(drawingParams);
+
+ return v;
+ }
+
+ /**
+ * Puts the given <code>value</code> for the drawing
+ * <code>parameter</code> in the <code>drawingParams</code>.
+ */
+ private void putDrawingParementer(HashMap<String, Object> drawingParams, String parameter,
+ int value) {
+ int[] valueArray = (int[]) drawingParams.get(parameter);
+ if (valueArray == null) {
+ valueArray = new int[1];
+ drawingParams.put(parameter, valueArray);
+ }
+ valueArray[0] = value;
+ }
+
+ /**
+ * Creates a new WeekView and returns it. Override this to customize the
+ * view creation.
+ *
+ * @return A new WeekView
+ */
+ protected WeekView getNewView() {
+ return new WeekView(mContext);
+ }
+
+ /**
+ * Changes which month is in focus and updates the view.
+ *
+ * @param month The month to show as in focus [0-11]
+ */
+ public void setFocusMonth(int month) {
+ if (mFocusMonth == month) {
+ return;
+ }
+ mFocusMonth = month;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (mGestureDetector.onTouchEvent(event)) {
+ WeekView weekView = (WeekView) v;
+ weekView.getDayFromLocation(event.getX(), mTempCalendar);
+ if (mTempCalendar.get(Calendar.YEAR) != 0) {
+ onDayTapped(mTempCalendar);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Maintains the same hour/min/sec but moves the day to the tapped day.
+ *
+ * @param day The day that was tapped
+ */
+ protected void onDayTapped(Calendar day) {
+ setSelectedDay(day);
+ }
+
+ /**
+ * This is here so we can identify single tap events and set the
+ * selected day correctly
+ */
+ protected class CalendarGestureListener extends GestureDetector.SimpleOnGestureListener {
+ @Override
+ public boolean onSingleTapUp(MotionEvent e) {
+ return true;
+ }
+ }
+ }
+
+ /**
+ * <p>
+ * This is a dynamic view for drawing a single week. It can be configured to
+ * display the week number, start the week on a given day, or show a reduced
+ * number of days. It is intended for use as a single view within a
+ * ListView. See {@link WeeksAdapter} for usage.
+ * </p>
+ *
+ * @hide
+ */
+ public class WeekView extends View {
+
+ /*
+ * 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.
+ */
+ public static final String VIEW_PARAMS_WEEK = "week";
+
+ /**
+ * 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 #mFirstDay}.
+ */
+ 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 int mDefaultHeight = 32;
+
+ protected int mMinHeight = 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 DAY_SEPARATOR_WIDTH = 1;
+
+ protected int mNumberTextSize = 14;
+
+ // affects the padding on the sides of this view
+ protected int mPadding = 0;
+
+ protected final Rect mTempRect = new Rect();
+
+ protected final Paint mDrawPaint = new Paint();
+
+ protected Paint mMonthNumDrawPaint = new Paint();
+
+ protected Drawable mSelectedDayLine;
+
+ protected final int mSelectionBackgroundColor;
+
+ protected final int mFocusedMonthDateColor;
+
+ protected final int mOtherMonthDateColor;
+
+ protected final int mGridLinesColor;
+
+ protected final int mWeekNumberColor;
+
+ // Cache the number strings so we don't have to recompute them each time
+ protected String[] mDayNumbers;
+
+ // Quick lookup for checking which days are in the focus month
+ protected boolean[] mFocusDay;
+
+ // The first day displayed by this item
+ protected Calendar mFirstDay;
+
+ // The month of the first day in this week
+ protected int mMonthOfFirstWeekDay = -1;
+
+ // The month of the last day in this week
+ protected int mLastWeekDayMonth = -1;
+
+ // The position of this week, equivalent to weeks since the week of Jan
+ // 1st, 1900
+ protected int mWeek = -1;
+
+ // 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 mHeight = mDefaultHeight;
+
+ // Whether the week number should be shown
+ protected boolean mShowWeekNum = false;
+
+ // If this view contains the selected day
+ protected boolean mHasSelectedDay = false;
+
+ // Which day is selected [0-6] or -1 if no day is selected
+ protected int mSelectedDay = DEFAULT_SELECTED_DAY;
+
+ // 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;
+
+ public WeekView(Context context) {
+ super(context);
+
+ TypedValue outTypedValue = new TypedValue();
+ context.getTheme().resolveAttribute(R.attr.dayPickerWeekViewStyle, outTypedValue, true);
+ TypedArray attributesArray = context.obtainStyledAttributes(outTypedValue.resourceId,
+ R.styleable.DayPickerWeekView);
+
+ mSelectionBackgroundColor = attributesArray.getColor(
+ R.styleable.DayPickerWeekView_selectionBackgroundColor, 0);
+ mFocusedMonthDateColor = attributesArray.getColor(
+ R.styleable.DayPickerWeekView_focusedMonthDateColor, 0);
+ mOtherMonthDateColor = attributesArray.getColor(
+ R.styleable.DayPickerWeekView_otherMonthDateColor, 0);
+ mGridLinesColor = attributesArray.getColor(
+ R.styleable.DayPickerWeekView_gridLinesColor, 0);
+ mWeekNumberColor = attributesArray.getColor(
+ R.styleable.DayPickerWeekView_weekNumberColor, 0);
+ mSelectedDayLine = attributesArray
+ .getDrawable(R.styleable.DayPickerWeekView_selectedDayLine);
+ attributesArray.recycle();
+
+ if (sScale == 0) {
+ sScale = context.getResources().getDisplayMetrics().density;
+ if (sScale != 1) {
+ mDefaultHeight *= sScale;
+ mMinHeight *= sScale;
+ mNumberTextSize *= sScale;
+ }
+ }
+
+ // Sets up any standard paints that will be used
+ setPaintProperties();
+ }
+
+ /**
+ * 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 setWeekParams(HashMap<String, Object> params) {
+ if (!params.containsKey(VIEW_PARAMS_WEEK)) {
+ throw new InvalidParameterException(
+ "You must specify the week number for this view");
+ }
+ setTag(params);
+ // We keep the current value for any params not present
+ if (params.containsKey(VIEW_PARAMS_HEIGHT)) {
+ mHeight = ((int[]) params.get(VIEW_PARAMS_HEIGHT))[0];
+ if (mHeight < mMinHeight) {
+ mHeight = mMinHeight;
+ }
+ }
+ if (params.containsKey(VIEW_PARAMS_SELECTED_DAY)) {
+ mSelectedDay = ((int[]) params.get(VIEW_PARAMS_SELECTED_DAY))[0];
+ }
+ mHasSelectedDay = mSelectedDay != -1;
+ if (params.containsKey(VIEW_PARAMS_NUM_DAYS)) {
+ mNumDays = ((int[]) params.get(VIEW_PARAMS_NUM_DAYS))[0];
+ }
+ if (params.containsKey(VIEW_PARAMS_SHOW_WK_NUM)) {
+ if (((int[]) params.get(VIEW_PARAMS_SHOW_WK_NUM))[0] != 0) {
+ mNumCells = mNumDays + 1;
+ mShowWeekNum = true;
+ } else {
+ mShowWeekNum = false;
+ }
+ } else {
+ mNumCells = mShowWeekNum ? mNumDays + 1 : mNumDays;
+ }
+ mWeek = ((int[]) params.get(VIEW_PARAMS_WEEK))[0];
+ mTempCalendar.clear();
+ mTempCalendar.set(1900, 0, 1);
+ mTempCalendar.add(Calendar.WEEK_OF_YEAR, mWeek);
+ if (params.containsKey(VIEW_PARAMS_WEEK_START)) {
+ mTempCalendar.setFirstDayOfWeek(((int[]) params.get(VIEW_PARAMS_WEEK_START))[0]);
+ } else {
+ mTempCalendar.setFirstDayOfWeek(DEFAULT_WEEK_START);
+ }
+
+ // Allocate space for caching the day numbers and focus values
+ mDayNumbers = new String[mNumCells];
+ mFocusDay = new boolean[mNumCells];
+
+ // If we're showing the week number calculate it based on Monday
+ int i = 0;
+ if (mShowWeekNum) {
+ mDayNumbers[0] = Integer.toString(mTempCalendar.get(Calendar.WEEK_OF_YEAR));
+ i++;
+ }
+
+ // Now adjust our starting day based on the start day of the week
+ int diff = mTempCalendar.getFirstDayOfWeek() - mTempCalendar.get(Calendar.DAY_OF_WEEK);
+ mTempCalendar.add(Calendar.DAY_OF_MONTH, diff);
+
+ mFirstDay = (Calendar) mTempCalendar.clone();
+
+ mMonthOfFirstWeekDay = mTempCalendar.get(Calendar.MONTH);
+
+ int focusMonth = params.containsKey(VIEW_PARAMS_FOCUS_MONTH) ? ((int[]) params
+ .get(VIEW_PARAMS_FOCUS_MONTH))[0] : DEFAULT_FOCUS_MONTH;
+
+ for (; i < mNumCells; i++) {
+ mFocusDay[i] = (mTempCalendar.get(Calendar.MONTH) == focusMonth);
+ mDayNumbers[i] = Integer.toString(mTempCalendar.get(Calendar.DAY_OF_MONTH));
+ mTempCalendar.add(Calendar.DAY_OF_MONTH, 1);
+ }
+ // We do one extra add at the end of the loop, if that pushed us to
+ // new month undo it
+ if (mTempCalendar.get(Calendar.DAY_OF_MONTH) == 1) {
+ mTempCalendar.add(Calendar.DAY_OF_MONTH, -1);
+ }
+ mLastWeekDayMonth = mTempCalendar.get(Calendar.MONTH);
+
+ updateSelectionPositions();
+ }
+
+ /**
+ * Sets up the text and style properties for painting. Override this if
+ * you want to use a different paint.
+ */
+ protected void setPaintProperties() {
+ mDrawPaint.setFakeBoldText(false);
+ mDrawPaint.setAntiAlias(true);
+ mDrawPaint.setTextSize(mNumberTextSize);
+ mDrawPaint.setStyle(Style.FILL);
+
+ mMonthNumDrawPaint.setFakeBoldText(true);
+ mMonthNumDrawPaint.setAntiAlias(true);
+ mMonthNumDrawPaint.setTextSize(mNumberTextSize);
+ mMonthNumDrawPaint.setColor(mFocusedMonthDateColor);
+ mMonthNumDrawPaint.setStyle(Style.FILL);
+ mMonthNumDrawPaint.setTextAlign(Align.CENTER);
+ }
+
+ /**
+ * Returns the month of the first day in this week.
+ *
+ * @return The month the first day of this view is in.
+ */
+ public int getMonthOfFirstWeekDay() {
+ return mMonthOfFirstWeekDay;
+ }
+
+ /**
+ * Returns the month of the last day in this week
+ *
+ * @return The month the last day of this view is in
+ */
+ public int getMonthOfLastWeekDay() {
+ return mLastWeekDayMonth;
+ }
+
+ /**
+ * Returns the first day in this view.
+ *
+ * @return The first day in the view.
+ */
+ public Calendar getFirstDay() {
+ return mFirstDay;
+ }
+
+ /**
+ * Returns the number of days this view will display.
+ */
+ public int getNumDays() {
+ return mNumDays;
+ }
+
+ /**
+ * Calculates the day that the given x position is in, accounting for
+ * week number. Returns a Time referencing that day or null if
+ *
+ * @param x The x position of the touch eventy
+ */
+ public void getDayFromLocation(float x, Calendar outCalendar) {
+ int dayStart = mShowWeekNum ? (mWidth - mPadding * 2) / mNumCells + mPadding : mPadding;
+ if (x < dayStart || x > mWidth - mPadding) {
+ outCalendar.set(0, 0, 0, 0, 0, 0);
+ return;
+ }
+ // Selection is (x - start) / (pixels/day) == (x -s) * day / pixels
+ int dayPosition = (int) ((x - dayStart) * mNumDays / (mWidth - dayStart - mPadding));
+ outCalendar.setTimeZone(mFirstDay.getTimeZone());
+ outCalendar.setTimeInMillis(mFirstDay.getTimeInMillis());
+ outCalendar.add(Calendar.DAY_OF_MONTH, dayPosition);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ drawBackground(canvas);
+ drawWeekNums(canvas);
+ drawDaySeparators(canvas);
+ }
+
+ /**
+ * This draws the selection highlight if a day is selected in this week.
+ * Override this method if you wish to have a different background
+ * drawn.
+ *
+ * @param canvas The canvas to draw on
+ */
+ protected void drawBackground(Canvas canvas) {
+ if (!mHasSelectedDay) {
+ return;
+ }
+ mDrawPaint.setColor(mSelectionBackgroundColor);
+
+ mTempRect.top = DAY_SEPARATOR_WIDTH;
+ mTempRect.bottom = mHeight;
+ mTempRect.left = mShowWeekNum ? mPadding + (mWidth - mPadding * 2) / mNumCells
+ : mPadding;
+ mTempRect.right = mSelectedLeft - 2;
+ canvas.drawRect(mTempRect, mDrawPaint);
+
+ mTempRect.left = mSelectedRight + 3;
+ mTempRect.right = mWidth - mPadding;
+ canvas.drawRect(mTempRect, mDrawPaint);
+ }
+
+ /**
+ * 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 drawWeekNums(Canvas canvas) {
+ float textHeight = mDrawPaint.getTextSize();
+ int y = (int) ((mHeight + textHeight) / 2) - DAY_SEPARATOR_WIDTH;
+ int nDays = mNumCells;
+
+ mDrawPaint.setTextAlign(Align.CENTER);
+ int i = 0;
+ int divisor = 2 * nDays;
+ if (mShowWeekNum) {
+ mDrawPaint.setColor(mWeekNumberColor);
+ int x = (mWidth - mPadding * 2) / divisor + mPadding;
+ canvas.drawText(mDayNumbers[0], x, y, mDrawPaint);
+ i++;
+ }
+ for (; i < nDays; i++) {
+ mMonthNumDrawPaint.setColor(mFocusDay[i] ? mFocusedMonthDateColor
+ : mOtherMonthDateColor);
+ int x = (2 * i + 1) * (mWidth - mPadding * 2) / divisor + mPadding;
+ canvas.drawText(mDayNumbers[i], x, y, mMonthNumDrawPaint);
+ }
+ }
+
+ /**
+ * Draws a horizontal line for separating the weeks. Override this
+ * method if you want custom separators.
+ *
+ * @param canvas The canvas to draw on
+ */
+ protected void drawDaySeparators(Canvas canvas) {
+ mDrawPaint.setColor(mGridLinesColor);
+ mDrawPaint.setStrokeWidth(DAY_SEPARATOR_WIDTH);
+ float x = mShowWeekNum ? mPadding + (mWidth - mPadding * 2) / mNumCells : mPadding;
+ canvas.drawLine(x, 0, mWidth - mPadding, 0, mDrawPaint);
+
+ if (mHasSelectedDay) {
+ mSelectedDayLine.setBounds(mSelectedLeft - 2, DAY_SEPARATOR_WIDTH,
+ mSelectedLeft + 4, mHeight + 1);
+ mSelectedDayLine.draw(canvas);
+ mSelectedDayLine.setBounds(mSelectedRight - 3, DAY_SEPARATOR_WIDTH,
+ mSelectedRight + 3, mHeight + 1);
+ mSelectedDayLine.draw(canvas);
+ }
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ mWidth = w;
+ updateSelectionPositions();
+ }
+
+ /**
+ * This calculates the positions for the selected day lines.
+ */
+ protected void updateSelectionPositions() {
+ if (mHasSelectedDay) {
+ int selectedPosition = mSelectedDay - mTempCalendar.getFirstDayOfWeek();
+ if (selectedPosition < 0) {
+ selectedPosition += 7;
+ }
+ if (mShowWeekNum) {
+ selectedPosition++;
+ }
+ mSelectedLeft = selectedPosition * (mWidth - mPadding * 2) / mNumCells + mPadding;
+ mSelectedRight = (selectedPosition + 1) * (mWidth - mPadding * 2) / mNumCells
+ + mPadding;
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mHeight);
+ }
+ }
+}
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 43d194f..e5544e9 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -30,8 +30,8 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
-import android.graphics.Rect;
import android.graphics.Paint.Align;
+import android.graphics.Rect;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Spanned;
@@ -41,11 +41,11 @@
import android.util.SparseArray;
import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.LayoutInflater.Filter;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
-import android.view.LayoutInflater.Filter;
import android.view.animation.OvershootInterpolator;
import android.view.inputmethod.InputMethodManager;
@@ -166,7 +166,12 @@
/**
* Listener to be notified upon current value change.
*/
- private OnChangedListener mListener;
+ private OnChangeListener mOnChangeListener;
+
+ /**
+ * Listener to be notified upon scroll state change.
+ */
+ private OnScrollListener mOnScrollListener;
/**
* Formatter for for displaying the current value.
@@ -308,9 +313,14 @@
private final Rect mTempRect = new Rect();
/**
+ * The current scroll state of the number picker.
+ */
+ private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE;
+
+ /**
* The callback interface used to indicate the number value has changed.
*/
- public interface OnChangedListener {
+ public interface OnChangeListener {
/**
* @param picker The NumberPicker associated with this listener.
* @param oldVal The previous value.
@@ -320,6 +330,36 @@
}
/**
+ * Interface for listening to the picker scroll state.
+ */
+ public interface OnScrollListener {
+
+ /**
+ * The view is not scrolling.
+ */
+ public static int SCROLL_STATE_IDLE = 0;
+
+ /**
+ * The user is scrolling using touch, and their finger is still on the screen.
+ */
+ public static int SCROLL_STATE_TOUCH_SCROLL = 1;
+
+ /**
+ * The user had previously been scrolling using touch and performed a fling.
+ */
+ public static int SCROLL_STATE_FLING = 2;
+
+ /**
+ * Callback method to be invoked while the number picker is being scrolled.
+ *
+ * @param view The view whose scroll state is being reported
+ * @param scrollState The current scroll state. One of {@link #SCROLL_STATE_IDLE},
+ * {@link #SCROLL_STATE_TOUCH_SCROLL} or {@link #SCROLL_STATE_IDLE}.
+ */
+ public void onScrollStateChanged(NumberPicker view, int scrollState);
+ }
+
+ /**
* Interface used to format the number into a string for presentation
*/
public interface Formatter {
@@ -492,11 +532,15 @@
mBeginEditOnUpEvent = false;
mAdjustScrollerOnUpEvent = true;
if (mDrawSelectorWheel) {
- mBeginEditOnUpEvent = mFlingScroller.isFinished()
+ boolean scrollersFinished = mFlingScroller.isFinished()
&& mAdjustScroller.isFinished();
+ if (!scrollersFinished) {
+ mFlingScroller.forceFinished(true);
+ mAdjustScroller.forceFinished(true);
+ tryNotifyScrollListener(OnScrollListener.SCROLL_STATE_IDLE);
+ }
+ mBeginEditOnUpEvent = scrollersFinished;
mAdjustScrollerOnUpEvent = true;
- mFlingScroller.forceFinished(true);
- mAdjustScroller.forceFinished(true);
hideInputControls();
return true;
}
@@ -512,6 +556,7 @@
int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY);
if (deltaDownY > mTouchSlop) {
mBeginEditOnUpEvent = false;
+ tryNotifyScrollListener(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
setDrawSelectorWheel(true);
hideInputControls();
return true;
@@ -531,10 +576,12 @@
switch (action) {
case MotionEvent.ACTION_MOVE:
float currentMoveY = ev.getY();
- if (mBeginEditOnUpEvent) {
+ if (mBeginEditOnUpEvent
+ || mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY);
if (deltaDownY > mTouchSlop) {
mBeginEditOnUpEvent = false;
+ tryNotifyScrollListener(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
}
}
int deltaMoveY = (int) (currentMoveY - mLastMotionEventY);
@@ -550,6 +597,7 @@
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mInputText, 0);
+ mInputText.setSelection(0, mInputText.getText().length());
return true;
}
VelocityTracker velocityTracker = mVelocityTracker;
@@ -557,6 +605,7 @@
int initialVelocity = (int) velocityTracker.getYVelocity();
if (Math.abs(initialVelocity) > mMinimumFlingVelocity) {
fling(initialVelocity);
+ tryNotifyScrollListener(OnScrollListener.SCROLL_STATE_FLING);
} else {
if (mAdjustScrollerOnUpEvent) {
if (mFlingScroller.isFinished() && mAdjustScroller.isFinished()) {
@@ -689,10 +738,19 @@
/**
* Set the callback that indicates the number has been adjusted by the user.
*
- * @param listener the callback, should not be null.
+ * @param onChangeListener the callback, should not be null.
*/
- public void setOnChangeListener(OnChangedListener listener) {
- mListener = listener;
+ public void setOnChangeListener(OnChangeListener onChangeListener) {
+ mOnChangeListener = onChangeListener;
+ }
+
+ /**
+ * Set the callback that in notified for scroll state changes.
+ *
+ * @param onScrollListener the callback, should not be null.
+ */
+ public void setOnScrollListener(OnScrollListener onScrollListener) {
+ mOnScrollListener = onScrollListener;
}
/**
@@ -966,6 +1024,7 @@
private void onScrollerFinished(Scroller scroller) {
if (scroller == mFlingScroller) {
postAdjustScrollerCommand(0);
+ tryNotifyScrollListener(OnScrollListener.SCROLL_STATE_IDLE);
} else {
showInputControls();
updateInputTextView();
@@ -973,6 +1032,17 @@
}
/**
+ * Notifies the scroll listener for the given <code>scrollState</code>
+ * if the scroll state differs from the current scroll state.
+ */
+ private void tryNotifyScrollListener(int scrollState) {
+ if (mOnScrollListener != null && mScrollState != scrollState) {
+ mScrollState = scrollState;
+ mOnScrollListener.onScrollStateChanged(this, scrollState);
+ }
+ }
+
+ /**
* Flings the selector with the given <code>velocityY</code>.
*/
private void fling(int velocityY) {
@@ -1118,7 +1188,8 @@
scrollSelectorValue = "";
} else {
if (mDisplayedValues != null) {
- scrollSelectorValue = mDisplayedValues[selectorIndex];
+ int displayedValueIndex = selectorIndex - mStart;
+ scrollSelectorValue = mDisplayedValues[displayedValueIndex];
} else {
scrollSelectorValue = formatNumber(selectorIndex);
}
@@ -1167,8 +1238,8 @@
* NumberPicker.
*/
private void notifyChange(int previous, int current) {
- if (mListener != null) {
- mListener.onChanged(this, previous, mCurrent);
+ if (mOnChangeListener != null) {
+ mOnChangeListener.onChanged(this, previous, mCurrent);
}
}
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 6cf1387..24b5e4a 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -25,7 +25,7 @@
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
-import android.widget.NumberPicker.OnChangedListener;
+import android.widget.NumberPicker.OnChangeListener;
import java.text.DateFormatSymbols;
import java.util.Calendar;
@@ -110,7 +110,7 @@
// hour
mHourPicker = (NumberPicker) findViewById(R.id.hour);
- mHourPicker.setOnChangeListener(new NumberPicker.OnChangedListener() {
+ mHourPicker.setOnChangeListener(new NumberPicker.OnChangeListener() {
public void onChanged(NumberPicker spinner, int oldVal, int newVal) {
mCurrentHour = newVal;
if (!mIs24HourView) {
@@ -137,7 +137,7 @@
mMinutePicker.setRange(0, 59);
mMinutePicker.setSpeed(100);
mMinutePicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
- mMinutePicker.setOnChangeListener(new NumberPicker.OnChangedListener() {
+ mMinutePicker.setOnChangeListener(new NumberPicker.OnChangeListener() {
public void onChanged(NumberPicker spinner, int oldVal, int newVal) {
mCurrentMinute = newVal;
onTimeChanged();
@@ -146,7 +146,7 @@
// am/pm
mAmPmPicker = (NumberPicker) findViewById(R.id.amPm);
- mAmPmPicker.setOnChangeListener(new OnChangedListener() {
+ mAmPmPicker.setOnChangeListener(new OnChangeListener() {
public void onChanged(NumberPicker picker, int oldVal, int newVal) {
picker.requestFocus();
if (mIsAm) {
@@ -184,7 +184,7 @@
setEnabled(false);
}
}
-
+
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
diff --git a/core/res/res/drawable-hdpi/simple_week_dayline_holo_light.9.png b/core/res/res/drawable-hdpi/simple_week_dayline_holo_light.9.png
new file mode 100644
index 0000000..ed1a5e9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/simple_week_dayline_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/simple_week_dayline_holo_light.9.png b/core/res/res/drawable-mdpi/simple_week_dayline_holo_light.9.png
new file mode 100644
index 0000000..f264cb6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/simple_week_dayline_holo_light.9.png
Binary files differ
diff --git a/core/res/res/layout/date_picker.xml b/core/res/res/layout/date_picker.xml
index 4fd46b3..5c023ee 100644
--- a/core/res/res/layout/date_picker.xml
+++ b/core/res/res/layout/date_picker.xml
@@ -19,45 +19,74 @@
<!-- Layout of date picker-->
-<!-- Warning: everything within the parent is removed and re-ordered depending
- on the date format selected by the user. -->
+<!-- Warning: everything within the "pickers" layout is removed and re-ordered
+ depending on the date format selected by the user.
+-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/parent"
- android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
android:layout_gravity="center_horizontal"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
+ android:orientation="horizontal"
+ android:gravity="center">
- <!-- Month -->
- <NumberPicker
- android:id="@+id/month"
- android:layout_width="80dip"
+ <LinearLayout android:id="@+id/pickers"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="1dip"
- android:layout_marginRight="1dip"
- android:focusable="true"
- android:focusableInTouchMode="true"
- />
+ android:layout_marginRight="15dip"
+ android:layout_weight="0.5"
+ android:orientation="horizontal"
+ android:gravity="center">
- <!-- Day -->
- <NumberPicker
- android:id="@+id/day"
- android:layout_width="80dip"
- android:layout_height="wrap_content"
- android:layout_marginLeft="1dip"
- android:layout_marginRight="1dip"
- android:focusable="true"
- android:focusableInTouchMode="true"
- />
+ <!-- Month -->
+ <NumberPicker
+ android:id="@+id/month"
+ android:layout_width="48dip"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="15dip"
+ android:layout_marginRight="15dip"
+ android:layout_marginTop="35dip"
+ android:layout_marginBottom="35dip"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
- <!-- Year -->
- <NumberPicker
- android:id="@+id/year"
- android:layout_width="95dip"
- android:layout_height="wrap_content"
- android:layout_marginLeft="1dip"
- android:layout_marginRight="1dip"
- android:focusable="true"
- android:focusableInTouchMode="true"
- />
+ <!-- Day -->
+ <NumberPicker
+ android:id="@+id/day"
+ android:layout_width="48dip"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="15dip"
+ android:layout_marginRight="15dip"
+ android:layout_marginTop="35dip"
+ android:layout_marginBottom="35dip"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
+
+ <!-- Year -->
+ <NumberPicker
+ android:id="@+id/year"
+ android:layout_width="48dip"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="15dip"
+ android:layout_marginRight="15dip"
+ android:layout_marginTop="35dip"
+ android:layout_marginBottom="35dip"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
+
+ </LinearLayout>
+
+ <!-- mini-month day-picker -->
+ <DayPicker
+ android:id="@+id/mini_month_day_picker"
+ android:layout_width="200dip"
+ android:layout_height="230dip"
+ android:layout_marginLeft="15dip"
+ android:layout_weight="0.5"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ />
+
</LinearLayout>
diff --git a/core/res/res/layout/date_picker_dialog.xml b/core/res/res/layout/date_picker_dialog.xml
index 949c8a3..90de1f5 100644
--- a/core/res/res/layout/date_picker_dialog.xml
+++ b/core/res/res/layout/date_picker_dialog.xml
@@ -17,9 +17,14 @@
*/
-->
+<!-- Note: We want the DatePicker to take as much space as possible, therefore
+ we set the width and height bigger than the max AlertDialog size
+ determined by our parent WeightedLinearLayout.
+
+ See: alert_dialog.xml
+-->
<DatePicker xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/datePicker"
- android:padding="5dip"
android:layout_gravity="center_horizontal"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
+ android:layout_width="250dip"
+ android:layout_height="600dip"/>
diff --git a/core/res/res/layout/day_picker.xml b/core/res/res/layout/day_picker.xml
new file mode 100644
index 0000000..46ab450
--- /dev/null
+++ b/core/res/res/layout/day_picker.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2010, 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true" >
+
+ <TextView android:id="@+android:id/month_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:paddingTop="10dip"
+ android:paddingBottom="10dip"
+ style="@android:style/TextAppearance.Medium" />
+
+ <LinearLayout android:id="@+android:id/day_names"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="6dip"
+ android:layout_marginRight="2dip"
+ android:layout_marginLeft="2dip"
+ android:gravity="center">
+
+ <TextView android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:visibility="gone" />
+
+ <TextView android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center"
+ style="?android:attr/dayPickerWeekDayViewStyle" />
+
+ <TextView android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center"
+ style="?android:attr/dayPickerWeekDayViewStyle" />
+
+ <TextView android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center"
+ style="?android:attr/dayPickerWeekDayViewStyle" />
+
+ <TextView android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center"
+ style="?android:attr/dayPickerWeekDayViewStyle" />
+
+ <TextView android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center"
+ style="?android:attr/dayPickerWeekDayViewStyle" />
+
+ <TextView android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center"
+ style="?android:attr/dayPickerWeekDayViewStyle" />
+
+ <TextView android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center"
+ style="?android:attr/dayPickerWeekDayViewStyle" />
+
+ </LinearLayout>
+
+ <ListView android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:drawSelectorOnTop="false"
+ android:cacheColorHint="@android:color/transparent"
+ android:fastScrollEnabled="false"
+ android:overScrollMode="never" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/time_picker.xml b/core/res/res/layout/time_picker.xml
index fa288422..bf81c18 100644
--- a/core/res/res/layout/time_picker.xml
+++ b/core/res/res/layout/time_picker.xml
@@ -30,7 +30,7 @@
android:id="@+id/hour"
android:layout_width="48dip"
android:layout_height="wrap_content"
- android:layout_marginRight="20dip"
+ android:layout_marginRight="13dip"
android:layout_marginTop="35dip"
android:layout_marginBottom="35dip"
android:focusable="true"
@@ -50,8 +50,8 @@
android:id="@+id/minute"
android:layout_width="48dip"
android:layout_height="wrap_content"
- android:layout_marginLeft="20dip"
- android:layout_marginRight="22dip"
+ android:layout_marginLeft="13dip"
+ android:layout_marginRight="15dip"
android:layout_marginTop="35dip"
android:layout_marginBottom="35dip"
android:focusable="true"
@@ -63,7 +63,7 @@
android:id="@+id/amPm"
android:layout_width="48dip"
android:layout_height="wrap_content"
- android:layout_marginLeft="22dip"
+ android:layout_marginLeft="15dip"
android:layout_marginTop="35dip"
android:layout_marginBottom="35dip"
android:focusable="true"
diff --git a/core/res/res/layout/time_picker_dialog.xml b/core/res/res/layout/time_picker_dialog.xml
index d5a6b5e..09326c8 100644
--- a/core/res/res/layout/time_picker_dialog.xml
+++ b/core/res/res/layout/time_picker_dialog.xml
@@ -22,4 +22,4 @@
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="5dip" />
+ />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 109fb0d..81191ff 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -503,16 +503,23 @@
<attr name="listPopupWindowStyle" format="reference" />
<!-- Default PopupMenu style. -->
<attr name="popupMenuStyle" format="reference" />
- <!-- NumberPicker up button style -->
+
+ <!-- @hide NumberPicker up button style -->
<attr name="numberPickerUpButtonStyle" format="reference" />
- <!-- NumberPicker down button style -->
+ <!-- @hide NumberPicker down button style -->
<attr name="numberPickerDownButtonStyle" format="reference" />
- <!-- NumberPicker input text style -->
+ <!-- @hide NumberPicker input text style -->
<attr name="numberPickerInputTextStyle" format="reference" />
- <!-- NumberPicker the fading edge length of the selector wheel -->
+ <!-- @hide NumberPicker the fading edge length of the selector wheel -->
<attr name="numberPickerStyle" format="reference" />
+ <!-- @hide DayPicker$WeekView style-->
+ <attr name="dayPickerWeekViewStyle" format="reference" />
+
+ <!-- @hide DayPickerDayView style-->
+ <attr name="dayPickerWeekDayViewStyle" format="reference" />
+
<!-- =================== -->
<!-- Action bar styles -->
<!-- =================== -->
@@ -2943,6 +2950,16 @@
</declare-styleable>
<!-- @hide -->
+ <declare-styleable name="DayPickerWeekView">
+ <attr name="selectionBackgroundColor" format="color|reference" />
+ <attr name="focusedMonthDateColor" format="color|reference" />
+ <attr name="otherMonthDateColor" format="color|reference" />
+ <attr name="weekNumberColor" format="color|reference" />
+ <attr name="gridLinesColor" format="color|reference" />
+ <attr name="selectedDayLine" format="reference" />
+ </declare-styleable>
+
+ <!-- @hide -->
<declare-styleable name="NumberPicker">
<attr name="orientation" />
<attr name="solidColor" format="color|reference" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ae029e5..8fa1d32 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1567,6 +1567,6 @@
<public type="style" name="Holo.Light.ButtonBar.AlertDialog" />
<public type="style" name="Holo.SegmentedButton" />
<public type="style" name="Holo.Light.SegmentedButton" />
-
<public type="string" name="selectTextMode" />
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9f98ce4..2e235f0 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2295,6 +2295,8 @@
<!-- The title of the time picker dialog. [CHAR LIMIT=NONE] -->
<string name="time_picker_dialog_title">Set time</string>
+ <!-- The title of the date picker dialog. [CHAR LIMIT=NONE] -->
+ <string name="date_picker_dialog_title">Set date</string>
<!-- Name of the button in the date/time picker to accept the date/time change -->
<string name="date_time_set">Set</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 58553e1..8d7556f 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -238,6 +238,11 @@
<item name="android:textColor">#ff272727</item>
</style>
+ <!-- @hide -->
+ <style name="TextAppearance.Small.DayPickerWeekDayView">
+ <item name="android:textStyle">bold</item>
+ </style>
+
<!-- Widget Styles -->
<style name="Widget">
@@ -468,21 +473,35 @@
<item name="android:background">@android:drawable/btn_default</item>
</style>
+ <!-- @hide -->
+ <style name="Widget.DayPickerWeekView">
+ <item name="android:selectionBackgroundColor">#330099FF</item>
+ <item name="android:focusedMonthDateColor">#FFFFFFFF</item>
+ <item name="android:otherMonthDateColor">#66FFFFFF</item>
+ <item name="android:weekNumberColor">#33FFFFFF</item>
+ <item name="android:gridLinesColor">#19FFFFFF</item>
+ <item name="selectedDayLine">@android:drawable/simple_week_dayline_holo_light</item>
+ </style>
+
+ <!-- @hide -->
<style name="Widget.NumberPicker">
<item name="android:orientation">vertical</item>
<item name="android:fadingEdge">vertical</item>
<item name="android:fadingEdgeLength">50dip</item>
- <item name="android:solidColor">?android:attr/colorBackground</item>
+ <item name="android:solidColor">@android:color/transparent</item>
</style>
+ <!-- @hide -->
<style name="Widget.ImageButton.NumberPickerUpButton">
<item name="android:background">@android:drawable/timepicker_up_btn</item>
</style>
+ <!-- @hide -->
<style name="Widget.ImageButton.NumberPickerDownButton">
<item name="android:background">@android:drawable/timepicker_down_btn</item>
</style>
+ <!-- @hide -->
<style name="Widget.EditText.NumberPickerInputText">
<item name="android:textAppearance">@style/TextAppearance.Large.Inverse.NumberPickerInputText</item>
<item name="android:gravity">center</item>
@@ -834,6 +853,7 @@
<item name="android:textStyle">bold</item>
</style>
+ <!-- @hide -->
<style name="TextAppearance.Large.Inverse.NumberPickerInputText">
<item name="android:textColor">@android:color/primary_text_light</item>
<item name="android:textSize">30sp</item>
@@ -1200,6 +1220,11 @@
<item name="android:textSize">18sp</item>
</style>
+ <!-- @hide -->
+ <style name="TextAppearance.Holo.DayPickerWeekDayView" parent="TextAppearance.Small.DayPickerWeekDayView">
+ <item name="android:textColor">#505050</item>
+ </style>
+
<!-- Light text styles -->
<style name="TextAppearance.Holo.Light" parent="TextAppearance.Holo">
</style>
@@ -1296,6 +1321,10 @@
<item name="android:textSize">18sp</item>
</style>
+ <!-- @hide -->
+ <style name="TextAppearance.Holo.Light.DayPickerWeekDayView" parent="TextAppearance.Small.DayPickerWeekDayView">
+ </style>
+
<!-- Widget Styles -->
<style name="Widget.Holo" parent="Widget">
@@ -1406,22 +1435,35 @@
<item name="android:listSelector">?android:attr/selectableItemBackground</item>
</style>
+ <!-- @hide -->
+ <style name="Widget.Holo.DayPickerWeekView">
+ <item name="android:selectionBackgroundColor">#330099FF</item>
+ <item name="android:focusedMonthDateColor">#FFFFFFFF</item>
+ <item name="android:otherMonthDateColor">#66FFFFFF</item>
+ <item name="android:weekNumberColor">#33FFFFFF</item>
+ <item name="android:gridLinesColor">#19FFFFFF</item>
+ <item name="selectedDayLine">@android:drawable/simple_week_dayline_holo_light</item>
+ </style>
+
<style name="Widget.Holo.ImageButton" parent="Widget.ImageButton">
<item name="android:background">@android:drawable/btn_default_holo_dark</item>
</style>
+ <!-- @hide -->
<style name="Widget.Holo.ImageButton.NumberPickerUpButton">
<item name="android:background">@null</item>
<item name="android:paddingBottom">26sp</item>
<item name="android:src">@android:drawable/timepicker_up_btn_holo_dark</item>
</style>
+ <!-- @hide -->
<style name="Widget.Holo.ImageButton.NumberPickerDownButton">
<item name="android:background">@null</item>
<item name="android:paddingTop">26sp</item>
<item name="android:src">@android:drawable/timepicker_down_btn_holo_dark</item>
</style>
+ <!-- @hide -->
<style name="Widget.Holo.EditText.NumberPickerInputText">
<item name="android:paddingTop">13sp</item>
<item name="android:paddingBottom">13sp</item>
@@ -1767,14 +1809,21 @@
<item name="android:background">@android:drawable/btn_default_holo_light</item>
</style>
+ <!-- @hide -->
+ <style name="Widget.Holo.Light.DayPickerWeekView" parent="Widget.DayPickerWeekView">
+ </style>
+
+ <!-- @hide -->
<style name="Widget.Holo.Light.ImageButton.NumberPickerUpButton" parent="Widget.Holo.Light.ImageButton.NumberPickerUpButton">
<item name="android:background">@android:drawable/timepicker_up_btn_holo_light</item>
</style>
+ <!-- @hide -->
<style name="Widget.Holo.Light.ImageButton.NumberPickerDownButton" parent="Widget.Holo.ImageButton.NumberPickerDownButton">
<item name="android:background">@android:drawable/timepicker_down_btn_holo_light</item>
</style>
+ <!-- @hide -->
<style name="Widget.Holo.Light.EditText.NumberPickerInputText" parent="Widget.Holo.EditText.NumberPickerInputText">
</style>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 0f21e9f..94e8f96 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -26,7 +26,7 @@
of it a dark color.
-->
<style name="Theme">
-
+
<item name="colorForeground">@android:color/bright_foreground_dark</item>
<item name="colorForegroundInverse">@android:color/bright_foreground_dark_inverse</item>
<item name="colorBackground">@android:color/background_dark</item>
@@ -280,6 +280,12 @@
<item name="numberPickerInputTextStyle">@style/Widget.EditText.NumberPickerInputText</item>
<item name="numberPickerStyle">@style/Widget.NumberPicker</item>
+ <!-- DayPicker$WeekView style-->
+ <item name="dayPickerWeekViewStyle">@style/Widget.DayPickerWeekView</item>
+
+ <!-- DayPickerWeekDayView style-->
+ <item name="dayPickerWeekDayViewStyle">@style/TextAppearance.Small.DayPickerWeekDayView</item>
+
</style>
<!-- Variant of the default (dark) theme with no title bar -->
@@ -917,6 +923,12 @@
<item name="numberPickerDownButtonStyle">@style/Widget.Holo.ImageButton.NumberPickerDownButton</item>
<item name="numberPickerInputTextStyle">@style/Widget.Holo.EditText.NumberPickerInputText</item>
+ <!-- DayPicker$WeekView style-->
+ <item name="dayPickerWeekViewStyle">@style/Widget.Holo.DayPickerWeekView</item>
+
+ <!-- DayPickerWeekDayView style-->
+ <item name="dayPickerWeekDayViewStyle">@style/TextAppearance.Holo.DayPickerWeekDayView</item>
+
</style>
<!-- New Honeycomb holographic theme. Light version. The widgets in the
@@ -1162,6 +1174,12 @@
<item name="numberPickerDownButtonStyle">@style/Widget.Holo.Light.ImageButton.NumberPickerDownButton</item>
<item name="numberPickerInputTextStyle">@style/Widget.Holo.Light.EditText.NumberPickerInputText</item>
+ <!-- DayPicker$WeekView style-->
+ <item name="dayPickerWeekViewStyle">@style/Widget.Holo.Light.DayPickerWeekView</item>
+
+ <!-- DayPickerWeekDayView style-->
+ <item name="dayPickerWeekDayViewStyle">@style/TextAppearance.Holo.Light.DayPickerWeekDayView</item>
+
</style>
<!-- Development legacy name; if you're using this, switch. -->
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 6587b51..d4edafd 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -378,6 +378,12 @@
static BCCvoid* symbolLookup(BCCvoid* pContext, const BCCchar* name) {
const ScriptCState::SymbolTable_t *sym;
ScriptC *s = (ScriptC *)pContext;
+ if (!strcmp(name, "__isThreadable")) {
+ return (BCCvoid*) s->mEnviroment.mIsThreadable;
+ } else if (!strcmp(name, "__clearThreadable")) {
+ s->mEnviroment.mIsThreadable = false;
+ return NULL;
+ }
sym = ScriptCState::lookupSymbol(name);
if (!sym) {
sym = ScriptCState::lookupSymbolCL(name);
diff --git a/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
new file mode 100644
index 0000000..7d41d1c
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 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 android.animation;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+
+/**
+ * Delegate implementing the native methods of android.animation.PropertyValuesHolder
+ *
+ * Through the layoutlib_create tool, the original native methods of PropertyValuesHolder have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
+ *
+ * The main goal of this class' methods are to provide a native way to access setters and getters
+ * on some object. In this case we want to default to using Java reflection instead so the native
+ * methods do nothing.
+ *
+ */
+/*package*/ class PropertyValuesHolder_Delegate {
+
+ /*package*/ static int nGetIntMethod(Class<?> targetClass, String methodName) {
+ // return 0 to force PropertyValuesHolder to use Java reflection.
+ return 0;
+ }
+
+ /*package*/ static int nGetFloatMethod(Class<?> targetClass, String methodName) {
+ // return 0 to force PropertyValuesHolder to use Java reflection.
+ return 0;
+ }
+
+ /*package*/ static void nCallIntMethod(Object target, int methodID, int arg) {
+ // do nothing
+ }
+
+ /*package*/ static void nCallFloatMethod(Object target, int methodID, float arg) {
+ // do nothing
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
index d58cde8..0130970 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
@@ -458,16 +458,10 @@
mCanvas.setDensity(mParams.getDensity());
}
- long preDrawTime = System.currentTimeMillis();
-
mViewRoot.draw(mCanvas);
- long drawTime = System.currentTimeMillis();
-
mViewInfo = visit(((ViewGroup)mViewRoot).getChildAt(0), mContext);
- System.out.println(String.format("rendering (ms): %03d", drawTime - preDrawTime));
-
// success!
return SceneStatus.SUCCESS.createResult();
} catch (Throwable e) {
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 4440685..1d40d33 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -105,6 +105,7 @@
* The list of classes on which to delegate all native methods.
*/
private final static String[] DELEGATE_CLASS_NATIVES = new String[] {
+ "android.animation.PropertyValuesHolder",
"android.graphics.Bitmap",
"android.graphics.Canvas",
"android.graphics.DashPathEffect",