PhoneticNameEditorView.java revision 1a7f42494dbde3c268bc0763ebd62d55d43027ae
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.model.DataKind;
20import com.android.contacts.model.EntityDelta;
21import com.android.contacts.model.EntityDelta.ValuesDelta;
22
23import android.content.ContentValues;
24import android.content.Context;
25import android.provider.ContactsContract.CommonDataKinds.StructuredName;
26import android.text.TextUtils;
27import android.util.AttributeSet;
28
29/**
30 * A dedicated editor for phonetic name. It is similar to {@link StructuredNameEditorView}.
31 */
32public class PhoneticNameEditorView extends TextFieldsEditorView {
33
34    private static class PhoneticValuesDelta extends ValuesDelta {
35        private ValuesDelta mValues;
36        private String mPhoneticName;
37
38        public PhoneticValuesDelta(ValuesDelta values) {
39            mValues = values;
40            buildPhoneticName();
41        }
42
43        @Override
44        public void put(String key, String value) {
45            if (key.equals(DataKind.PSEUDO_COLUMN_PHONETIC_NAME)) {
46                mPhoneticName = value;
47                parsePhoneticName(value);
48            } else {
49                mValues.put(key, value);
50                buildPhoneticName();
51            }
52        }
53
54        @Override
55        public String getAsString(String key) {
56            if (key.equals(DataKind.PSEUDO_COLUMN_PHONETIC_NAME)) {
57                return mPhoneticName;
58            } else {
59                return mValues.getAsString(key);
60            }
61        }
62
63        private void parsePhoneticName(String value) {
64            ContentValues values = PhoneticNameEditorView.parsePhoneticName(value, null);
65            mValues.put(StructuredName.PHONETIC_FAMILY_NAME,
66                    values.getAsString(StructuredName.PHONETIC_FAMILY_NAME));
67            mValues.put(StructuredName.PHONETIC_MIDDLE_NAME,
68                    values.getAsString(StructuredName.PHONETIC_MIDDLE_NAME));
69            mValues.put(StructuredName.PHONETIC_GIVEN_NAME,
70                    values.getAsString(StructuredName.PHONETIC_GIVEN_NAME));
71        }
72
73        private void buildPhoneticName() {
74            String family = mValues.getAsString(StructuredName.PHONETIC_FAMILY_NAME);
75            String middle = mValues.getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
76            String given = mValues.getAsString(StructuredName.PHONETIC_GIVEN_NAME);
77            mPhoneticName = PhoneticNameEditorView.buildPhoneticName(family, middle, given);
78        }
79
80        @Override
81        public Long getId() {
82            return mValues.getId();
83        }
84
85        @Override
86        public boolean isVisible() {
87            return mValues.isVisible();
88        }
89    }
90
91    /**
92     * Parses phonetic name and returns parsed data (family, middle, given) as ContentValues.
93     * Parsed data should be {@link StructuredName#PHONETIC_FAMILY_NAME},
94     * {@link StructuredName#PHONETIC_MIDDLE_NAME}, and
95     * {@link StructuredName#PHONETIC_GIVEN_NAME}.
96     * If this method cannot parse given phoneticName, null values will be stored.
97     *
98     * @param phoneticName Phonetic name to be parsed
99     * @param values ContentValues to be used for storing data. If null, new instance will be
100     * created.
101     * @return ContentValues with parsed data. Those data can be null.
102     */
103    public static ContentValues parsePhoneticName(String phoneticName, ContentValues values) {
104        String family = null;
105        String middle = null;
106        String given = null;
107
108        if (!TextUtils.isEmpty(phoneticName)) {
109            String[] strings = phoneticName.split(" ", 3);
110            switch (strings.length) {
111                case 1:
112                    family = strings[0];
113                    break;
114                case 2:
115                    family = strings[0];
116                    given = strings[1];
117                    break;
118                case 3:
119                    family = strings[0];
120                    middle = strings[1];
121                    given = strings[2];
122                    break;
123            }
124        }
125
126        if (values == null) {
127            values = new ContentValues();
128        }
129        values.put(StructuredName.PHONETIC_FAMILY_NAME, family);
130        values.put(StructuredName.PHONETIC_MIDDLE_NAME, middle);
131        values.put(StructuredName.PHONETIC_GIVEN_NAME, given);
132        return values;
133    }
134
135    /**
136     * Constructs and returns a phonetic full name from given parts.
137     */
138    public static String buildPhoneticName(String family, String middle, String given) {
139        if (!TextUtils.isEmpty(family) || !TextUtils.isEmpty(middle)
140                || !TextUtils.isEmpty(given)) {
141            StringBuilder sb = new StringBuilder();
142            if (!TextUtils.isEmpty(family)) {
143                sb.append(family.trim()).append(' ');
144            }
145            if (!TextUtils.isEmpty(middle)) {
146                sb.append(middle.trim()).append(' ');
147            }
148            if (!TextUtils.isEmpty(given)) {
149                sb.append(given.trim()).append(' ');
150            }
151            sb.setLength(sb.length() - 1);  // Yank the last space
152            return sb.toString();
153        } else {
154            return null;
155        }
156    }
157
158    public static boolean isUnstructuredPhoneticNameColumn(String column) {
159        return DataKind.PSEUDO_COLUMN_PHONETIC_NAME.equals(column);
160    }
161
162    public PhoneticNameEditorView(Context context) {
163        super(context);
164    }
165
166    public PhoneticNameEditorView(Context context, AttributeSet attrs) {
167        super(context, attrs);
168    }
169
170    public PhoneticNameEditorView(Context context, AttributeSet attrs, int defStyle) {
171        super(context, attrs, defStyle);
172    }
173
174    @Override
175    public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly,
176            ViewIdGenerator vig) {
177        if (!(entry instanceof PhoneticValuesDelta)) {
178            entry = new PhoneticValuesDelta(entry);
179        }
180        super.setValues(kind, entry, state, readOnly, vig);
181    }
182
183    @Override
184    public void onFieldChanged(String column, String value) {
185        if (!isFieldChanged(column, value)) {
186            return;
187        }
188
189        if (hasShortAndLongForms()) {
190            PhoneticValuesDelta entry = (PhoneticValuesDelta) getEntry();
191
192            // Determine whether the user is modifying the structured or unstructured phonetic
193            // name field. See a similar approach in {@link StructuredNameEditor#onFieldChanged}.
194            // This is because on device rotation, a hidden TextView's onRestoreInstanceState() will
195            // be called and incorrectly restore a null value for the hidden field, which ultimately
196            // modifies the underlying phonetic name. Hence, ignore onFieldChanged() update requests
197            // from fields that aren't visible.
198            boolean isEditingUnstructuredPhoneticName = !areOptionalFieldsVisible();
199
200            if (isEditingUnstructuredPhoneticName == isUnstructuredPhoneticNameColumn(column)) {
201                // Call into the superclass to update the field and rebuild the underlying
202                // phonetic name.
203                super.onFieldChanged(column, value);
204            }
205        }
206    }
207
208    public boolean hasData() {
209        ValuesDelta entry = getEntry();
210
211        String family = entry.getAsString(StructuredName.PHONETIC_FAMILY_NAME);
212        String middle = entry.getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
213        String given = entry.getAsString(StructuredName.PHONETIC_GIVEN_NAME);
214
215        return !TextUtils.isEmpty(family) || !TextUtils.isEmpty(middle)
216                || !TextUtils.isEmpty(given);
217    }
218}
219