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