EventFieldEditorView.java revision 17e6f9d6c0dab8bb02f4f7e2f9f43f8b8449f55a
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 17package com.android.contacts.editor; 18 19import com.android.contacts.R; 20import com.android.contacts.datepicker.DatePicker; 21import com.android.contacts.datepicker.DatePickerDialog; 22import com.android.contacts.datepicker.DatePickerDialog.OnDateSetListener; 23import com.android.contacts.model.AccountType.DataKind; 24import com.android.contacts.model.AccountType.EditField; 25import com.android.contacts.model.AccountType.EventEditType; 26import com.android.contacts.model.EntityDelta; 27import com.android.contacts.model.EntityDelta.ValuesDelta; 28import com.android.contacts.util.DateUtils; 29 30import android.app.Dialog; 31import android.content.Context; 32import android.os.Bundle; 33import android.text.TextUtils; 34import android.util.AttributeSet; 35import android.view.View; 36import android.widget.LinearLayout; 37import android.widget.TextView; 38 39import java.text.ParsePosition; 40import java.util.Calendar; 41import java.util.Date; 42 43/** 44 * Editor that allows editing Events using a {@link DatePickerDialog} 45 */ 46public class EventFieldEditorView extends LabeledEditorView { 47 /** 48 * Exchange requires 8:00 for birthdays 49 */ 50 private final int DEFAULT_HOUR = 8; 51 52 private TextView mDateView; 53 54 public EventFieldEditorView(Context context) { 55 super(context); 56 } 57 58 public EventFieldEditorView(Context context, AttributeSet attrs) { 59 super(context, attrs); 60 } 61 62 public EventFieldEditorView(Context context, AttributeSet attrs, int defStyle) { 63 super(context, attrs, defStyle); 64 } 65 66 @Override 67 public int getBaseline(int row) { 68 int baseline = super.getBaseline(row); 69 if (mDateView != null) { 70 // The date view will be centered vertically in the corresponding line item 71 int lineItemHeight = getLineItemHeight(row); 72 int offset = (lineItemHeight - mDateView.getMeasuredHeight()) / 2; 73 baseline = Math.max(baseline, offset + mDateView.getBaseline()); 74 } 75 return baseline; 76 } 77 78 @Override 79 protected void onLayout(boolean changed, int l, int t, int r, int b) { 80 super.onLayout(changed, l, t, r, b); 81 82 int l1 = getPaddingLeft(); 83 int t1 = getPaddingTop(); 84 int r1 = getMeasuredWidth() - getPaddingRight(); 85 86 // Fields 87 // Subtract buttons left and right if necessary 88 final int labelWidth = (getLabel() != null) ? getLabel().getMeasuredWidth() : 0; 89 final int deleteWidth = (getDelete() != null) ? getDelete().getMeasuredWidth() : 0; 90 final int r2 = r1 - deleteWidth - labelWidth; 91 if (mDateView != null) { 92 int height = mDateView.getMeasuredHeight(); 93 int baseline = getBaseline(0); 94 int top = t1 + baseline - mDateView.getBaseline(); 95 mDateView.layout( 96 l1, top, 97 r2, top + height); 98 } 99 } 100 101 @Override 102 protected int getLineItemHeight(int row) { 103 int height = mDateView == null ? 0 : mDateView.getMeasuredHeight(); 104 return Math.max(height, super.getLineItemHeight(row)); 105 } 106 107 @Override 108 protected void requestFocusForFirstEditField() { 109 if (mDateView != null) mDateView.requestFocus(); 110 } 111 112 @Override 113 public void setEnabled(boolean enabled) { 114 super.setEnabled(enabled); 115 116 if (mDateView != null) mDateView.setEnabled(!isReadOnly() && enabled); 117 } 118 119 @Override 120 public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly, 121 ViewIdGenerator vig) { 122 if (kind.fieldList.size() != 1) throw new IllegalStateException("kind must have 1 field"); 123 super.setValues(kind, entry, state, readOnly, vig); 124 125 if (mDateView == null) { 126 127 // TODO: Change to android.R.attr.spinnerTextStyle when available 128 mDateView = new TextView(getContext(), null, android.R.attr.editTextStyle); 129 mDateView.setFocusable(true); 130 mDateView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 131 LayoutParams.WRAP_CONTENT)); 132 mDateView.setEnabled(isEnabled() && !readOnly); 133 mDateView.setOnClickListener(new OnClickListener() { 134 @Override 135 public void onClick(View v) { 136 showDialog(R.id.dialog_event_date_picker); 137 } 138 }); 139 addView(mDateView); 140 } 141 142 rebuildDateView(); 143 } 144 145 private void rebuildDateView() { 146 final EditField editField = getKind().fieldList.get(0); 147 final String column = editField.column; 148 final String data = DateUtils.formatDate(getContext(), getEntry().getAsString(column)); 149 mDateView.setText(data); 150 } 151 152 @Override 153 public Dialog createDialog(Bundle bundle) { 154 if (bundle == null) throw new IllegalArgumentException("bundle must not be null"); 155 int dialogId = bundle.getInt(DIALOG_ID_KEY); 156 switch (dialogId) { 157 case R.id.dialog_event_date_picker: 158 return createDatePickerDialog(); 159 default: 160 return super.createDialog(bundle); 161 } 162 } 163 164 @Override 165 protected EventEditType getType() { 166 return (EventEditType) super.getType(); 167 } 168 169 @Override 170 protected void onLabelRebuilt() { 171 // if we changed to a type that requires a year, ensure that it is actually set 172 final String column = getKind().fieldList.get(0).column; 173 final String oldValue = getEntry().getAsString(column); 174 final DataKind kind = getKind(); 175 176 final Calendar calendar = Calendar.getInstance(); 177 final int defaultYear = calendar.get(Calendar.YEAR); 178 179 // Check whether the year is optional 180 final boolean isYearOptional = getType().isYearOptional(); 181 182 if (!isYearOptional && !TextUtils.isEmpty(oldValue)) { 183 final ParsePosition position = new ParsePosition(0); 184 final Date date2 = kind.dateFormatWithoutYear.parse(oldValue, position); 185 186 // Don't understand the date, lets not change it 187 if (date2 == null) return; 188 189 // This value is missing the year. Add it now 190 calendar.setTime(date2); 191 calendar.set(defaultYear, calendar.get(Calendar.MONTH), 192 calendar.get(Calendar.DAY_OF_MONTH), DEFAULT_HOUR, 0, 0); 193 194 onFieldChanged(column, kind.dateFormatWithYear.format(calendar.getTime())); 195 rebuildDateView(); 196 } 197 } 198 199 /** 200 * Prepare dialog for entering a date 201 */ 202 private Dialog createDatePickerDialog() { 203 final String column = getKind().fieldList.get(0).column; 204 final String oldValue = getEntry().getAsString(column); 205 final DataKind kind = getKind(); 206 207 final Calendar calendar = Calendar.getInstance(); 208 final int defaultYear = calendar.get(Calendar.YEAR); 209 210 // Check whether the year is optional 211 final boolean isYearOptional = getType().isYearOptional(); 212 213 final int oldYear, oldMonth, oldDay; 214 if (TextUtils.isEmpty(oldValue)) { 215 // Default to January first, 30 years ago 216 oldYear = defaultYear; 217 oldMonth = 0; 218 oldDay = 1; 219 } else { 220 final ParsePosition position = new ParsePosition(0); 221 // Try parsing with year 222 final Date date1 = kind.dateFormatWithYear.parse(oldValue, position); 223 if (date1 != null) { 224 calendar.setTime(date1); 225 oldYear = calendar.get(Calendar.YEAR); 226 oldMonth = calendar.get(Calendar.MONTH); 227 oldDay = calendar.get(Calendar.DAY_OF_MONTH); 228 } else { 229 final Date date2 = kind.dateFormatWithoutYear.parse(oldValue, position); 230 // Don't understand the date, lets not change it 231 if (date2 == null) return null; 232 calendar.setTime(date2); 233 oldYear = isYearOptional ? 0 : defaultYear; 234 oldMonth = calendar.get(Calendar.MONTH); 235 oldDay = calendar.get(Calendar.DAY_OF_MONTH); 236 } 237 } 238 final OnDateSetListener callBack = new OnDateSetListener() { 239 @Override 240 public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { 241 if (year == 0 && !isYearOptional) throw new IllegalStateException(); 242 final Calendar outCalendar = Calendar.getInstance(); 243 244 // If no year specified, set it to 1900. The format string will ignore that year 245 // For formats other than Exchange, the time of the day is ignored 246 outCalendar.clear(); 247 outCalendar.set(year == 0 ? 1900 : year, monthOfYear, dayOfMonth, 248 DEFAULT_HOUR, 0, 0); 249 250 final String resultString; 251 if (year == 0) { 252 resultString = kind.dateFormatWithoutYear.format(outCalendar.getTime()); 253 } else { 254 resultString = kind.dateFormatWithYear.format(outCalendar.getTime()); 255 } 256 onFieldChanged(column, resultString); 257 rebuildDateView(); 258 } 259 }; 260 final DatePickerDialog resultDialog = new DatePickerDialog(getContext(), callBack, 261 oldYear, oldMonth, oldDay, isYearOptional); 262 return resultDialog; 263 } 264} 265