blob: dea0bad70c8ca4607bbcb4b66ba99333d1049957 [file] [log] [blame]
Evan Millar45e0ed32009-06-01 16:44:38 -07001/*
2 * Copyright (C) 2009 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
Evan Millar66388be2009-05-28 15:41:07 -070017package com.android.contacts;
18
19
Evan Millar11d628c2009-09-02 08:55:01 -070020import com.android.contacts.model.ContactsSource;
Jeff Sharkey802b2052009-08-04 14:21:06 -070021import com.android.contacts.ui.FastTrackWindow;
Jeff Sharkey49d17b32009-09-07 02:14:21 -070022import com.android.contacts.util.Constants;
Jeff Sharkey802b2052009-08-04 14:21:06 -070023
Evan Millar45e0ed32009-06-01 16:44:38 -070024import java.io.ByteArrayInputStream;
Evan Millar2cd51002009-09-02 14:33:38 -070025
26import android.provider.Contacts.People.Phones;
Jeff Sharkey39261272009-06-03 19:15:09 -070027import android.provider.ContactsContract.Data;
Evan Millar8a79cee2009-08-19 17:20:49 -070028import android.provider.ContactsContract.RawContacts;
29
Evan Millar45e0ed32009-06-01 16:44:38 -070030import java.io.InputStream;
31
32import android.net.Uri;
33import android.content.ContentResolver;
Evan Millar2c1cc832009-07-13 11:08:06 -070034import android.content.ContentUris;
Evan Millar7e4accf2009-06-08 10:43:26 -070035import android.content.ContentValues;
Evan Millar45e0ed32009-06-01 16:44:38 -070036import android.content.Context;
Jeff Sharkey3f0b7b82009-08-12 11:28:53 -070037import android.content.Intent;
Evan Millar11d628c2009-09-02 08:55:01 -070038import android.content.pm.PackageManager;
Evan Millar45e0ed32009-06-01 16:44:38 -070039import android.database.Cursor;
40import android.graphics.Bitmap;
41import android.graphics.BitmapFactory;
Evan Millarf19104c2009-09-02 17:53:25 -070042import android.graphics.drawable.Drawable;
Evan Millar66388be2009-05-28 15:41:07 -070043import android.provider.ContactsContract.CommonDataKinds.Email;
44import android.provider.ContactsContract.CommonDataKinds.Im;
45import android.provider.ContactsContract.CommonDataKinds.Organization;
46import android.provider.ContactsContract.CommonDataKinds.Phone;
Evan Millar2c1cc832009-07-13 11:08:06 -070047import android.provider.ContactsContract.CommonDataKinds.Photo;
Jeff Sharkeyc6ad3ab2009-07-21 19:30:15 -070048import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
Evan Millar2cd51002009-09-02 14:33:38 -070049import android.provider.ContactsContract.Contacts;
Evan Millar66388be2009-05-28 15:41:07 -070050import android.provider.Im.ProviderNames;
Jeff Sharkey39261272009-06-03 19:15:09 -070051import android.database.Cursor;
Evan Millar66388be2009-05-28 15:41:07 -070052import android.text.TextUtils;
Jeff Sharkey39261272009-06-03 19:15:09 -070053import android.util.Log;
Evan Millar11d628c2009-09-02 08:55:01 -070054import android.view.LayoutInflater;
55import android.view.View;
56import android.view.ViewGroup;
57import android.widget.ImageView;
58import android.widget.TextView;
Evan Millar66388be2009-05-28 15:41:07 -070059
60public class ContactsUtils {
Evan Millar45e0ed32009-06-01 16:44:38 -070061
Evan Millar11d628c2009-09-02 08:55:01 -070062 private static final String TAG = "ContactsUtils";
Jeff Sharkey39261272009-06-03 19:15:09 -070063 /**
64 * Build the display title for the {@link Data#CONTENT_URI} entry in the
65 * provided cursor, assuming the given mimeType.
66 */
67 public static final CharSequence getDisplayLabel(Context context,
68 String mimeType, Cursor cursor) {
69 // Try finding the type and label for this mimetype
70 int colType;
71 int colLabel;
72
Jeff Sharkey39261272009-06-03 19:15:09 -070073 if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)
Jeff Sharkey49d17b32009-09-07 02:14:21 -070074 || Constants.MIME_SMS_ADDRESS.equals(mimeType)) {
Jeff Sharkey39261272009-06-03 19:15:09 -070075 // Reset to phone mimetype so we generate a label for SMS case
76 mimeType = Phone.CONTENT_ITEM_TYPE;
77 colType = cursor.getColumnIndex(Phone.TYPE);
78 colLabel = cursor.getColumnIndex(Phone.LABEL);
79 } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
80 colType = cursor.getColumnIndex(Email.TYPE);
81 colLabel = cursor.getColumnIndex(Email.LABEL);
Jeff Sharkeyc6ad3ab2009-07-21 19:30:15 -070082 } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) {
83 colType = cursor.getColumnIndex(StructuredPostal.TYPE);
84 colLabel = cursor.getColumnIndex(StructuredPostal.LABEL);
Jeff Sharkey39261272009-06-03 19:15:09 -070085 } else if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
86 colType = cursor.getColumnIndex(Organization.TYPE);
87 colLabel = cursor.getColumnIndex(Organization.LABEL);
88 } else {
89 return null;
90 }
91
92 final int type = cursor.getInt(colType);
93 final CharSequence label = cursor.getString(colLabel);
94
95 return getDisplayLabel(context, mimeType, type, label);
96 }
97
Evan Millar66388be2009-05-28 15:41:07 -070098 public static final CharSequence getDisplayLabel(Context context, String mimetype, int type,
99 CharSequence label) {
100 CharSequence display = "";
101 final int customType;
102 final int defaultType;
103 final int arrayResId;
104
105 if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
106 defaultType = Phone.TYPE_HOME;
107 customType = Phone.TYPE_CUSTOM;
108 arrayResId = com.android.internal.R.array.phoneTypes;
109 } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
110 defaultType = Email.TYPE_HOME;
111 customType = Email.TYPE_CUSTOM;
112 arrayResId = com.android.internal.R.array.emailAddressTypes;
Jeff Sharkeyc6ad3ab2009-07-21 19:30:15 -0700113 } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimetype)) {
114 defaultType = StructuredPostal.TYPE_HOME;
115 customType = StructuredPostal.TYPE_CUSTOM;
Evan Millar66388be2009-05-28 15:41:07 -0700116 arrayResId = com.android.internal.R.array.postalAddressTypes;
117 } else if (Organization.CONTENT_ITEM_TYPE.equals(mimetype)) {
Dmitri Plotnikov48cf72b2009-07-17 11:00:26 -0700118 defaultType = Organization.TYPE_WORK;
Evan Millar66388be2009-05-28 15:41:07 -0700119 customType = Organization.TYPE_CUSTOM;
120 arrayResId = com.android.internal.R.array.organizationTypes;
121 } else {
122 // Can't return display label for given mimetype.
123 return display;
124 }
Evan Millar45e0ed32009-06-01 16:44:38 -0700125
Evan Millar66388be2009-05-28 15:41:07 -0700126 if (type != customType) {
127 CharSequence[] labels = context.getResources().getTextArray(arrayResId);
128 try {
129 display = labels[type - 1];
130 } catch (ArrayIndexOutOfBoundsException e) {
131 display = labels[defaultType - 1];
132 }
133 } else {
134 if (!TextUtils.isEmpty(label)) {
135 display = label;
136 }
137 }
138 return display;
139 }
Evan Millar45e0ed32009-06-01 16:44:38 -0700140
Evan Millar45e0ed32009-06-01 16:44:38 -0700141 /**
142 * Opens an InputStream for the person's photo and returns the photo as a Bitmap.
143 * If the person's photo isn't present returns null.
144 *
145 * @param aggCursor the Cursor pointing to the data record containing the photo.
146 * @param bitmapColumnIndex the column index where the photo Uri is stored.
147 * @param options the decoding options, can be set to null
148 * @return the photo Bitmap
149 */
Evan Millar0a40ffa2009-06-18 16:49:08 -0700150 public static Bitmap loadContactPhoto(Cursor cursor, int bitmapColumnIndex,
Evan Millar45e0ed32009-06-01 16:44:38 -0700151 BitmapFactory.Options options) {
Evan Millar0a40ffa2009-06-18 16:49:08 -0700152 if (cursor == null) {
Evan Millar45e0ed32009-06-01 16:44:38 -0700153 return null;
154 }
155
Evan Millar7911ff52009-07-21 15:55:18 -0700156 byte[] data = cursor.getBlob(bitmapColumnIndex);
Evan Millar45e0ed32009-06-01 16:44:38 -0700157 return BitmapFactory.decodeByteArray(data, 0, data.length, options);
158 }
159
160 /**
161 * Loads a placeholder photo.
162 *
163 * @param placeholderImageResource the resource to use for the placeholder image
164 * @param context the Context
165 * @param options the decoding options, can be set to null
166 * @return the placeholder Bitmap.
167 */
168 public static Bitmap loadPlaceholderPhoto(int placeholderImageResource, Context context,
169 BitmapFactory.Options options) {
170 if (placeholderImageResource == 0) {
171 return null;
172 }
173 return BitmapFactory.decodeResource(context.getResources(),
174 placeholderImageResource, options);
175 }
176
Evan Millar7911ff52009-07-21 15:55:18 -0700177 public static Bitmap loadContactPhoto(Context context, long photoId,
Evan Millar2c1cc832009-07-13 11:08:06 -0700178 BitmapFactory.Options options) {
179 Cursor photoCursor = null;
180 Bitmap photoBm = null;
181
182 try {
183 photoCursor = context.getContentResolver().query(
184 ContentUris.withAppendedId(Data.CONTENT_URI, photoId),
185 new String[] { Photo.PHOTO },
186 null, null, null);
187
188 if (photoCursor.moveToFirst() && !photoCursor.isNull(0)) {
189 byte[] photoData = photoCursor.getBlob(0);
190 photoBm = BitmapFactory.decodeByteArray(photoData, 0,
191 photoData.length, options);
192 }
193 } finally {
194 if (photoCursor != null) {
195 photoCursor.close();
196 }
197 }
198
199 return photoBm;
200 }
201
Evan Millar66388be2009-05-28 15:41:07 -0700202 /**
203 * This looks up the provider name defined in
204 * {@link android.provider.Im.ProviderNames} from the predefined IM protocol id.
205 * This is used for interacting with the IM application.
206 *
207 * @param protocol the protocol ID
208 * @return the provider name the IM app uses for the given protocol, or null if no
209 * provider is defined for the given protocol
210 * @hide
211 */
212 public static String lookupProviderNameFromId(int protocol) {
213 switch (protocol) {
214 case Im.PROTOCOL_GOOGLE_TALK:
215 return ProviderNames.GTALK;
216 case Im.PROTOCOL_AIM:
217 return ProviderNames.AIM;
218 case Im.PROTOCOL_MSN:
219 return ProviderNames.MSN;
220 case Im.PROTOCOL_YAHOO:
221 return ProviderNames.YAHOO;
222 case Im.PROTOCOL_ICQ:
223 return ProviderNames.ICQ;
224 case Im.PROTOCOL_JABBER:
225 return ProviderNames.JABBER;
226 case Im.PROTOCOL_SKYPE:
227 return ProviderNames.SKYPE;
228 case Im.PROTOCOL_QQ:
229 return ProviderNames.QQ;
230 }
231 return null;
232 }
233
Jeff Sharkey3f0b7b82009-08-12 11:28:53 -0700234 public static Intent getPhotoPickIntent() {
235 Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
236 intent.setType("image/*");
237 intent.putExtra("crop", "true");
238 intent.putExtra("aspectX", 1);
239 intent.putExtra("aspectY", 1);
240 intent.putExtra("outputX", 96);
241 intent.putExtra("outputY", 96);
242 intent.putExtra("return-data", true);
243 return intent;
244 }
Evan Millar8a79cee2009-08-19 17:20:49 -0700245
246 public static long queryForContactId(ContentResolver cr, long rawContactId) {
247 Cursor contactIdCursor = null;
248 long contactId = -1;
249 try {
250 contactIdCursor = cr.query(RawContacts.CONTENT_URI,
251 new String[] {RawContacts.CONTACT_ID},
252 RawContacts._ID + "=" + rawContactId, null, null);
253 if (contactIdCursor != null && contactIdCursor.moveToFirst()) {
254 contactId = contactIdCursor.getLong(0);
255 }
256 } finally {
257 if (contactIdCursor != null) {
258 contactIdCursor.close();
259 }
260 }
261 return contactId;
262 }
Evan Millar11d628c2009-09-02 08:55:01 -0700263
Evan Millar2cd51002009-09-02 14:33:38 -0700264 public static String querySuperPrimaryPhone(ContentResolver cr, long contactId) {
265 Cursor c = null;
266 String phone = null;
267 try {
268 Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
Jeff Sharkey49d17b32009-09-07 02:14:21 -0700269 Uri dataUri = Uri.withAppendedPath(baseUri, Contacts.Data.CONTENT_DIRECTORY);
Evan Millar2cd51002009-09-02 14:33:38 -0700270
271 c = cr.query(dataUri,
272 new String[] {Phone.NUMBER},
273 Data.MIMETYPE + "=" + Phone.MIMETYPE +
274 " AND " + Data.IS_SUPER_PRIMARY + "=1",
275 null, null);
276 if (c != null && c.moveToFirst()) {
277 // Just return the first one.
278 phone = c.getString(0);
279 }
280 } finally {
281 if (c != null) {
282 c.close();
283 }
284 }
285 return phone;
286 }
287
288 public static long queryForRawContactId(ContentResolver cr, long contactId) {
289 Cursor rawContactIdCursor = null;
290 long rawContactId = -1;
291 try {
292 rawContactIdCursor = cr.query(RawContacts.CONTENT_URI,
293 new String[] {RawContacts._ID},
294 RawContacts.CONTACT_ID + "=" + contactId, null, null);
295 if (rawContactIdCursor != null && rawContactIdCursor.moveToFirst()) {
296 // Just return the first one.
297 rawContactId = rawContactIdCursor.getLong(0);
298 }
299 } finally {
300 if (rawContactIdCursor != null) {
301 rawContactIdCursor.close();
302 }
303 }
304 return rawContactId;
305 }
306
Evan Millar11d628c2009-09-02 08:55:01 -0700307
308 /**
309 * Utility for creating a standard tab indicator view.
310 *
311 * @param parent The parent ViewGroup to attach the new view to.
312 * @param label The label to display in the tab indicator. If null, not label will be displayed.
313 * @param icon The icon to display. If null, no icon will be displayed.
314 * @return The tab indicator View.
315 */
316 public static View createTabIndicatorView(ViewGroup parent, CharSequence label, Drawable icon) {
317 final LayoutInflater inflater = (LayoutInflater)parent.getContext().getSystemService(
318 Context.LAYOUT_INFLATER_SERVICE);
319 final View tabIndicator = inflater.inflate(R.layout.tab_indicator, parent, false);
320 tabIndicator.getBackground().setDither(true);
321
322 final TextView tv = (TextView) tabIndicator.findViewById(R.id.tab_title);
323 tv.setText(label);
324
325 final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.tab_icon);
326 iconView.setImageDrawable(icon);
327
328 return tabIndicator;
329 }
330
331 /**
332 * Utility for creating a standard tab indicator view.
333 *
334 * @param context The label to display in the tab indicator. If null, not label will be displayed.
335 * @param parent The parent ViewGroup to attach the new view to.
336 * @param source The {@link ContactsSource} to build the tab view from.
337 * @return The tab indicator View.
338 */
339 public static View createTabIndicatorView(ViewGroup parent, ContactsSource source) {
340 Drawable icon = null;
341 if (source != null) {
342 final String packageName = source.resPackageName;
343 if (source.iconRes > 0) {
344 try {
345 final Context authContext = parent.getContext().
346 createPackageContext(packageName, 0);
347 icon = authContext.getResources().getDrawable(source.iconRes);
348
349 } catch (PackageManager.NameNotFoundException e) {
350 Log.d(TAG, "error getting the Package Context for " + packageName, e);
351 }
352 }
353 }
354 return createTabIndicatorView(parent, null, icon);
355 }
Evan Millar14fecb62009-09-09 09:23:12 -0700356
357 /**
358 * Kick off an intent to initiate a call.
359 */
360 public static void initiateCall(Context context, CharSequence phoneNumber) {
361 Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
362 Uri.fromParts("tel", phoneNumber.toString(), null));
363 context.startActivity(intent);
364 }
365
366 /**
367 * Kick off an intent to initiate an Sms/Mms message.
368 */
369 public static void initiateSms(Context context, CharSequence phoneNumber) {
370 Intent intent = new Intent(Intent.ACTION_SENDTO,
371 Uri.fromParts("sms", phoneNumber.toString(), null));
372 context.startActivity(intent);
373 }
Evan Millar66388be2009-05-28 15:41:07 -0700374}