1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.contacts.datepicker;
18
19// This is a fork of the standard Android DatePicker that additionally allows toggling the year
20// on/off. It uses some private API so that not everything has to be copied.
21
22import android.app.AlertDialog;
23import android.content.Context;
24import android.content.DialogInterface;
25import android.content.DialogInterface.OnClickListener;
26import android.os.Build;
27import android.os.Bundle;
28import android.text.TextUtils.TruncateAt;
29import android.view.LayoutInflater;
30import android.view.View;
31import android.widget.TextView;
32
33import com.android.contacts.R;
34import com.android.contacts.datepicker.DatePicker.OnDateChangedListener;
35
36import java.text.DateFormatSymbols;
37import java.util.Calendar;
38
39/**
40 * A simple dialog containing an {@link DatePicker}.
41 *
42 * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date Picker
43 * tutorial</a>.</p>
44 */
45public class DatePickerDialog extends AlertDialog implements OnClickListener,
46        OnDateChangedListener {
47
48    private static final String YEAR = "year";
49    private static final String MONTH = "month";
50    private static final String DAY = "day";
51    private static final String YEAR_OPTIONAL = "year_optional";
52
53    private final DatePicker mDatePicker;
54    private final OnDateSetListener mCallBack;
55    private final Calendar mCalendar;
56    private final java.text.DateFormat mTitleDateFormat;
57    private final String[] mWeekDays;
58
59    private int mInitialYear;
60    private int mInitialMonth;
61    private int mInitialDay;
62
63    /**
64     * The callback used to indicate the user is done filling in the date.
65     */
66    public interface OnDateSetListener {
67        /**
68         * @param view The view associated with this listener.
69         * @param year The year that was set or 0 if the user has not specified a year
70         * @param monthOfYear The month that was set (0-11) for compatibility
71         *  with {@link java.util.Calendar}.
72         * @param dayOfMonth The day of the month that was set.
73         */
74        void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth);
75    }
76
77    /**
78     * @param context The context the dialog is to run in.
79     * @param callBack How the parent is notified that the date is set.
80     * @param year The initial year of the dialog
81     * @param monthOfYear The initial month of the dialog.
82     * @param dayOfMonth The initial day of the dialog.
83     */
84    public DatePickerDialog(Context context,
85            OnDateSetListener callBack,
86            int year,
87            int monthOfYear,
88            int dayOfMonth) {
89        this(context, callBack, year, monthOfYear, dayOfMonth, false);
90    }
91
92    /**
93     * @param context The context the dialog is to run in.
94     * @param callBack How the parent is notified that the date is set.
95     * @param year The initial year of the dialog or 0 if no year has been specified
96     * @param monthOfYear The initial month of the dialog.
97     * @param dayOfMonth The initial day of the dialog.
98     * @param yearOptional Whether the year can be toggled by the user
99     */
100    public DatePickerDialog(Context context,
101            OnDateSetListener callBack,
102            int year,
103            int monthOfYear,
104            int dayOfMonth,
105            boolean yearOptional) {
106        this(context, context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB
107                        ? com.android.internal.R.style.Theme_Holo_Light_Dialog_Alert
108                        : com.android.internal.R.style.Theme_Dialog_Alert,
109                callBack, year, monthOfYear, dayOfMonth, yearOptional);
110    }
111
112    /**
113     * @param context The context the dialog is to run in.
114     * @param theme the theme to apply to this dialog
115     * @param callBack How the parent is notified that the date is set.
116     * @param year The initial year of the dialog or 0 if no year has been specified
117     * @param monthOfYear The initial month of the dialog.
118     * @param dayOfMonth The initial day of the dialog.
119     */
120    public DatePickerDialog(Context context,
121            int theme,
122            OnDateSetListener callBack,
123            int year,
124            int monthOfYear,
125            int dayOfMonth) {
126        this(context, theme, callBack, year, monthOfYear, dayOfMonth, false);
127    }
128
129    /**
130     * @param context The context the dialog is to run in.
131     * @param theme the theme to apply to this dialog
132     * @param callBack How the parent is notified that the date is set.
133     * @param year The initial year of the dialog.
134     * @param monthOfYear The initial month of the dialog.
135     * @param dayOfMonth The initial day of the dialog.
136     * @param yearOptional Whether the year can be toggled by the user
137     */
138    public DatePickerDialog(Context context,
139            int theme,
140            OnDateSetListener callBack,
141            int year,
142            int monthOfYear,
143            int dayOfMonth,
144            boolean yearOptional) {
145        super(context, theme);
146
147        mCallBack = callBack;
148        mInitialYear = year;
149        mInitialMonth = monthOfYear;
150        mInitialDay = dayOfMonth;
151        DateFormatSymbols symbols = new DateFormatSymbols();
152        mWeekDays = symbols.getShortWeekdays();
153
154        mTitleDateFormat = java.text.DateFormat.
155                                getDateInstance(java.text.DateFormat.FULL);
156        mCalendar = Calendar.getInstance();
157        updateTitle(mInitialYear, mInitialMonth, mInitialDay);
158
159        setButton(BUTTON_POSITIVE, context.getText(com.android.internal.R.string.date_time_set),
160                this);
161        setButton(BUTTON_NEGATIVE, context.getText(android.R.string.cancel),
162                (OnClickListener) null);
163
164        LayoutInflater inflater =
165                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
166        View view = inflater.inflate(R.layout.date_picker_dialog, null);
167        setView(view);
168        mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
169        mDatePicker.init(mInitialYear, mInitialMonth, mInitialDay, yearOptional, this);
170    }
171
172    @Override
173    public void show() {
174        super.show();
175
176        /* Sometimes the full month is displayed causing the title
177         * to be very long, in those cases ensure it doesn't wrap to
178         * 2 lines (as that looks jumpy) and ensure we ellipsize the end.
179         */
180        TextView title = (TextView) findViewById(com.android.internal.R.id.alertTitle);
181        title.setSingleLine();
182        title.setEllipsize(TruncateAt.END);
183    }
184
185    public void onClick(DialogInterface dialog, int which) {
186        if (mCallBack != null) {
187            mDatePicker.clearFocus();
188            mCallBack.onDateSet(mDatePicker, mDatePicker.getYear(),
189                    mDatePicker.getMonth(), mDatePicker.getDayOfMonth());
190        }
191    }
192
193    public void onDateChanged(DatePicker view, int year,
194            int month, int day) {
195        updateTitle(year, month, day);
196    }
197
198    public void updateDate(int year, int monthOfYear, int dayOfMonth) {
199        mInitialYear = year;
200        mInitialMonth = monthOfYear;
201        mInitialDay = dayOfMonth;
202        mDatePicker.updateDate(year, monthOfYear, dayOfMonth);
203    }
204
205    private void updateTitle(int year, int month, int day) {
206        mCalendar.set(Calendar.YEAR, year);
207        mCalendar.set(Calendar.MONTH, month);
208        mCalendar.set(Calendar.DAY_OF_MONTH, day);
209        setTitle(mTitleDateFormat.format(mCalendar.getTime()));
210    }
211
212    @Override
213    public Bundle onSaveInstanceState() {
214        Bundle state = super.onSaveInstanceState();
215        state.putInt(YEAR, mDatePicker.getYear());
216        state.putInt(MONTH, mDatePicker.getMonth());
217        state.putInt(DAY, mDatePicker.getDayOfMonth());
218        state.putBoolean(YEAR_OPTIONAL, mDatePicker.isYearOptional());
219        return state;
220    }
221
222    @Override
223    public void onRestoreInstanceState(Bundle savedInstanceState) {
224        super.onRestoreInstanceState(savedInstanceState);
225        int year = savedInstanceState.getInt(YEAR);
226        int month = savedInstanceState.getInt(MONTH);
227        int day = savedInstanceState.getInt(DAY);
228        boolean yearOptional = savedInstanceState.getBoolean(YEAR_OPTIONAL);
229        mDatePicker.init(year, month, day, yearOptional, this);
230        updateTitle(year, month, day);
231    }
232}
233