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