• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import android.content.ContentValues;
19 import android.content.Context;
20 import android.database.Cursor;
21 import android.net.Uri;
22 import android.net.Uri.Builder;
23 import android.provider.ContactsContract;
24 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
25 import android.text.TextUtils;
26 import com.android.contacts.common.model.dataitem.StructuredNameDataItem;
27 import java.util.Map;
28 import 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  */
34 public 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    */
structuredNameToDisplayName( Context context, Map<String, String> structuredName)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    */
structuredNameToDisplayName(Context context, ContentValues values)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. */
fetchDisplayName(Context context, Uri 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    */
displayNameToStructuredName( Context context, String displayName)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    */
displayNameToStructuredName( Context context, String displayName, ContentValues contentValues)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 
appendQueryParameter(Builder builder, String field, String value)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    */
parsePhoneticName( String phoneticName, StructuredNameDataItem item)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. */
buildPhoneticName(String family, String middle, String given)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