blob: 25da482b78ee8c771f0c87b99246a914681a209c [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 Millar45e0ed32009-06-01 16:44:38 -070020import android.content.ContentResolver;
Evan Millar2c1cc832009-07-13 11:08:06 -070021import android.content.ContentUris;
Jeff Sharkey624ddc32009-10-01 21:32:19 -070022import android.content.ContentValues;
Evan Millar45e0ed32009-06-01 16:44:38 -070023import android.content.Context;
Jeff Sharkey3f0b7b82009-08-12 11:28:53 -070024import android.content.Intent;
Evan Millar45e0ed32009-06-01 16:44:38 -070025import android.database.Cursor;
26import android.graphics.Bitmap;
27import android.graphics.BitmapFactory;
Evan Millarf19104c2009-09-02 17:53:25 -070028import android.graphics.drawable.Drawable;
Neel Parekh2ad90a32009-09-20 19:08:50 -070029import android.net.Uri;
30import android.provider.ContactsContract.Contacts;
31import android.provider.ContactsContract.Data;
32import android.provider.ContactsContract.RawContacts;
Evan Millar66388be2009-05-28 15:41:07 -070033import android.provider.ContactsContract.CommonDataKinds.Email;
34import android.provider.ContactsContract.CommonDataKinds.Im;
35import android.provider.ContactsContract.CommonDataKinds.Organization;
36import android.provider.ContactsContract.CommonDataKinds.Phone;
Evan Millar2c1cc832009-07-13 11:08:06 -070037import android.provider.ContactsContract.CommonDataKinds.Photo;
Jeff Sharkeyc6ad3ab2009-07-21 19:30:15 -070038import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
Evan Millar66388be2009-05-28 15:41:07 -070039import android.provider.Im.ProviderNames;
Evan Millar66388be2009-05-28 15:41:07 -070040import android.text.TextUtils;
Evan Millar11d628c2009-09-02 08:55:01 -070041import android.view.LayoutInflater;
42import android.view.View;
43import android.view.ViewGroup;
44import android.widget.ImageView;
45import android.widget.TextView;
Evan Millar66388be2009-05-28 15:41:07 -070046
Neel Parekh2ad90a32009-09-20 19:08:50 -070047import com.android.contacts.model.ContactsSource;
48import com.android.contacts.util.Constants;
49
50import java.util.ArrayList;
51
Evan Millar66388be2009-05-28 15:41:07 -070052public class ContactsUtils {
Evan Millar45e0ed32009-06-01 16:44:38 -070053
Evan Millar11d628c2009-09-02 08:55:01 -070054 private static final String TAG = "ContactsUtils";
Jeff Sharkey39261272009-06-03 19:15:09 -070055 /**
56 * Build the display title for the {@link Data#CONTENT_URI} entry in the
57 * provided cursor, assuming the given mimeType.
58 */
59 public static final CharSequence getDisplayLabel(Context context,
60 String mimeType, Cursor cursor) {
61 // Try finding the type and label for this mimetype
62 int colType;
63 int colLabel;
64
Jeff Sharkey39261272009-06-03 19:15:09 -070065 if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)
Jeff Sharkey49d17b32009-09-07 02:14:21 -070066 || Constants.MIME_SMS_ADDRESS.equals(mimeType)) {
Jeff Sharkey39261272009-06-03 19:15:09 -070067 // Reset to phone mimetype so we generate a label for SMS case
68 mimeType = Phone.CONTENT_ITEM_TYPE;
69 colType = cursor.getColumnIndex(Phone.TYPE);
70 colLabel = cursor.getColumnIndex(Phone.LABEL);
71 } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
72 colType = cursor.getColumnIndex(Email.TYPE);
73 colLabel = cursor.getColumnIndex(Email.LABEL);
Jeff Sharkeyc6ad3ab2009-07-21 19:30:15 -070074 } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) {
75 colType = cursor.getColumnIndex(StructuredPostal.TYPE);
76 colLabel = cursor.getColumnIndex(StructuredPostal.LABEL);
Jeff Sharkey39261272009-06-03 19:15:09 -070077 } else if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
78 colType = cursor.getColumnIndex(Organization.TYPE);
79 colLabel = cursor.getColumnIndex(Organization.LABEL);
80 } else {
81 return null;
82 }
83
84 final int type = cursor.getInt(colType);
85 final CharSequence label = cursor.getString(colLabel);
86
87 return getDisplayLabel(context, mimeType, type, label);
88 }
89
Evan Millar66388be2009-05-28 15:41:07 -070090 public static final CharSequence getDisplayLabel(Context context, String mimetype, int type,
91 CharSequence label) {
92 CharSequence display = "";
93 final int customType;
94 final int defaultType;
95 final int arrayResId;
96
97 if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
98 defaultType = Phone.TYPE_HOME;
99 customType = Phone.TYPE_CUSTOM;
100 arrayResId = com.android.internal.R.array.phoneTypes;
101 } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
102 defaultType = Email.TYPE_HOME;
103 customType = Email.TYPE_CUSTOM;
104 arrayResId = com.android.internal.R.array.emailAddressTypes;
Jeff Sharkeyc6ad3ab2009-07-21 19:30:15 -0700105 } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimetype)) {
106 defaultType = StructuredPostal.TYPE_HOME;
107 customType = StructuredPostal.TYPE_CUSTOM;
Evan Millar66388be2009-05-28 15:41:07 -0700108 arrayResId = com.android.internal.R.array.postalAddressTypes;
109 } else if (Organization.CONTENT_ITEM_TYPE.equals(mimetype)) {
Dmitri Plotnikov48cf72b2009-07-17 11:00:26 -0700110 defaultType = Organization.TYPE_WORK;
Evan Millar66388be2009-05-28 15:41:07 -0700111 customType = Organization.TYPE_CUSTOM;
112 arrayResId = com.android.internal.R.array.organizationTypes;
113 } else {
114 // Can't return display label for given mimetype.
115 return display;
116 }
Evan Millar45e0ed32009-06-01 16:44:38 -0700117
Evan Millar66388be2009-05-28 15:41:07 -0700118 if (type != customType) {
119 CharSequence[] labels = context.getResources().getTextArray(arrayResId);
120 try {
121 display = labels[type - 1];
122 } catch (ArrayIndexOutOfBoundsException e) {
123 display = labels[defaultType - 1];
124 }
125 } else {
126 if (!TextUtils.isEmpty(label)) {
127 display = label;
128 }
129 }
130 return display;
131 }
Evan Millar45e0ed32009-06-01 16:44:38 -0700132
Evan Millar45e0ed32009-06-01 16:44:38 -0700133 /**
134 * Opens an InputStream for the person's photo and returns the photo as a Bitmap.
135 * If the person's photo isn't present returns null.
136 *
137 * @param aggCursor the Cursor pointing to the data record containing the photo.
138 * @param bitmapColumnIndex the column index where the photo Uri is stored.
139 * @param options the decoding options, can be set to null
140 * @return the photo Bitmap
141 */
Evan Millar0a40ffa2009-06-18 16:49:08 -0700142 public static Bitmap loadContactPhoto(Cursor cursor, int bitmapColumnIndex,
Evan Millar45e0ed32009-06-01 16:44:38 -0700143 BitmapFactory.Options options) {
Evan Millar0a40ffa2009-06-18 16:49:08 -0700144 if (cursor == null) {
Evan Millar45e0ed32009-06-01 16:44:38 -0700145 return null;
146 }
147
Evan Millar7911ff52009-07-21 15:55:18 -0700148 byte[] data = cursor.getBlob(bitmapColumnIndex);
Evan Millar45e0ed32009-06-01 16:44:38 -0700149 return BitmapFactory.decodeByteArray(data, 0, data.length, options);
150 }
151
152 /**
153 * Loads a placeholder photo.
154 *
155 * @param placeholderImageResource the resource to use for the placeholder image
156 * @param context the Context
157 * @param options the decoding options, can be set to null
158 * @return the placeholder Bitmap.
159 */
160 public static Bitmap loadPlaceholderPhoto(int placeholderImageResource, Context context,
161 BitmapFactory.Options options) {
162 if (placeholderImageResource == 0) {
163 return null;
164 }
165 return BitmapFactory.decodeResource(context.getResources(),
166 placeholderImageResource, options);
167 }
168
Evan Millar7911ff52009-07-21 15:55:18 -0700169 public static Bitmap loadContactPhoto(Context context, long photoId,
Evan Millar2c1cc832009-07-13 11:08:06 -0700170 BitmapFactory.Options options) {
171 Cursor photoCursor = null;
172 Bitmap photoBm = null;
173
174 try {
175 photoCursor = context.getContentResolver().query(
176 ContentUris.withAppendedId(Data.CONTENT_URI, photoId),
177 new String[] { Photo.PHOTO },
178 null, null, null);
179
180 if (photoCursor.moveToFirst() && !photoCursor.isNull(0)) {
181 byte[] photoData = photoCursor.getBlob(0);
182 photoBm = BitmapFactory.decodeByteArray(photoData, 0,
183 photoData.length, options);
184 }
185 } finally {
186 if (photoCursor != null) {
187 photoCursor.close();
188 }
189 }
190
191 return photoBm;
192 }
193
Evan Millar66388be2009-05-28 15:41:07 -0700194 /**
195 * This looks up the provider name defined in
196 * {@link android.provider.Im.ProviderNames} from the predefined IM protocol id.
197 * This is used for interacting with the IM application.
198 *
199 * @param protocol the protocol ID
200 * @return the provider name the IM app uses for the given protocol, or null if no
201 * provider is defined for the given protocol
202 * @hide
203 */
204 public static String lookupProviderNameFromId(int protocol) {
205 switch (protocol) {
206 case Im.PROTOCOL_GOOGLE_TALK:
207 return ProviderNames.GTALK;
208 case Im.PROTOCOL_AIM:
209 return ProviderNames.AIM;
210 case Im.PROTOCOL_MSN:
211 return ProviderNames.MSN;
212 case Im.PROTOCOL_YAHOO:
213 return ProviderNames.YAHOO;
214 case Im.PROTOCOL_ICQ:
215 return ProviderNames.ICQ;
216 case Im.PROTOCOL_JABBER:
217 return ProviderNames.JABBER;
218 case Im.PROTOCOL_SKYPE:
219 return ProviderNames.SKYPE;
220 case Im.PROTOCOL_QQ:
221 return ProviderNames.QQ;
222 }
223 return null;
224 }
225
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700226 /**
227 * Build {@link Intent} to launch an action for the given {@link Im} or
228 * {@link Email} row. Returns null when missing protocol or data.
229 */
230 public static Intent buildImIntent(ContentValues values) {
231 final boolean isEmail = Email.CONTENT_ITEM_TYPE.equals(values.getAsString(Data.MIMETYPE));
232 final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK : values.getAsInteger(Im.PROTOCOL);
233
234 String host = values.getAsString(Im.CUSTOM_PROTOCOL);
235 String data = values.getAsString(isEmail ? Email.DATA : Im.DATA);
236 if (protocol != Im.PROTOCOL_CUSTOM) {
237 // Try bringing in a well-known host for specific protocols
238 host = ContactsUtils.lookupProviderNameFromId(protocol);
239 }
240
241 if (!TextUtils.isEmpty(host) && !TextUtils.isEmpty(data)) {
242 final String authority = host.toLowerCase();
243 final Uri imUri = new Uri.Builder().scheme(Constants.SCHEME_IMTO).authority(
244 authority).appendPath(data).build();
245 return new Intent(Intent.ACTION_SENDTO, imUri);
246 } else {
247 return null;
248 }
249 }
250
Jeff Sharkey3f0b7b82009-08-12 11:28:53 -0700251 public static Intent getPhotoPickIntent() {
252 Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
253 intent.setType("image/*");
254 intent.putExtra("crop", "true");
255 intent.putExtra("aspectX", 1);
256 intent.putExtra("aspectY", 1);
257 intent.putExtra("outputX", 96);
258 intent.putExtra("outputY", 96);
259 intent.putExtra("return-data", true);
260 return intent;
261 }
Evan Millar8a79cee2009-08-19 17:20:49 -0700262
263 public static long queryForContactId(ContentResolver cr, long rawContactId) {
264 Cursor contactIdCursor = null;
265 long contactId = -1;
266 try {
267 contactIdCursor = cr.query(RawContacts.CONTENT_URI,
268 new String[] {RawContacts.CONTACT_ID},
269 RawContacts._ID + "=" + rawContactId, null, null);
270 if (contactIdCursor != null && contactIdCursor.moveToFirst()) {
271 contactId = contactIdCursor.getLong(0);
272 }
273 } finally {
274 if (contactIdCursor != null) {
275 contactIdCursor.close();
276 }
277 }
278 return contactId;
279 }
Evan Millar11d628c2009-09-02 08:55:01 -0700280
Evan Millar2cd51002009-09-02 14:33:38 -0700281 public static String querySuperPrimaryPhone(ContentResolver cr, long contactId) {
282 Cursor c = null;
283 String phone = null;
284 try {
285 Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
Jeff Sharkey49d17b32009-09-07 02:14:21 -0700286 Uri dataUri = Uri.withAppendedPath(baseUri, Contacts.Data.CONTENT_DIRECTORY);
Evan Millar2cd51002009-09-02 14:33:38 -0700287
288 c = cr.query(dataUri,
289 new String[] {Phone.NUMBER},
290 Data.MIMETYPE + "=" + Phone.MIMETYPE +
291 " AND " + Data.IS_SUPER_PRIMARY + "=1",
292 null, null);
293 if (c != null && c.moveToFirst()) {
294 // Just return the first one.
295 phone = c.getString(0);
296 }
297 } finally {
298 if (c != null) {
299 c.close();
300 }
301 }
302 return phone;
303 }
304
305 public static long queryForRawContactId(ContentResolver cr, long contactId) {
306 Cursor rawContactIdCursor = null;
307 long rawContactId = -1;
308 try {
309 rawContactIdCursor = cr.query(RawContacts.CONTENT_URI,
310 new String[] {RawContacts._ID},
311 RawContacts.CONTACT_ID + "=" + contactId, null, null);
312 if (rawContactIdCursor != null && rawContactIdCursor.moveToFirst()) {
313 // Just return the first one.
314 rawContactId = rawContactIdCursor.getLong(0);
315 }
316 } finally {
317 if (rawContactIdCursor != null) {
318 rawContactIdCursor.close();
319 }
320 }
321 return rawContactId;
322 }
323
Neel Parekh2ad90a32009-09-20 19:08:50 -0700324 public static ArrayList<Long> queryForAllRawContactIds(ContentResolver cr, long contactId) {
325 Cursor rawContactIdCursor = null;
326 ArrayList<Long> rawContactIds = new ArrayList<Long>();
327 try {
328 rawContactIdCursor = cr.query(RawContacts.CONTENT_URI,
329 new String[] {RawContacts._ID},
330 RawContacts.CONTACT_ID + "=" + contactId, null, null);
331 if (rawContactIdCursor != null) {
332 while (rawContactIdCursor.moveToNext()) {
333 rawContactIds.add(rawContactIdCursor.getLong(0));
334 }
335 }
336 } finally {
337 if (rawContactIdCursor != null) {
338 rawContactIdCursor.close();
339 }
340 }
341 return rawContactIds;
342 }
343
Evan Millar11d628c2009-09-02 08:55:01 -0700344
345 /**
346 * Utility for creating a standard tab indicator view.
347 *
348 * @param parent The parent ViewGroup to attach the new view to.
349 * @param label The label to display in the tab indicator. If null, not label will be displayed.
350 * @param icon The icon to display. If null, no icon will be displayed.
351 * @return The tab indicator View.
352 */
353 public static View createTabIndicatorView(ViewGroup parent, CharSequence label, Drawable icon) {
354 final LayoutInflater inflater = (LayoutInflater)parent.getContext().getSystemService(
355 Context.LAYOUT_INFLATER_SERVICE);
356 final View tabIndicator = inflater.inflate(R.layout.tab_indicator, parent, false);
357 tabIndicator.getBackground().setDither(true);
358
359 final TextView tv = (TextView) tabIndicator.findViewById(R.id.tab_title);
360 tv.setText(label);
361
362 final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.tab_icon);
363 iconView.setImageDrawable(icon);
364
365 return tabIndicator;
366 }
367
368 /**
369 * Utility for creating a standard tab indicator view.
370 *
371 * @param context The label to display in the tab indicator. If null, not label will be displayed.
372 * @param parent The parent ViewGroup to attach the new view to.
373 * @param source The {@link ContactsSource} to build the tab view from.
374 * @return The tab indicator View.
375 */
376 public static View createTabIndicatorView(ViewGroup parent, ContactsSource source) {
377 Drawable icon = null;
378 if (source != null) {
Jeff Sharkeyab066932009-09-21 09:55:30 -0700379 icon = source.getDisplayIcon(parent.getContext());
Evan Millar11d628c2009-09-02 08:55:01 -0700380 }
381 return createTabIndicatorView(parent, null, icon);
382 }
Evan Millar14fecb62009-09-09 09:23:12 -0700383
384 /**
385 * Kick off an intent to initiate a call.
386 */
387 public static void initiateCall(Context context, CharSequence phoneNumber) {
388 Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
389 Uri.fromParts("tel", phoneNumber.toString(), null));
390 context.startActivity(intent);
391 }
392
393 /**
394 * Kick off an intent to initiate an Sms/Mms message.
395 */
396 public static void initiateSms(Context context, CharSequence phoneNumber) {
397 Intent intent = new Intent(Intent.ACTION_SENDTO,
398 Uri.fromParts("sms", phoneNumber.toString(), null));
399 context.startActivity(intent);
400 }
Evan Millar66388be2009-05-28 15:41:07 -0700401}