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 17 package android.app; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.StyleRes; 22 import android.content.Context; 23 import android.content.DialogInterface; 24 import android.content.DialogInterface.OnClickListener; 25 import android.os.Bundle; 26 import android.util.TypedValue; 27 import android.view.LayoutInflater; 28 import android.view.View; 29 import android.widget.Button; 30 import android.widget.DatePicker; 31 import android.widget.DatePicker.OnDateChangedListener; 32 import android.widget.DatePicker.ValidationCallback; 33 34 import com.android.internal.R; 35 36 import java.util.Calendar; 37 38 /** 39 * A simple dialog containing an {@link android.widget.DatePicker}. 40 * <p> 41 * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a> 42 * guide. 43 */ 44 public class DatePickerDialog extends AlertDialog implements OnClickListener, 45 OnDateChangedListener { 46 private static final String YEAR = "year"; 47 private static final String MONTH = "month"; 48 private static final String DAY = "day"; 49 50 private final DatePicker mDatePicker; 51 52 private OnDateSetListener mDateSetListener; 53 54 /** 55 * Creates a new date picker dialog for the current date using the parent 56 * context's default date picker dialog theme. 57 * 58 * @param context the parent context 59 */ DatePickerDialog(@onNull Context context)60 public DatePickerDialog(@NonNull Context context) { 61 this(context, 0, null, Calendar.getInstance(), -1, -1, -1); 62 } 63 64 /** 65 * Creates a new date picker dialog for the current date. 66 * 67 * @param context the parent context 68 * @param themeResId the resource ID of the theme against which to inflate 69 * this dialog, or {@code 0} to use the parent 70 * {@code context}'s default alert dialog theme 71 */ DatePickerDialog(@onNull Context context, @StyleRes int themeResId)72 public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId) { 73 this(context, themeResId, null, Calendar.getInstance(), -1, -1, -1); 74 } 75 76 /** 77 * Creates a new date picker dialog for the specified date using the parent 78 * context's default date picker dialog theme. 79 * 80 * @param context the parent context 81 * @param listener the listener to call when the user sets the date 82 * @param year the initially selected year 83 * @param month the initially selected month (0-11 for compatibility with 84 * {@link Calendar#MONTH}) 85 * @param dayOfMonth the initially selected day of month (1-31, depending 86 * on month) 87 */ DatePickerDialog(@onNull Context context, @Nullable OnDateSetListener listener, int year, int month, int dayOfMonth)88 public DatePickerDialog(@NonNull Context context, @Nullable OnDateSetListener listener, 89 int year, int month, int dayOfMonth) { 90 this(context, 0, listener, null, year, month, dayOfMonth); 91 } 92 93 /** 94 * Creates a new date picker dialog for the specified date. 95 * 96 * @param context the parent context 97 * @param themeResId the resource ID of the theme against which to inflate 98 * this dialog, or {@code 0} to use the parent 99 * {@code context}'s default alert dialog theme 100 * @param listener the listener to call when the user sets the date 101 * @param year the initially selected year 102 * @param monthOfYear the initially selected month of the year (0-11 for 103 * compatibility with {@link Calendar#MONTH}) 104 * @param dayOfMonth the initially selected day of month (1-31, depending 105 * on month) 106 */ DatePickerDialog(@onNull Context context, @StyleRes int themeResId, @Nullable OnDateSetListener listener, int year, int monthOfYear, int dayOfMonth)107 public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId, 108 @Nullable OnDateSetListener listener, int year, int monthOfYear, int dayOfMonth) { 109 this(context, themeResId, listener, null, year, monthOfYear, dayOfMonth); 110 } 111 DatePickerDialog(@onNull Context context, @StyleRes int themeResId, @Nullable OnDateSetListener listener, @Nullable Calendar calendar, int year, int monthOfYear, int dayOfMonth)112 private DatePickerDialog(@NonNull Context context, @StyleRes int themeResId, 113 @Nullable OnDateSetListener listener, @Nullable Calendar calendar, int year, 114 int monthOfYear, int dayOfMonth) { 115 super(context, resolveDialogTheme(context, themeResId)); 116 117 final Context themeContext = getContext(); 118 final LayoutInflater inflater = LayoutInflater.from(themeContext); 119 final View view = inflater.inflate(R.layout.date_picker_dialog, null); 120 setView(view); 121 122 setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this); 123 setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this); 124 setButtonPanelLayoutHint(LAYOUT_HINT_SIDE); 125 126 if (calendar != null) { 127 year = calendar.get(Calendar.YEAR); 128 monthOfYear = calendar.get(Calendar.MONTH); 129 dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); 130 } 131 132 mDatePicker = (DatePicker) view.findViewById(R.id.datePicker); 133 mDatePicker.init(year, monthOfYear, dayOfMonth, this); 134 mDatePicker.setValidationCallback(mValidationCallback); 135 136 mDateSetListener = listener; 137 } 138 resolveDialogTheme(@onNull Context context, @StyleRes int themeResId)139 static @StyleRes int resolveDialogTheme(@NonNull Context context, @StyleRes int themeResId) { 140 if (themeResId == 0) { 141 final TypedValue outValue = new TypedValue(); 142 context.getTheme().resolveAttribute(R.attr.datePickerDialogTheme, outValue, true); 143 return outValue.resourceId; 144 } else { 145 return themeResId; 146 } 147 } 148 149 @Override onDateChanged(@onNull DatePicker view, int year, int month, int dayOfMonth)150 public void onDateChanged(@NonNull DatePicker view, int year, int month, int dayOfMonth) { 151 mDatePicker.init(year, month, dayOfMonth, this); 152 } 153 154 /** 155 * Sets the listener to call when the user sets the date. 156 * 157 * @param listener the listener to call when the user sets the date 158 */ setOnDateSetListener(@ullable OnDateSetListener listener)159 public void setOnDateSetListener(@Nullable OnDateSetListener listener) { 160 mDateSetListener = listener; 161 } 162 163 @Override onClick(@onNull DialogInterface dialog, int which)164 public void onClick(@NonNull DialogInterface dialog, int which) { 165 switch (which) { 166 case BUTTON_POSITIVE: 167 if (mDateSetListener != null) { 168 // Clearing focus forces the dialog to commit any pending 169 // changes, e.g. typed text in a NumberPicker. 170 mDatePicker.clearFocus(); 171 mDateSetListener.onDateSet(mDatePicker, mDatePicker.getYear(), 172 mDatePicker.getMonth(), mDatePicker.getDayOfMonth()); 173 } 174 break; 175 case BUTTON_NEGATIVE: 176 cancel(); 177 break; 178 } 179 } 180 181 /** 182 * Returns the {@link DatePicker} contained in this dialog. 183 * 184 * @return the date picker 185 */ 186 @NonNull getDatePicker()187 public DatePicker getDatePicker() { 188 return mDatePicker; 189 } 190 191 /** 192 * Sets the current date. 193 * 194 * @param year the year 195 * @param month the month (0-11 for compatibility with 196 * {@link Calendar#MONTH}) 197 * @param dayOfMonth the day of month (1-31, depending on month) 198 */ updateDate(int year, int month, int dayOfMonth)199 public void updateDate(int year, int month, int dayOfMonth) { 200 mDatePicker.updateDate(year, month, dayOfMonth); 201 } 202 203 @Override onSaveInstanceState()204 public Bundle onSaveInstanceState() { 205 final Bundle state = super.onSaveInstanceState(); 206 state.putInt(YEAR, mDatePicker.getYear()); 207 state.putInt(MONTH, mDatePicker.getMonth()); 208 state.putInt(DAY, mDatePicker.getDayOfMonth()); 209 return state; 210 } 211 212 @Override onRestoreInstanceState(Bundle savedInstanceState)213 public void onRestoreInstanceState(Bundle savedInstanceState) { 214 super.onRestoreInstanceState(savedInstanceState); 215 final int year = savedInstanceState.getInt(YEAR); 216 final int month = savedInstanceState.getInt(MONTH); 217 final int day = savedInstanceState.getInt(DAY); 218 mDatePicker.init(year, month, day, this); 219 } 220 221 private final ValidationCallback mValidationCallback = new ValidationCallback() { 222 @Override 223 public void onValidationChanged(boolean valid) { 224 final Button positive = getButton(BUTTON_POSITIVE); 225 if (positive != null) { 226 positive.setEnabled(valid); 227 } 228 } 229 }; 230 231 /** 232 * The listener used to indicate the user has finished selecting a date. 233 */ 234 public interface OnDateSetListener { 235 /** 236 * @param view the picker associated with the dialog 237 * @param year the selected year 238 * @param month the selected month (0-11 for compatibility with 239 * {@link Calendar#MONTH}) 240 * @param dayOfMonth th selected day of the month (1-31, depending on 241 * month) 242 */ onDateSet(DatePicker view, int year, int month, int dayOfMonth)243 void onDateSet(DatePicker view, int year, int month, int dayOfMonth); 244 } 245 } 246