1 /* 2 * Copyright (C) 2010 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.editor; 18 19 import com.android.contacts.R; 20 import com.android.contacts.datepicker.DatePicker; 21 import com.android.contacts.datepicker.DatePickerDialog; 22 import com.android.contacts.datepicker.DatePickerDialog.OnDateSetListener; 23 import com.android.contacts.model.AccountType.EditField; 24 import com.android.contacts.model.AccountType.EventEditType; 25 import com.android.contacts.model.DataKind; 26 import com.android.contacts.model.EntityDelta; 27 import com.android.contacts.model.EntityDelta.ValuesDelta; 28 import com.android.contacts.util.DateUtils; 29 30 import android.app.Dialog; 31 import android.content.Context; 32 import android.content.res.Resources; 33 import android.os.Bundle; 34 import android.text.TextUtils; 35 import android.util.AttributeSet; 36 import android.view.View; 37 import android.widget.Button; 38 39 import java.text.ParsePosition; 40 import java.util.Calendar; 41 import java.util.Date; 42 import java.util.Locale; 43 44 /** 45 * Editor that allows editing Events using a {@link DatePickerDialog} 46 */ 47 public class EventFieldEditorView extends LabeledEditorView { 48 /** 49 * Exchange requires 8:00 for birthdays 50 */ 51 private final static int DEFAULT_HOUR = 8; 52 53 /** 54 * Default string to show when there is no date selected yet. 55 */ 56 private String mNoDateString; 57 private int mPrimaryTextColor; 58 private int mSecondaryTextColor; 59 60 private Button mDateView; 61 EventFieldEditorView(Context context)62 public EventFieldEditorView(Context context) { 63 super(context); 64 } 65 EventFieldEditorView(Context context, AttributeSet attrs)66 public EventFieldEditorView(Context context, AttributeSet attrs) { 67 super(context, attrs); 68 } 69 EventFieldEditorView(Context context, AttributeSet attrs, int defStyle)70 public EventFieldEditorView(Context context, AttributeSet attrs, int defStyle) { 71 super(context, attrs, defStyle); 72 } 73 74 /** {@inheritDoc} */ 75 @Override onFinishInflate()76 protected void onFinishInflate() { 77 super.onFinishInflate(); 78 79 Resources resources = mContext.getResources(); 80 mPrimaryTextColor = resources.getColor(R.color.primary_text_color); 81 mSecondaryTextColor = resources.getColor(R.color.secondary_text_color); 82 mNoDateString = mContext.getString(R.string.event_edit_field_hint_text); 83 84 mDateView = (Button) findViewById(R.id.date_view); 85 mDateView.setOnClickListener(new OnClickListener() { 86 @Override 87 public void onClick(View v) { 88 showDialog(R.id.dialog_event_date_picker); 89 } 90 }); 91 } 92 93 @Override editNewlyAddedField()94 public void editNewlyAddedField() { 95 showDialog(R.id.dialog_event_date_picker); 96 } 97 98 @Override requestFocusForFirstEditField()99 protected void requestFocusForFirstEditField() { 100 mDateView.requestFocus(); 101 } 102 103 @Override setEnabled(boolean enabled)104 public void setEnabled(boolean enabled) { 105 super.setEnabled(enabled); 106 107 mDateView.setEnabled(!isReadOnly() && enabled); 108 } 109 110 @Override setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly, ViewIdGenerator vig)111 public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly, 112 ViewIdGenerator vig) { 113 if (kind.fieldList.size() != 1) throw new IllegalStateException("kind must have 1 field"); 114 super.setValues(kind, entry, state, readOnly, vig); 115 116 mDateView.setEnabled(isEnabled() && !readOnly); 117 118 rebuildDateView(); 119 } 120 rebuildDateView()121 private void rebuildDateView() { 122 final EditField editField = getKind().fieldList.get(0); 123 final String column = editField.column; 124 String data = DateUtils.formatDate(getContext(), getEntry().getAsString(column)); 125 if (TextUtils.isEmpty(data)) { 126 mDateView.setText(mNoDateString); 127 mDateView.setTextColor(mSecondaryTextColor); 128 setDeleteButtonVisible(false); 129 } else { 130 mDateView.setText(data); 131 mDateView.setTextColor(mPrimaryTextColor); 132 setDeleteButtonVisible(true); 133 } 134 } 135 136 @Override isEmpty()137 public boolean isEmpty() { 138 final EditField editField = getKind().fieldList.get(0); 139 final String column = editField.column; 140 return TextUtils.isEmpty(getEntry().getAsString(column)); 141 } 142 143 @Override createDialog(Bundle bundle)144 public Dialog createDialog(Bundle bundle) { 145 if (bundle == null) throw new IllegalArgumentException("bundle must not be null"); 146 int dialogId = bundle.getInt(DIALOG_ID_KEY); 147 switch (dialogId) { 148 case R.id.dialog_event_date_picker: 149 return createDatePickerDialog(); 150 default: 151 return super.createDialog(bundle); 152 } 153 } 154 155 @Override getType()156 protected EventEditType getType() { 157 return (EventEditType) super.getType(); 158 } 159 160 @Override onLabelRebuilt()161 protected void onLabelRebuilt() { 162 // if we changed to a type that requires a year, ensure that it is actually set 163 final String column = getKind().fieldList.get(0).column; 164 final String oldValue = getEntry().getAsString(column); 165 final DataKind kind = getKind(); 166 167 final Calendar calendar = Calendar.getInstance(DateUtils.UTC_TIMEZONE, Locale.US); 168 final int defaultYear = calendar.get(Calendar.YEAR); 169 170 // Check whether the year is optional 171 final boolean isYearOptional = getType().isYearOptional(); 172 173 if (!isYearOptional && !TextUtils.isEmpty(oldValue)) { 174 final ParsePosition position = new ParsePosition(0); 175 final Date date2 = kind.dateFormatWithoutYear.parse(oldValue, position); 176 177 // Don't understand the date, lets not change it 178 if (date2 == null) return; 179 180 // This value is missing the year. Add it now 181 calendar.setTime(date2); 182 calendar.set(defaultYear, calendar.get(Calendar.MONTH), 183 calendar.get(Calendar.DAY_OF_MONTH), DEFAULT_HOUR, 0, 0); 184 185 onFieldChanged(column, kind.dateFormatWithYear.format(calendar.getTime())); 186 rebuildDateView(); 187 } 188 } 189 190 /** 191 * Prepare dialog for entering a date 192 */ createDatePickerDialog()193 private Dialog createDatePickerDialog() { 194 final String column = getKind().fieldList.get(0).column; 195 final String oldValue = getEntry().getAsString(column); 196 final DataKind kind = getKind(); 197 198 final Calendar calendar = Calendar.getInstance(DateUtils.UTC_TIMEZONE, Locale.US); 199 final int defaultYear = calendar.get(Calendar.YEAR); 200 201 // Check whether the year is optional 202 final boolean isYearOptional = getType().isYearOptional(); 203 204 final int oldYear, oldMonth, oldDay; 205 if (TextUtils.isEmpty(oldValue)) { 206 // Default to January first, 30 years ago 207 oldYear = defaultYear; 208 oldMonth = 0; 209 oldDay = 1; 210 } else { 211 final ParsePosition position = new ParsePosition(0); 212 // Try parsing with year 213 Date date1 = kind.dateFormatWithYear.parse(oldValue, position); 214 if (date1 == null) { 215 // If that format does not fit, try guessing the right format 216 date1 = DateUtils.parseDate(oldValue); 217 } 218 if (date1 != null) { 219 calendar.setTime(date1); 220 oldYear = calendar.get(Calendar.YEAR); 221 oldMonth = calendar.get(Calendar.MONTH); 222 oldDay = calendar.get(Calendar.DAY_OF_MONTH); 223 } else { 224 final Date date2 = kind.dateFormatWithoutYear.parse(oldValue, position); 225 // Don't understand the date, lets not change it 226 if (date2 == null) return null; 227 calendar.setTime(date2); 228 oldYear = isYearOptional ? 0 : defaultYear; 229 oldMonth = calendar.get(Calendar.MONTH); 230 oldDay = calendar.get(Calendar.DAY_OF_MONTH); 231 } 232 } 233 final OnDateSetListener callBack = new OnDateSetListener() { 234 @Override 235 public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { 236 if (year == 0 && !isYearOptional) throw new IllegalStateException(); 237 final Calendar outCalendar = 238 Calendar.getInstance(DateUtils.UTC_TIMEZONE, Locale.US); 239 240 // If no year specified, set it to 2000 (we could pick any leap year here). 241 // The format string will ignore that year. 242 // For formats other than Exchange, the time of the day is ignored 243 outCalendar.clear(); 244 outCalendar.set(year == 0 ? 2000 : year, monthOfYear, dayOfMonth, 245 DEFAULT_HOUR, 0, 0); 246 247 final String resultString; 248 if (year == 0) { 249 resultString = kind.dateFormatWithoutYear.format(outCalendar.getTime()); 250 } else { 251 resultString = kind.dateFormatWithYear.format(outCalendar.getTime()); 252 } 253 254 onFieldChanged(column, resultString); 255 rebuildDateView(); 256 } 257 }; 258 final DatePickerDialog resultDialog = new DatePickerDialog(getContext(), callBack, 259 oldYear, oldMonth, oldDay, isYearOptional); 260 return resultDialog; 261 } 262 263 /** 264 * @return Default hour which should be used for birthday field. 265 */ getDefaultHourForBirthday()266 public static int getDefaultHourForBirthday() { 267 return DEFAULT_HOUR; 268 } 269 270 @Override clearAllFields()271 public void clearAllFields() { 272 // Update UI 273 mDateView.setText(mNoDateString); 274 mDateView.setTextColor(mSecondaryTextColor); 275 276 // Update state 277 final String column = getKind().fieldList.get(0).column; 278 onFieldChanged(column, ""); 279 } 280 } 281