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 android.app.Dialog; 20 import android.content.Context; 21 import android.content.res.Resources; 22 import android.os.Bundle; 23 import android.provider.ContactsContract.CommonDataKinds.Event; 24 import android.text.TextUtils; 25 import android.util.AttributeSet; 26 import android.view.View; 27 import android.widget.Button; 28 29 import com.android.contacts.R; 30 import com.android.contacts.datepicker.DatePicker; 31 import com.android.contacts.datepicker.DatePickerDialog; 32 import com.android.contacts.datepicker.DatePickerDialog.OnDateSetListener; 33 import com.android.contacts.model.RawContactDelta; 34 import com.android.contacts.model.ValuesDelta; 35 import com.android.contacts.model.account.AccountType.EditField; 36 import com.android.contacts.model.account.AccountType.EventEditType; 37 import com.android.contacts.model.dataitem.DataKind; 38 import com.android.contacts.util.CommonDateUtils; 39 import com.android.contacts.util.DateUtils; 40 41 import java.text.ParsePosition; 42 import java.util.Calendar; 43 import java.util.Date; 44 import java.util.Locale; 45 46 /** 47 * Editor that allows editing Events using a {@link DatePickerDialog} 48 */ 49 public class EventFieldEditorView extends LabeledEditorView { 50 51 /** 52 * Default string to show when there is no date selected yet. 53 */ 54 private String mNoDateString; 55 private int mPrimaryTextColor; 56 private int mHintTextColor; 57 58 private Button mDateView; 59 EventFieldEditorView(Context context)60 public EventFieldEditorView(Context context) { 61 super(context); 62 } 63 EventFieldEditorView(Context context, AttributeSet attrs)64 public EventFieldEditorView(Context context, AttributeSet attrs) { 65 super(context, attrs); 66 } 67 EventFieldEditorView(Context context, AttributeSet attrs, int defStyle)68 public EventFieldEditorView(Context context, AttributeSet attrs, int defStyle) { 69 super(context, attrs, defStyle); 70 } 71 72 /** {@inheritDoc} */ 73 @Override onFinishInflate()74 protected void onFinishInflate() { 75 super.onFinishInflate(); 76 77 Resources resources = getContext().getResources(); 78 mPrimaryTextColor = resources.getColor(R.color.primary_text_color); 79 mHintTextColor = resources.getColor(R.color.editor_disabled_text_color); 80 mNoDateString = getContext().getString(R.string.event_edit_field_hint_text); 81 82 mDateView = (Button) findViewById(R.id.date_view); 83 mDateView.setOnClickListener(new OnClickListener() { 84 @Override 85 public void onClick(View v) { 86 showDialog(R.id.dialog_event_date_picker); 87 } 88 }); 89 } 90 91 @Override editNewlyAddedField()92 public void editNewlyAddedField() { 93 showDialog(R.id.dialog_event_date_picker); 94 } 95 96 @Override requestFocusForFirstEditField()97 protected void requestFocusForFirstEditField() { 98 mDateView.requestFocus(); 99 } 100 101 @Override setEnabled(boolean enabled)102 public void setEnabled(boolean enabled) { 103 super.setEnabled(enabled); 104 105 mDateView.setEnabled(!isReadOnly() && enabled); 106 } 107 108 @Override setValues(DataKind kind, ValuesDelta entry, RawContactDelta state, boolean readOnly, ViewIdGenerator vig)109 public void setValues(DataKind kind, ValuesDelta entry, RawContactDelta state, boolean readOnly, 110 ViewIdGenerator vig) { 111 if (kind.fieldList.size() != 1) throw new IllegalStateException("kind must have 1 field"); 112 super.setValues(kind, entry, state, readOnly, vig); 113 114 mDateView.setEnabled(isEnabled() && !readOnly); 115 116 rebuildDateView(); 117 updateEmptiness(); 118 } 119 rebuildDateView()120 private void rebuildDateView() { 121 final EditField editField = getKind().fieldList.get(0); 122 final String column = editField.column; 123 String data = DateUtils.formatDate(getContext(), getEntry().getAsString(column), 124 false /*Use the short DateFormat to ensure that it fits inside the EditText*/); 125 if (TextUtils.isEmpty(data)) { 126 mDateView.setText(mNoDateString); 127 mDateView.setTextColor(mHintTextColor); 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 if (dialogId == R.id.dialog_event_date_picker) { 148 return createDatePickerDialog(); 149 } else { 150 return super.createDialog(bundle); 151 } 152 } 153 154 @Override getType()155 protected EventEditType getType() { 156 return (EventEditType) super.getType(); 157 } 158 159 @Override onLabelRebuilt()160 protected void onLabelRebuilt() { 161 // if we changed to a type that requires a year, ensure that it is actually set 162 final String column = getKind().fieldList.get(0).column; 163 final String oldValue = getEntry().getAsString(column); 164 final DataKind kind = getKind(); 165 166 final Calendar calendar = Calendar.getInstance(DateUtils.UTC_TIMEZONE, Locale.US); 167 final int defaultYear = calendar.get(Calendar.YEAR); 168 169 // Check whether the year is optional 170 final boolean isYearOptional = getType() != null && getType().isYearOptional(); 171 172 if (!isYearOptional && !TextUtils.isEmpty(oldValue)) { 173 final ParsePosition position = new ParsePosition(0); 174 final Date date2 = kind.dateFormatWithoutYear == null 175 ? null : 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), CommonDateUtils.DEFAULT_HOUR, 0, 0); 184 185 final String formattedDate = kind.dateFormatWithYear == null 186 ? null : kind.dateFormatWithYear.format(calendar.getTime()); 187 if (formattedDate == null) return; 188 189 onFieldChanged(column, formattedDate); 190 rebuildDateView(); 191 } 192 } 193 194 /** 195 * Prepare dialog for entering a date 196 */ createDatePickerDialog()197 private Dialog createDatePickerDialog() { 198 final String column = getKind().fieldList.get(0).column; 199 final String oldValue = getEntry().getAsString(column); 200 final DataKind kind = getKind(); 201 202 final Calendar calendar = Calendar.getInstance(DateUtils.UTC_TIMEZONE, Locale.US); 203 final int defaultYear = calendar.get(Calendar.YEAR); 204 205 // Check whether the year is optional 206 final boolean isYearOptional = getType().isYearOptional(); 207 208 final int oldYear, oldMonth, oldDay; 209 210 if (TextUtils.isEmpty(oldValue)) { 211 // Default to the current date 212 oldYear = defaultYear; 213 oldMonth = calendar.get(Calendar.MONTH); 214 oldDay = calendar.get(Calendar.DAY_OF_MONTH); 215 } else { 216 // Try parsing with year 217 Calendar cal = DateUtils.parseDate(oldValue, false); 218 if (cal != null) { 219 if (DateUtils.isYearSet(cal)) { 220 oldYear = cal.get(Calendar.YEAR); 221 } else { 222 //cal.set(Calendar.YEAR, 0); 223 oldYear = isYearOptional ? DatePickerDialog.NO_YEAR : defaultYear; 224 } 225 oldMonth = cal.get(Calendar.MONTH); 226 oldDay = cal.get(Calendar.DAY_OF_MONTH); 227 } else { 228 return null; 229 } 230 } 231 final OnDateSetListener callBack = new OnDateSetListener() { 232 @Override 233 public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { 234 if (year == 0 && !isYearOptional) throw new IllegalStateException(); 235 final Calendar outCalendar = 236 Calendar.getInstance(DateUtils.UTC_TIMEZONE, Locale.US); 237 238 // If no year specified, set it to 2000 (we could pick any leap year here). 239 // The format string will ignore that year. 240 // For formats other than Exchange, the time of the day is ignored 241 outCalendar.clear(); 242 outCalendar.set(year == DatePickerDialog.NO_YEAR ? 2000 : year, monthOfYear, 243 dayOfMonth, CommonDateUtils.DEFAULT_HOUR, 0, 0); 244 245 final String resultString; 246 if (year == 0) { 247 resultString = kind.dateFormatWithoutYear == null 248 ? null : kind.dateFormatWithoutYear.format(outCalendar.getTime()); 249 } else { 250 resultString = kind.dateFormatWithYear == null 251 ? null : kind.dateFormatWithYear.format(outCalendar.getTime()); 252 } 253 if (resultString == null) return; 254 255 onFieldChanged(column, resultString); 256 rebuildDateView(); 257 } 258 }; 259 final DatePickerDialog resultDialog = new DatePickerDialog(getContext(), callBack, 260 oldYear, oldMonth, oldDay, isYearOptional); 261 return resultDialog; 262 } 263 264 @Override clearAllFields()265 public void clearAllFields() { 266 // Update UI 267 mDateView.setText(mNoDateString); 268 mDateView.setTextColor(mHintTextColor); 269 270 // Update state 271 final String column = getKind().fieldList.get(0).column; 272 onFieldChanged(column, ""); 273 } 274 275 /** 276 * Sets the typeColumn of entry as TYPE_BIRTHDAY and calls rebuildValues() to refresh the view. 277 */ restoreBirthday()278 public void restoreBirthday() { 279 saveValue(getKind().typeColumn, Integer.toString(Event.TYPE_BIRTHDAY)); 280 rebuildValues(); 281 } 282 283 /** 284 * EventEditType Birthday: 285 * rawValue=3 labelRes=17039911 secondary=false specificMax=1 customColumn=null 286 * mYearOptional=true 287 */ isBirthdayType()288 public boolean isBirthdayType(){ 289 final EventEditType eventType = getType(); 290 return eventType.rawValue == Event.TYPE_BIRTHDAY && !eventType.secondary 291 && eventType.specificMax == 1 && eventType.customColumn == null 292 && eventType.isYearOptional(); 293 } 294 } 295