/* * Copyright (C) 2007 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.app; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StyleRes; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.os.Bundle; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.DatePicker; import android.widget.DatePicker.OnDateChangedListener; import android.widget.DatePicker.ValidationCallback; import com.android.internal.R; import java.util.Calendar; /** * A simple dialog containing an {@link android.widget.DatePicker}. * <p> * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a> * guide. */ public class DatePickerDialog extends AlertDialog implements OnClickListener, OnDateChangedListener { private static final String YEAR = "year"; private static final String MONTH = "month"; private static final String DAY = "day"; private final DatePicker mDatePicker; private OnDateSetListener mDateSetListener; /** * Creates a new date picker dialog for the current date using the parent * context's default date picker dialog theme. * * @param context the parent context */ public DatePickerDialog(@NonNull Context context) { this(context, 0, null, Calendar.getInstance(), -1, -1, -1); } /** * Creates a new date picker dialog for the current date. * * @param context the parent context * @param themeResId the resource ID of the theme against which to inflate * this dialog, or {@code 0} to use the parent * {@code context}'s default alert dialog theme */ public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId) { this(context, themeResId, null, Calendar.getInstance(), -1, -1, -1); } /** * Creates a new date picker dialog for the specified date using the parent * context's default date picker dialog theme. * * @param context the parent context * @param listener the listener to call when the user sets the date * @param year the initially selected year * @param month the initially selected month (0-11 for compatibility with * {@link Calendar#MONTH}) * @param dayOfMonth the initially selected day of month (1-31, depending * on month) */ public DatePickerDialog(@NonNull Context context, @Nullable OnDateSetListener listener, int year, int month, int dayOfMonth) { this(context, 0, listener, null, year, month, dayOfMonth); } /** * Creates a new date picker dialog for the specified date. * * @param context the parent context * @param themeResId the resource ID of the theme against which to inflate * this dialog, or {@code 0} to use the parent * {@code context}'s default alert dialog theme * @param listener the listener to call when the user sets the date * @param year the initially selected year * @param monthOfYear the initially selected month of the year (0-11 for * compatibility with {@link Calendar#MONTH}) * @param dayOfMonth the initially selected day of month (1-31, depending * on month) */ public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId, @Nullable OnDateSetListener listener, int year, int monthOfYear, int dayOfMonth) { this(context, themeResId, listener, null, year, monthOfYear, dayOfMonth); } private DatePickerDialog(@NonNull Context context, @StyleRes int themeResId, @Nullable OnDateSetListener listener, @Nullable Calendar calendar, int year, int monthOfYear, int dayOfMonth) { super(context, resolveDialogTheme(context, themeResId)); final Context themeContext = getContext(); final LayoutInflater inflater = LayoutInflater.from(themeContext); final View view = inflater.inflate(R.layout.date_picker_dialog, null); setView(view); setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this); setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this); setButtonPanelLayoutHint(LAYOUT_HINT_SIDE); if (calendar != null) { year = calendar.get(Calendar.YEAR); monthOfYear = calendar.get(Calendar.MONTH); dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); } mDatePicker = (DatePicker) view.findViewById(R.id.datePicker); mDatePicker.init(year, monthOfYear, dayOfMonth, this); mDatePicker.setValidationCallback(mValidationCallback); mDateSetListener = listener; } static @StyleRes int resolveDialogTheme(@NonNull Context context, @StyleRes int themeResId) { if (themeResId == 0) { final TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(R.attr.datePickerDialogTheme, outValue, true); return outValue.resourceId; } else { return themeResId; } } @Override public void onDateChanged(@NonNull DatePicker view, int year, int month, int dayOfMonth) { mDatePicker.init(year, month, dayOfMonth, this); } /** * Sets the listener to call when the user sets the date. * * @param listener the listener to call when the user sets the date */ public void setOnDateSetListener(@Nullable OnDateSetListener listener) { mDateSetListener = listener; } @Override public void onClick(@NonNull DialogInterface dialog, int which) { switch (which) { case BUTTON_POSITIVE: if (mDateSetListener != null) { // Clearing focus forces the dialog to commit any pending // changes, e.g. typed text in a NumberPicker. mDatePicker.clearFocus(); mDateSetListener.onDateSet(mDatePicker, mDatePicker.getYear(), mDatePicker.getMonth(), mDatePicker.getDayOfMonth()); } break; case BUTTON_NEGATIVE: cancel(); break; } } /** * Returns the {@link DatePicker} contained in this dialog. * * @return the date picker */ @NonNull public DatePicker getDatePicker() { return mDatePicker; } /** * Sets the current date. * * @param year the year * @param month the month (0-11 for compatibility with * {@link Calendar#MONTH}) * @param dayOfMonth the day of month (1-31, depending on month) */ public void updateDate(int year, int month, int dayOfMonth) { mDatePicker.updateDate(year, month, dayOfMonth); } @Override public Bundle onSaveInstanceState() { final Bundle state = super.onSaveInstanceState(); state.putInt(YEAR, mDatePicker.getYear()); state.putInt(MONTH, mDatePicker.getMonth()); state.putInt(DAY, mDatePicker.getDayOfMonth()); return state; } @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); final int year = savedInstanceState.getInt(YEAR); final int month = savedInstanceState.getInt(MONTH); final int day = savedInstanceState.getInt(DAY); mDatePicker.init(year, month, day, this); } private final ValidationCallback mValidationCallback = new ValidationCallback() { @Override public void onValidationChanged(boolean valid) { final Button positive = getButton(BUTTON_POSITIVE); if (positive != null) { positive.setEnabled(valid); } } }; /** * The listener used to indicate the user has finished selecting a date. */ public interface OnDateSetListener { /** * @param view the picker associated with the dialog * @param year the selected year * @param month the selected month (0-11 for compatibility with * {@link Calendar#MONTH}) * @param dayOfMonth th selected day of the month (1-31, depending on * month) */ void onDateSet(DatePicker view, int year, int month, int dayOfMonth); } }