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 try { 98 if (cursor.moveToFirst()) { 99 displayName = cursor.getString(0); 100 } 101 } finally { 102 cursor.close(); 103 } 104 return displayName; 105 } 106 107 /** 108 * Converts the given display name string into a structured name (as a map from 109 * {@link StructuredName} fields to corresponding values). 110 * <p> 111 * Note that this operates via a call back to the ContactProvider, but it does not access the 112 * database, so it should be safe to call from the UI thread. 113 * @param context Activity context. 114 * @param displayName The display name to convert. 115 * @return The structured name map computed from the display name. 116 */ 117 public static Map<String, String> displayNameToStructuredName(Context context, 118 String displayName) { 119 Map<String, String> structuredName = new TreeMap<String, String>(); 120 Builder builder = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name"); 121 122 appendQueryParameter(builder, StructuredName.DISPLAY_NAME, displayName); 123 Cursor cursor = context.getContentResolver().query(builder.build(), STRUCTURED_NAME_FIELDS, 124 null, null, null); 125 126 try { 127 if (cursor.moveToFirst()) { 128 for (int i = 0; i < STRUCTURED_NAME_FIELDS.length; i++) { 129 structuredName.put(STRUCTURED_NAME_FIELDS[i], cursor.getString(i)); 130 } 131 } 132 } finally { 133 cursor.close(); 134 } 135 return structuredName; 136 } 137 138 /** 139 * Converts the given display name string into a structured name (inserting the structured 140 * values into a new or existing ContentValues object). 141 * <p> 142 * Note that this operates via a call back to the ContactProvider, but it does not access the 143 * database, so it should be safe to call from the UI thread. 144 * @param context Activity context. 145 * @param displayName The display name to convert. 146 * @param contentValues The content values object to place the structured name values into. If 147 * null, a new one will be created and returned. 148 * @return The ContentValues object containing the structured name fields derived from the 149 * display name. 150 */ 151 public static ContentValues displayNameToStructuredName(Context context, String displayName, 152 ContentValues contentValues) { 153 if (contentValues == null) { 154 contentValues = new ContentValues(); 155 } 156 Map<String, String> mapValues = displayNameToStructuredName(context, displayName); 157 for (String key : mapValues.keySet()) { 158 contentValues.put(key, mapValues.get(key)); 159 } 160 return contentValues; 161 } 162 163 private static void appendQueryParameter(Builder builder, String field, String value) { 164 if (!TextUtils.isEmpty(value)) { 165 builder.appendQueryParameter(field, value); 166 } 167 } 168 169 /** 170 * Parses phonetic name and returns parsed data (family, middle, given) as ContentValues. 171 * Parsed data should be {@link StructuredName#PHONETIC_FAMILY_NAME}, 172 * {@link StructuredName#PHONETIC_MIDDLE_NAME}, and 173 * {@link StructuredName#PHONETIC_GIVEN_NAME}. 174 * If this method cannot parse given phoneticName, null values will be stored. 175 * 176 * @param phoneticName Phonetic name to be parsed 177 * @param values ContentValues to be used for storing data. If null, new instance will be 178 * created. 179 * @return ContentValues with parsed data. Those data can be null. 180 */ 181 public static StructuredNameDataItem parsePhoneticName(String phoneticName, 182 StructuredNameDataItem item) { 183 String family = null; 184 String middle = null; 185 String given = null; 186 187 if (!TextUtils.isEmpty(phoneticName)) { 188 String[] strings = phoneticName.split(" ", 3); 189 switch (strings.length) { 190 case 1: 191 family = strings[0]; 192 break; 193 case 2: 194 family = strings[0]; 195 given = strings[1]; 196 break; 197 case 3: 198 family = strings[0]; 199 middle = strings[1]; 200 given = strings[2]; 201 break; 202 } 203 } 204 205 if (item == null) { 206 item = new StructuredNameDataItem(); 207 } 208 item.setPhoneticFamilyName(family); 209 item.setPhoneticMiddleName(middle); 210 item.setPhoneticGivenName(given); 211 return item; 212 } 213 214 /** 215 * Constructs and returns a phonetic full name from given parts. 216 */ 217 public static String buildPhoneticName(String family, String middle, String given) { 218 if (!TextUtils.isEmpty(family) || !TextUtils.isEmpty(middle) 219 || !TextUtils.isEmpty(given)) { 220 StringBuilder sb = new StringBuilder(); 221 if (!TextUtils.isEmpty(family)) { 222 sb.append(family.trim()).append(' '); 223 } 224 if (!TextUtils.isEmpty(middle)) { 225 sb.append(middle.trim()).append(' '); 226 } 227 if (!TextUtils.isEmpty(given)) { 228 sb.append(given.trim()).append(' '); 229 } 230 sb.setLength(sb.length() - 1); // Yank the last space 231 return sb.toString(); 232 } else { 233 return null; 234 } 235 } 236 } 237