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.EditField;
24import com.android.contacts.model.AccountType.EventEditType;
25import com.android.contacts.model.DataKind;
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.content.res.ColorStateList;
33import android.content.res.Resources;
34import android.os.Bundle;
35import android.text.TextUtils;
36import android.util.AttributeSet;
37import android.view.View;
38import android.widget.Button;
39
40import java.text.ParsePosition;
41import java.util.Calendar;
42import java.util.Date;
43import java.util.Locale;
44
45/**
46 * Editor that allows editing Events using a {@link DatePickerDialog}
47 */
48public 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