Home | History | Annotate | Download | only in editor
      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.model.DataKind;
     20 import com.android.contacts.model.EntityDelta;
     21 import com.android.contacts.model.EntityDelta.ValuesDelta;
     22 
     23 import android.content.ContentValues;
     24 import android.content.Context;
     25 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
     26 import android.text.TextUtils;
     27 import android.util.AttributeSet;
     28 
     29 /**
     30  * A dedicated editor for phonetic name. It is similar to {@link StructuredNameEditorView}.
     31  */
     32 public 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         } else {
    206             // All fields are always visible, so we don't have to worry about blocking updates
    207             // from onRestoreInstanceState() from hidden fields. Always call into the superclass
    208             // to update the field and rebuild the underlying phonetic name.
    209             super.onFieldChanged(column, value);
    210         }
    211     }
    212 
    213     public boolean hasData() {
    214         ValuesDelta entry = getEntry();
    215 
    216         String family = entry.getAsString(StructuredName.PHONETIC_FAMILY_NAME);
    217         String middle = entry.getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
    218         String given = entry.getAsString(StructuredName.PHONETIC_GIVEN_NAME);
    219 
    220         return !TextUtils.isEmpty(family) || !TextUtils.isEmpty(middle)
    221                 || !TextUtils.isEmpty(given);
    222     }
    223 }
    224