1 /* 2 * Copyright (C) 2011 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 package com.android.contacts.common.util; 17 18 19 import android.content.ContentValues; 20 import android.content.Context; 21 import android.database.Cursor; 22 import android.net.Uri; 23 import android.net.Uri.Builder; 24 import android.provider.ContactsContract; 25 import android.provider.ContactsContract.CommonDataKinds.StructuredName; 26 import android.text.TextUtils; 27 28 import com.android.contacts.common.model.dataitem.StructuredNameDataItem; 29 30 import java.util.Map; 31 import java.util.TreeMap; 32 33 /** 34 * Utility class for converting between a display name and structured name (and vice-versa), via 35 * calls to the contact provider. 36 */ 37 public class NameConverter { 38 39 /** 40 * The array of fields that comprise a structured name. 41 */ 42 public static final String[] STRUCTURED_NAME_FIELDS = new String[] { 43 StructuredName.PREFIX, 44 StructuredName.GIVEN_NAME, 45 StructuredName.MIDDLE_NAME, 46 StructuredName.FAMILY_NAME, 47 StructuredName.SUFFIX 48 }; 49 50 /** 51 * Converts the given structured name (provided as a map from {@link StructuredName} fields to 52 * corresponding values) into a display name string. 53 * <p> 54 * Note that this operates via a call back to the ContactProvider, but it does not access the 55 * database, so it should be safe to call from the UI thread. See 56 * ContactsProvider2.completeName() for the underlying method call. 57 * @param context Activity context. 58 * @param structuredName The structured name map to convert. 59 * @return The display name computed from the structured name map. 60 */ 61 public static String structuredNameToDisplayName(Context context, 62 Map<String, String> structuredName) { 63 Builder builder = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name"); 64 for (String key : STRUCTURED_NAME_FIELDS) { 65 if (structuredName.containsKey(key)) { 66 appendQueryParameter(builder, key, structuredName.get(key)); 67 } 68 } 69 return fetchDisplayName(context, builder.build()); 70 } 71 72 /** 73 * Converts the given structured name (provided as ContentValues) into a display name string. 74 * @param context Activity context. 75 * @param values The content values containing values comprising the structured name. 76 * @return 77 */ 78 public static String structuredNameToDisplayName(Context context, ContentValues values) { 79 Builder builder = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name"); 80 for (String key : STRUCTURED_NAME_FIELDS) { 81 if (values.containsKey(key)) { 82 appendQueryParameter(builder, key, values.getAsString(key)); 83 } 84 } 85 return fetchDisplayName(context, builder.build()); 86 } 87 88 /** 89 * Helper method for fetching the display name via the given URI. 90 */ 91 private static String fetchDisplayName(Context context, Uri uri) { 92 String displayName = null; 93 Cursor cursor = context.getContentResolver().query(uri, new String[]{ 94 StructuredName.DISPLAY_NAME, 95 }, null, null, null); 96 97 if (cursor != null) { 98 try { 99 if (cursor.moveToFirst()) { 100 displayName = cursor.getString(0); 101 } 102 } finally { 103 cursor.close(); 104 } 105 } 106 return displayName; 107 } 108 109 /** 110 * Converts the given display name string into a structured name (as a map from 111 * {@link StructuredName} fields to corresponding values). 112 * <p> 113 * Note that this operates via a call back to the ContactProvider, but it does not access the 114 * database, so it should be safe to call from the UI thread. 115 * @param context Activity context. 116 * @param displayName The display name to convert. 117 * @return The structured name map computed from the display name. 118 */ 119 public static Map<String, String> displayNameToStructuredName(Context context, 120 String displayName) { 121 Map<String, String> structuredName = new TreeMap<String, String>(); 122 Builder builder = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name"); 123 124 appendQueryParameter(builder, StructuredName.DISPLAY_NAME, displayName); 125 Cursor cursor = context.getContentResolver().query(builder.build(), STRUCTURED_NAME_FIELDS, 126 null, null, null); 127 128 if (cursor != null) { 129 try { 130 if (cursor.moveToFirst()) { 131 for (int i = 0; i < STRUCTURED_NAME_FIELDS.length; i++) { 132 structuredName.put(STRUCTURED_NAME_FIELDS[i], cursor.getString(i)); 133 } 134 } 135 } finally { 136 cursor.close(); 137 } 138 } 139 return structuredName; 140 } 141 142 /** 143 * Converts the given display name string into a structured name (inserting the structured 144 * values into a new or existing ContentValues object). 145 * <p> 146 * Note that this operates via a call back to the ContactProvider, but it does not access the 147 * database, so it should be safe to call from the UI thread. 148 * @param context Activity context. 149 * @param displayName The display name to convert. 150 * @param contentValues The content values object to place the structured name values into. If 151 * null, a new one will be created and returned. 152 * @return The ContentValues object containing the structured name fields derived from the 153 * display name. 154 */ 155 public static ContentValues displayNameToStructuredName(Context context, String displayName, 156 ContentValues contentValues) { 157 if (contentValues == null) { 158 contentValues = new ContentValues(); 159 } 160 Map<String, String> mapValues = displayNameToStructuredName(context, displayName); 161 for (String key : mapValues.keySet()) { 162 contentValues.put(key, mapValues.get(key)); 163 } 164 return contentValues; 165 } 166 167 private static void appendQueryParameter(Builder builder, String field, String value) { 168 if (!TextUtils.isEmpty(value)) { 169 builder.appendQueryParameter(field, value); 170 } 171 } 172 173 /** 174 * Parses phonetic name and returns parsed data (family, middle, given) as ContentValues. 175 * Parsed data should be {@link StructuredName#PHONETIC_FAMILY_NAME}, 176 * {@link StructuredName#PHONETIC_MIDDLE_NAME}, and 177 * {@link StructuredName#PHONETIC_GIVEN_NAME}. 178 * If this method cannot parse given phoneticName, null values will be stored. 179 * 180 * @param phoneticName Phonetic name to be parsed 181 * @param values ContentValues to be used for storing data. If null, new instance will be 182 * created. 183 * @return ContentValues with parsed data. Those data can be null. 184 */ 185 public static StructuredNameDataItem parsePhoneticName(String phoneticName, 186 StructuredNameDataItem item) { 187 String family = null; 188 String middle = null; 189 String given = null; 190 191 if (!TextUtils.isEmpty(phoneticName)) { 192 String[] strings = phoneticName.split(" ", 3); 193 switch (strings.length) { 194 case 1: 195 family = strings[0]; 196 break; 197 case 2: 198 family = strings[0]; 199 given = strings[1]; 200 break; 201 case 3: 202 family = strings[0]; 203 middle = strings[1]; 204 given = strings[2]; 205 break; 206 } 207 } 208 209 if (item == null) { 210 item = new StructuredNameDataItem(); 211 } 212 item.setPhoneticFamilyName(family); 213 item.setPhoneticMiddleName(middle); 214 item.setPhoneticGivenName(given); 215 return item; 216 } 217 218 /** 219 * Constructs and returns a phonetic full name from given parts. 220 */ 221 public static String buildPhoneticName(String family, String middle, String given) { 222 if (!TextUtils.isEmpty(family) || !TextUtils.isEmpty(middle) 223 || !TextUtils.isEmpty(given)) { 224 StringBuilder sb = new StringBuilder(); 225 if (!TextUtils.isEmpty(family)) { 226 sb.append(family.trim()).append(' '); 227 } 228 if (!TextUtils.isEmpty(middle)) { 229 sb.append(middle.trim()).append(' '); 230 } 231 if (!TextUtils.isEmpty(given)) { 232 sb.append(given.trim()).append(' '); 233 } 234 sb.setLength(sb.length() - 1); // Yank the last space 235 return sb.toString(); 236 } else { 237 return null; 238 } 239 } 240 } 241