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