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