Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5a7a2696 authored by Daniel Lehmann's avatar Daniel Lehmann
Browse files

Fix support for birthday on February 29th with year omitted

Bug:6260151
Change-Id: Ib78e8bfc30dd5d9554c1f82f9617f7abacb5ce78
parent 91e44c64
Loading
Loading
Loading
Loading
+9 −7
Original line number Diff line number Diff line
@@ -54,6 +54,8 @@ import java.util.Calendar;
 */
@Widget
public class DatePicker extends FrameLayout {
    /** Magic year that represents "no year" */
    public static int NO_YEAR = 0;

    private static final int DEFAULT_START_YEAR = 1900;
    private static final int DEFAULT_END_YEAR = 2100;
@@ -83,7 +85,7 @@ public class DatePicker extends FrameLayout {

        /**
         * @param view The view associated with this listener.
         * @param year The year that was set.
         * @param year The year that was set or {@link DatePicker#NO_YEAR} if no year was set
         * @param monthOfYear The month that was set (0-11) for compatibility
         *  with {@link java.util.Calendar}.
         * @param dayOfMonth The day of the month that was set.
@@ -279,7 +281,7 @@ public class DatePicker extends FrameLayout {

    public void updateDate(int year, int monthOfYear, int dayOfMonth) {
        if (mYear != year || mMonth != monthOfYear || mDay != dayOfMonth) {
            mYear = (mYearOptional && year == 0) ? getCurrentYear() : year;
            mYear = (mYearOptional && year == NO_YEAR) ? getCurrentYear() : year;
            mMonth = monthOfYear;
            mDay = dayOfMonth;
            updateSpinners();
@@ -413,7 +415,7 @@ public class DatePicker extends FrameLayout {

    /**
     * Initialize the state.
     * @param year The initial year or 0 if no year has been specified
     * @param year The initial year or {@link #NO_YEAR} if no year has been specified
     * @param monthOfYear The initial month.
     * @param dayOfMonth The initial day of the month.
     * @param yearOptional True if the user can toggle the year
@@ -421,11 +423,11 @@ public class DatePicker extends FrameLayout {
     */
    public void init(int year, int monthOfYear, int dayOfMonth, boolean yearOptional,
            OnDateChangedListener onDateChangedListener) {
        mYear = (yearOptional && year == 0) ? getCurrentYear() : year;
        mYear = (yearOptional && year == NO_YEAR) ? getCurrentYear() : year;
        mMonth = monthOfYear;
        mDay = dayOfMonth;
        mYearOptional = yearOptional;
        mHasYear = yearOptional ? (year != 0) : true;
        mHasYear = yearOptional ? (year != NO_YEAR) : true;
        mOnDateChangedListener = onDateChangedListener;
        updateSpinners();
    }
@@ -454,7 +456,7 @@ public class DatePicker extends FrameLayout {
    }

    public int getYear() {
        return (mYearOptional && !mHasYear) ? 0 : mYear;
        return (mYearOptional && !mHasYear) ? NO_YEAR : mYear;
    }

    public boolean isYearOptional() {
@@ -482,7 +484,7 @@ public class DatePicker extends FrameLayout {

    private void notifyDateChanged() {
        if (mOnDateChangedListener != null) {
            int year = (mYearOptional && !mHasYear) ? 0 : mYear;
            int year = (mYearOptional && !mHasYear) ? NO_YEAR : mYear;
            mOnDateChangedListener.onDateChanged(DatePicker.this, year, mMonth, mDay);
        }
    }
+17 −11
Original line number Diff line number Diff line
@@ -47,6 +47,9 @@ import java.util.Calendar;
public class DatePickerDialog extends AlertDialog implements OnClickListener,
        OnDateChangedListener {

    /** Magic year that represents "no year" */
    public static int NO_YEAR = DatePicker.NO_YEAR;

    private static final String YEAR = "year";
    private static final String MONTH = "month";
    private static final String DAY = "day";
@@ -54,7 +57,6 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,

    private final DatePicker mDatePicker;
    private final OnDateSetListener mCallBack;
    private final Calendar mCalendar;
    private final DateFormat mTitleDateFormat;
    private final DateFormat mTitleNoYearDateFormat;

@@ -68,7 +70,8 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
    public interface OnDateSetListener {
        /**
         * @param view The view associated with this listener.
         * @param year The year that was set or 0 if the user has not specified a year
         * @param year The year that was set or {@link DatePickerDialog#NO_YEAR} if the user has
         *  not specified a year
         * @param monthOfYear The month that was set (0-11) for compatibility
         *  with {@link java.util.Calendar}.
         * @param dayOfMonth The day of the month that was set.
@@ -94,7 +97,8 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
    /**
     * @param context The context the dialog is to run in.
     * @param callBack How the parent is notified that the date is set.
     * @param year The initial year of the dialog or 0 if no year has been specified
     * @param year The initial year of the dialog or {@link DatePickerDialog#NO_YEAR} if no year
     *  has been specified
     * @param monthOfYear The initial month of the dialog.
     * @param dayOfMonth The initial day of the dialog.
     * @param yearOptional Whether the year can be toggled by the user
@@ -115,7 +119,8 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
     * @param context The context the dialog is to run in.
     * @param theme the theme to apply to this dialog
     * @param callBack How the parent is notified that the date is set.
     * @param year The initial year of the dialog or 0 if no year has been specified
     * @param year The initial year of the dialog or {@link DatePickerDialog#NO_YEAR} if no year
     *  has been specified
     * @param monthOfYear The initial month of the dialog.
     * @param dayOfMonth The initial day of the dialog.
     */
@@ -132,7 +137,8 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
     * @param context The context the dialog is to run in.
     * @param theme the theme to apply to this dialog
     * @param callBack How the parent is notified that the date is set.
     * @param year The initial year of the dialog.
     * @param year The initial year of the dialog or {@link DatePickerDialog#NO_YEAR} if no
     *  year has been specified.
     * @param monthOfYear The initial month of the dialog.
     * @param dayOfMonth The initial day of the dialog.
     * @param yearOptional Whether the year can be toggled by the user
@@ -154,7 +160,6 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
        mTitleDateFormat = DateFormat.getDateInstance(DateFormat.FULL);
        mTitleNoYearDateFormat = new SimpleDateFormat(
                DateUtils.isMonthBeforeDay(getContext()) ? "MMMM dd" : "dd MMMM");
        mCalendar = Calendar.getInstance();
        updateTitle(mInitialYear, mInitialMonth, mInitialDay);

        setButton(BUTTON_POSITIVE, context.getText(com.android.internal.R.string.date_time_set),
@@ -205,12 +210,13 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener,
    }

    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);
        final Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month);
        calendar.set(Calendar.DAY_OF_MONTH, day);
        final DateFormat dateFormat =
                year == 0 ? mTitleNoYearDateFormat : mTitleDateFormat;
        setTitle(dateFormat.format(mCalendar.getTime()));
                year == NO_YEAR ? mTitleNoYearDateFormat : mTitleDateFormat;
        setTitle(dateFormat.format(calendar.getTime()));
    }

    @Override
+22 −10
Original line number Diff line number Diff line
@@ -203,7 +203,7 @@ public class EventFieldEditorView extends LabeledEditorView {

        final int oldYear, oldMonth, oldDay;
        if (TextUtils.isEmpty(oldValue)) {
            // Default to January first, 30 years ago
            // Default to January first of this year
            oldYear = defaultYear;
            oldMonth = 0;
            oldDay = 1;
@@ -220,16 +220,28 @@ public class EventFieldEditorView extends LabeledEditorView {
                oldYear = calendar.get(Calendar.YEAR);
                oldMonth = calendar.get(Calendar.MONTH);
                oldDay = calendar.get(Calendar.DAY_OF_MONTH);
            } else {
                // Unfortunately, we need a one-off hack for February 29th, because
                // the parse functions assume 1970, which wasn't a leap year
                // Caveat here: This won't catch AccountTypes that allow omitting the year but
                // require a time of the day. But as we don't have any of those at the moment,
                // this shouldn't be an issue
                if (DateUtils.NO_YEAR_DATE_FEB29TH.equals(oldValue)) {
                    oldYear = isYearOptional ? DatePickerDialog.NO_YEAR : defaultYear;
                    oldMonth = Calendar.FEBRUARY;
                    oldDay = 29;
                } else {
                    final Date date2 = kind.dateFormatWithoutYear.parse(oldValue, position);
                // Don't understand the date, lets not change it
                    // Don't understand the date? Let's not show any dialog
                    if (date2 == null) return null;

                    calendar.setTime(date2);
                oldYear = isYearOptional ? 0 : defaultYear;
                    oldYear = isYearOptional ? DatePickerDialog.NO_YEAR : defaultYear;
                    oldMonth = calendar.get(Calendar.MONTH);
                    oldDay = calendar.get(Calendar.DAY_OF_MONTH);
                }
            }
        }
        final OnDateSetListener callBack = new OnDateSetListener() {
            @Override
            public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
@@ -241,8 +253,8 @@ public class EventFieldEditorView extends LabeledEditorView {
                // The format string will ignore that year.
                // For formats other than Exchange, the time of the day is ignored
                outCalendar.clear();
                outCalendar.set(year == 0 ? 2000 : year, monthOfYear, dayOfMonth,
                        DEFAULT_HOUR, 0, 0);
                outCalendar.set(year == DatePickerDialog.NO_YEAR ? 2000 : year, monthOfYear,
                        dayOfMonth, DEFAULT_HOUR, 0, 0);

                final String resultString;
                if (year == 0) {
+25 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.text.format.DateFormat;

import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
@@ -34,6 +35,11 @@ public class DateUtils {
    // All the SimpleDateFormats in this class use the UTC timezone
    public static final SimpleDateFormat NO_YEAR_DATE_FORMAT =
            new SimpleDateFormat("--MM-dd", Locale.US);
    /**
     * When parsing a date without a year, the system assumes 1970, which wasn't a leap-year.
     * Let's add a one-off hack for that day of the year
     */
    public static final String NO_YEAR_DATE_FEB29TH = "--02-29";
    public static final SimpleDateFormat FULL_DATE_FORMAT =
            new SimpleDateFormat("yyyy-MM-dd", Locale.US);
    public static final SimpleDateFormat DATE_AND_TIME_FORMAT =
@@ -88,6 +94,14 @@ public class DateUtils {
        return null;
    }

    private static final Date getUtcDate(int year, int month, int dayOfMonth) {
        final Calendar calendar = Calendar.getInstance(UTC_TIMEZONE, Locale.US);
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month);
        calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        return calendar.getTime();
    }

    /**
     * Parses the supplied string to see if it looks like a date. If so,
     * returns the same date in a cleaned-up format for the user.  Otherwise, returns
@@ -105,13 +119,21 @@ public class DateUtils {

        ParsePosition parsePosition = new ParsePosition(0);

        final boolean noYearParsed;
        Date date;

        // Unfortunately, we can't parse Feb 29th correctly, so let's handle this day seperately
        if (NO_YEAR_DATE_FEB29TH.equals(string)) {
            date = getUtcDate(0, Calendar.FEBRUARY, 29);
            noYearParsed = true;
        } else {
            synchronized (NO_YEAR_DATE_FORMAT) {
                date = NO_YEAR_DATE_FORMAT.parse(string, parsePosition);
            }
            noYearParsed = parsePosition.getIndex() == string.length();
        }

        if (parsePosition.getIndex() == string.length()) {
        if (noYearParsed) {
            java.text.DateFormat outFormat = isMonthBeforeDay(context)
                    ? FORMAT_WITHOUT_YEAR_MONTH_FIRST
                    : FORMAT_WITHOUT_YEAR_DAY_FIRST;