Contacts.java revision dc2da5fd922fc8de0ffcb22df3622b57ed777732
1/*
2 * Copyright (C) 2006 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
17package android.provider;
18
19import com.android.internal.R;
20
21import android.content.ContentResolver;
22import android.content.ContentUris;
23import android.content.ContentValues;
24import android.content.Context;
25import android.content.Intent;
26import android.database.Cursor;
27import android.graphics.Bitmap;
28import android.graphics.BitmapFactory;
29import android.net.Uri;
30import android.text.TextUtils;
31import android.util.Log;
32import android.widget.ImageView;
33import android.accounts.Account;
34
35import java.io.ByteArrayInputStream;
36import java.io.InputStream;
37
38/**
39 * The Contacts provider stores all information about contacts.
40 */
41public class Contacts {
42    private static final String TAG = "Contacts";
43
44    public static final String AUTHORITY = "contacts";
45
46    /**
47     * The content:// style URL for this provider
48     */
49    public static final Uri CONTENT_URI =
50        Uri.parse("content://" + AUTHORITY);
51
52    /** Signifies an email address row that is stored in the ContactMethods table */
53    public static final int KIND_EMAIL = 1;
54    /** Signifies a postal address row that is stored in the ContactMethods table */
55    public static final int KIND_POSTAL = 2;
56    /** Signifies an IM address row that is stored in the ContactMethods table */
57    public static final int KIND_IM = 3;
58    /** Signifies an Organization row that is stored in the Organizations table */
59    public static final int KIND_ORGANIZATION = 4;
60    /** Signifies an Phone row that is stored in the Phones table */
61    public static final int KIND_PHONE = 5;
62
63    /**
64     * no public constructor since this is a utility class
65     */
66    private Contacts() {}
67
68    /**
69     * Columns from the Settings table that other columns join into themselves.
70     */
71    public interface SettingsColumns {
72        /**
73         * The _SYNC_ACCOUNT to which this setting corresponds. This may be null.
74         * <P>Type: TEXT</P>
75         */
76        public static final String _SYNC_ACCOUNT = "_sync_account";
77
78        /**
79         * The _SYNC_ACCOUNT_TYPE to which this setting corresponds. This may be null.
80         * <P>Type: TEXT</P>
81         */
82        public static final String _SYNC_ACCOUNT_TYPE = "_sync_account_type";
83
84        /**
85         * The key of this setting.
86         * <P>Type: TEXT</P>
87         */
88        public static final String KEY = "key";
89
90        /**
91         * The value of this setting.
92         * <P>Type: TEXT</P>
93         */
94        public static final String VALUE = "value";
95    }
96
97    /**
98     * The settings over all of the people
99     */
100    public static final class Settings implements BaseColumns, SettingsColumns {
101        /**
102         * no public constructor since this is a utility class
103         */
104        private Settings() {}
105
106        /**
107         * The content:// style URL for this table
108         */
109        public static final Uri CONTENT_URI =
110            Uri.parse("content://contacts/settings");
111
112        /**
113         * The directory twig for this sub-table
114         */
115        public static final String CONTENT_DIRECTORY = "settings";
116
117        /**
118         * The default sort order for this table
119         */
120        public static final String DEFAULT_SORT_ORDER = "key ASC";
121
122        /**
123         * A setting that is used to indicate if we should sync down all groups for the
124         * specified account. For this setting the _SYNC_ACCOUNT column must be set.
125         * If this isn't set then we will only sync the groups whose SHOULD_SYNC column
126         * is set to true.
127         * <p>
128         * This is a boolean setting. It is true if it is set and it is anything other than the
129         * emptry string or "0".
130         */
131        public static final String SYNC_EVERYTHING = "syncEverything";
132
133        public static String getSetting(ContentResolver cr, String account, String key) {
134            // For now we only support a single account and the UI doesn't know what
135            // the account name is, so we're using a global setting for SYNC_EVERYTHING.
136            // Some day when we add multiple accounts to the UI this should honor the account
137            // that was asked for.
138            String selectString;
139            String[] selectArgs;
140            if (false) {
141                selectString = (account == null)
142                        ? "_sync_account is null AND key=?"
143                        : "_sync_account=? AND key=?";
144//                : "_sync_account=? AND _sync_account_type=? AND key=?";
145                selectArgs = (account == null)
146                ? new String[]{key}
147                : new String[]{account, key};
148            } else {
149                selectString = "key=?";
150                selectArgs = new String[] {key};
151            }
152            Cursor cursor = cr.query(Settings.CONTENT_URI, new String[]{VALUE},
153                    selectString, selectArgs, null);
154            try {
155                if (!cursor.moveToNext()) return null;
156                return cursor.getString(0);
157            } finally {
158                cursor.close();
159            }
160        }
161
162        public static void setSetting(ContentResolver cr, String account, String key,
163                String value) {
164            ContentValues values = new ContentValues();
165            // For now we only support a single account and the UI doesn't know what
166            // the account name is, so we're using a global setting for SYNC_EVERYTHING.
167            // Some day when we add multiple accounts to the UI this should honor the account
168            // that was asked for.
169            //values.put(_SYNC_ACCOUNT, account.mName);
170            //values.put(_SYNC_ACCOUNT_TYPE, account.mType);
171            values.put(KEY, key);
172            values.put(VALUE, value);
173            cr.update(Settings.CONTENT_URI, values, null, null);
174        }
175    }
176
177    /**
178     * Columns from the People table that other tables join into themselves.
179     */
180    public interface PeopleColumns {
181        /**
182         * The person's name.
183         * <P>Type: TEXT</P>
184         */
185        public static final String NAME = "name";
186
187        /**
188         * Phonetic equivalent of the person's name, in a locale-dependent
189         * character set (e.g. hiragana for Japanese).
190         * Used for pronunciation and/or collation in some languages.
191         * <p>Type: TEXT</P>
192         */
193        public static final String PHONETIC_NAME = "phonetic_name";
194
195        /**
196         * The display name. If name is not null name, else if number is not null number,
197         * else if email is not null email.
198         * <P>Type: TEXT</P>
199         */
200        public static final String DISPLAY_NAME = "display_name";
201
202        /**
203         * The field for sorting list phonetically. The content of this field
204         * may not be human readable but phonetically sortable.
205         * <P>Type: TEXT</p>
206         * @hide Used only in Contacts application for now.
207         */
208        public static final String SORT_STRING = "sort_string";
209
210        /**
211         * Notes about the person.
212         * <P>Type: TEXT</P>
213         */
214        public static final String NOTES = "notes";
215
216        /**
217         * The number of times a person has been contacted
218         * <P>Type: INTEGER</P>
219         */
220        public static final String TIMES_CONTACTED = "times_contacted";
221
222        /**
223         * The last time a person was contacted.
224         * <P>Type: INTEGER</P>
225         */
226        public static final String LAST_TIME_CONTACTED = "last_time_contacted";
227
228        /**
229         * A custom ringtone associated with a person. Not always present.
230         * <P>Type: TEXT (URI to the ringtone)</P>
231         */
232        public static final String CUSTOM_RINGTONE = "custom_ringtone";
233
234        /**
235         * Whether the person should always be sent to voicemail. Not always
236         * present.
237         * <P>Type: INTEGER (0 for false, 1 for true)</P>
238         */
239        public static final String SEND_TO_VOICEMAIL = "send_to_voicemail";
240
241        /**
242         * Is the contact starred?
243         * <P>Type: INTEGER (boolean)</P>
244         */
245        public static final String STARRED = "starred";
246
247        /**
248         * The server version of the photo
249         * <P>Type: TEXT (the version number portion of the photo URI)</P>
250         */
251        public static final String PHOTO_VERSION = "photo_version";
252    }
253
254    /**
255     * This table contains people.
256     */
257    public static final class People implements BaseColumns, SyncConstValue, PeopleColumns,
258            PhonesColumns, PresenceColumns {
259        /**
260         * no public constructor since this is a utility class
261         */
262        private People() {}
263
264        /**
265         * The content:// style URL for this table
266         */
267        public static final Uri CONTENT_URI =
268            Uri.parse("content://contacts/people");
269
270        /**
271         * The content:// style URL for filtering people by name. The filter
272         * argument should be passed as an additional path segment after this URI.
273         */
274        public static final Uri CONTENT_FILTER_URI =
275            Uri.parse("content://contacts/people/filter");
276
277        /**
278         * The content:// style URL for the table that holds the deleted
279         * contacts.
280         */
281        public static final Uri DELETED_CONTENT_URI =
282            Uri.parse("content://contacts/deleted_people");
283
284        /**
285         * The content:// style URL for filtering people that have a specific
286         * E-mail or IM address. The filter argument should be passed as an
287         * additional path segment after this URI. This matches any people with
288         * at least one E-mail or IM {@link ContactMethods} that match the
289         * filter.
290         *
291         * Not exposed because we expect significant changes in the contacts
292         * schema and do not want to have to support this.
293         * @hide
294         */
295        public static final Uri WITH_EMAIL_OR_IM_FILTER_URI =
296            Uri.parse("content://contacts/people/with_email_or_im_filter");
297
298        /**
299         * The MIME type of {@link #CONTENT_URI} providing a directory of
300         * people.
301         */
302        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person";
303
304        /**
305         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
306         * person.
307         */
308        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person";
309
310        /**
311         * The default sort order for this table
312         */
313        public static final String DEFAULT_SORT_ORDER = People.NAME + " ASC";
314
315        /**
316         * The ID of the persons preferred phone number.
317         * <P>Type: INTEGER (foreign key to phones table on the _ID field)</P>
318         */
319        public static final String PRIMARY_PHONE_ID = "primary_phone";
320
321        /**
322         * The ID of the persons preferred email.
323         * <P>Type: INTEGER (foreign key to contact_methods table on the
324         * _ID field)</P>
325         */
326        public static final String PRIMARY_EMAIL_ID = "primary_email";
327
328        /**
329         * The ID of the persons preferred organization.
330         * <P>Type: INTEGER (foreign key to organizations table on the
331         * _ID field)</P>
332         */
333        public static final String PRIMARY_ORGANIZATION_ID = "primary_organization";
334
335        /**
336         * Mark a person as having been contacted.
337         *
338         * @param resolver the ContentResolver to use
339         * @param personId the person who was contacted
340         */
341        public static void markAsContacted(ContentResolver resolver, long personId) {
342            Uri uri = ContentUris.withAppendedId(CONTENT_URI, personId);
343            uri = Uri.withAppendedPath(uri, "update_contact_time");
344            ContentValues values = new ContentValues();
345            // There is a trigger in place that will update TIMES_CONTACTED when
346            // LAST_TIME_CONTACTED is modified.
347            values.put(LAST_TIME_CONTACTED, System.currentTimeMillis());
348            resolver.update(uri, values, null, null);
349        }
350
351        /**
352         * @hide Used in vCard parser code.
353         */
354        public static long tryGetMyContactsGroupId(ContentResolver resolver) {
355            Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUPS_PROJECTION,
356                    Groups.SYSTEM_ID + "='" + Groups.GROUP_MY_CONTACTS + "'", null, null);
357            if (groupsCursor != null) {
358                try {
359                    if (groupsCursor.moveToFirst()) {
360                        return groupsCursor.getLong(0);
361                    }
362                } finally {
363                    groupsCursor.close();
364                }
365            }
366            return 0;
367        }
368
369        /**
370         * Adds a person to the My Contacts group.
371         *
372         * @param resolver the resolver to use
373         * @param personId the person to add to the group
374         * @return the URI of the group membership row
375         * @throws IllegalStateException if the My Contacts group can't be found
376         */
377        public static Uri addToMyContactsGroup(ContentResolver resolver, long personId) {
378            long groupId = tryGetMyContactsGroupId(resolver);
379            if (groupId == 0) {
380                throw new IllegalStateException("Failed to find the My Contacts group");
381            }
382
383            return addToGroup(resolver, personId, groupId);
384        }
385
386        /**
387         * Adds a person to a group referred to by name.
388         *
389         * @param resolver the resolver to use
390         * @param personId the person to add to the group
391         * @param groupName the name of the group to add the contact to
392         * @return the URI of the group membership row
393         * @throws IllegalStateException if the group can't be found
394         */
395        public static Uri addToGroup(ContentResolver resolver, long personId, String groupName) {
396            long groupId = 0;
397            Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUPS_PROJECTION,
398                    Groups.NAME + "=?", new String[] { groupName }, null);
399            if (groupsCursor != null) {
400                try {
401                    if (groupsCursor.moveToFirst()) {
402                        groupId = groupsCursor.getLong(0);
403                    }
404                } finally {
405                    groupsCursor.close();
406                }
407            }
408
409            if (groupId == 0) {
410                throw new IllegalStateException("Failed to find the My Contacts group");
411            }
412
413            return addToGroup(resolver, personId, groupId);
414        }
415
416        /**
417         * Adds a person to a group.
418         *
419         * @param resolver the resolver to use
420         * @param personId the person to add to the group
421         * @param groupId the group to add the person to
422         * @return the URI of the group membership row
423         */
424        public static Uri addToGroup(ContentResolver resolver, long personId, long groupId) {
425            ContentValues values = new ContentValues();
426            values.put(GroupMembership.PERSON_ID, personId);
427            values.put(GroupMembership.GROUP_ID, groupId);
428            return resolver.insert(GroupMembership.CONTENT_URI, values);
429        }
430
431        private static final String[] GROUPS_PROJECTION = new String[] {
432            Groups._ID,
433        };
434
435        /**
436         * Creates a new contacts and adds it to the "My Contacts" group.
437         *
438         * @param resolver the ContentResolver to use
439         * @param values the values to use when creating the contact
440         * @return the URI of the contact, or null if the operation fails
441         */
442        public static Uri createPersonInMyContactsGroup(ContentResolver resolver,
443                ContentValues values) {
444
445            Uri contactUri = resolver.insert(People.CONTENT_URI, values);
446            if (contactUri == null) {
447                Log.e(TAG, "Failed to create the contact");
448                return null;
449            }
450
451            if (addToMyContactsGroup(resolver, ContentUris.parseId(contactUri)) == null) {
452                resolver.delete(contactUri, null, null);
453                return null;
454            }
455            return contactUri;
456        }
457
458        public static Cursor queryGroups(ContentResolver resolver, long person) {
459            return resolver.query(GroupMembership.CONTENT_URI, null, "person=?",
460                    new String[]{String.valueOf(person)}, Groups.DEFAULT_SORT_ORDER);
461        }
462
463        /**
464         * Set the photo for this person. data may be null
465         * @param cr the ContentResolver to use
466         * @param person the Uri of the person whose photo is to be updated
467         * @param data the byte[] that represents the photo
468         */
469        public static void setPhotoData(ContentResolver cr, Uri person, byte[] data) {
470            Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY);
471            ContentValues values = new ContentValues();
472            values.put(Photos.DATA, data);
473            cr.update(photoUri, values, null, null);
474        }
475
476        /**
477         * Opens an InputStream for the person's photo and returns the photo as a Bitmap.
478         * If the person's photo isn't present returns the placeholderImageResource instead.
479         * @param person the person whose photo should be used
480         */
481        public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri person) {
482            Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY);
483            Cursor cursor = cr.query(photoUri, new String[]{Photos.DATA}, null, null, null);
484            try {
485                if (!cursor.moveToNext()) {
486                    return null;
487                }
488                byte[] data = cursor.getBlob(0);
489                if (data == null) {
490                    return null;
491                }
492                return new ByteArrayInputStream(data);
493            } finally {
494                cursor.close();
495            }
496        }
497
498        /**
499         * Opens an InputStream for the person's photo and returns the photo as a Bitmap.
500         * If the person's photo isn't present returns the placeholderImageResource instead.
501         * @param context the Context
502         * @param person the person whose photo should be used
503         * @param placeholderImageResource the image resource to use if the person doesn't
504         *   have a photo
505         * @param options the decoding options, can be set to null
506         */
507        public static Bitmap loadContactPhoto(Context context, Uri person,
508                int placeholderImageResource, BitmapFactory.Options options) {
509            if (person == null) {
510                return loadPlaceholderPhoto(placeholderImageResource, context, options);
511            }
512
513            InputStream stream = openContactPhotoInputStream(context.getContentResolver(), person);
514            Bitmap bm = stream != null ? BitmapFactory.decodeStream(stream, null, options) : null;
515            if (bm == null) {
516                bm = loadPlaceholderPhoto(placeholderImageResource, context, options);
517            }
518            return bm;
519        }
520
521        private static Bitmap loadPlaceholderPhoto(int placeholderImageResource, Context context,
522                BitmapFactory.Options options) {
523            if (placeholderImageResource == 0) {
524                return null;
525            }
526            return BitmapFactory.decodeResource(context.getResources(),
527                    placeholderImageResource, options);
528        }
529
530        /**
531         * A sub directory of a single person that contains all of their Phones.
532         */
533        public static final class Phones implements BaseColumns, PhonesColumns,
534                PeopleColumns {
535            /**
536             * no public constructor since this is a utility class
537             */
538            private Phones() {}
539
540            /**
541             * The directory twig for this sub-table
542             */
543            public static final String CONTENT_DIRECTORY = "phones";
544
545            /**
546             * The default sort order for this table
547             */
548            public static final String DEFAULT_SORT_ORDER = "number ASC";
549        }
550
551        /**
552         * A subdirectory of a single person that contains all of their
553         * ContactMethods.
554         */
555        public static final class ContactMethods
556                implements BaseColumns, ContactMethodsColumns, PeopleColumns {
557            /**
558             * no public constructor since this is a utility class
559             */
560            private ContactMethods() {}
561
562            /**
563             * The directory twig for this sub-table
564             */
565            public static final String CONTENT_DIRECTORY = "contact_methods";
566
567            /**
568             * The default sort order for this table
569             */
570            public static final String DEFAULT_SORT_ORDER = "data ASC";
571        }
572
573        /**
574         * The extensions for a person
575         */
576        public static class Extensions implements BaseColumns, ExtensionsColumns {
577            /**
578             * no public constructor since this is a utility class
579             */
580            private Extensions() {}
581
582            /**
583             * The directory twig for this sub-table
584             */
585            public static final String CONTENT_DIRECTORY = "extensions";
586
587            /**
588             * The default sort order for this table
589             */
590            public static final String DEFAULT_SORT_ORDER = "name ASC";
591
592            /**
593             * The ID of the person this phone number is assigned to.
594             * <P>Type: INTEGER (long)</P>
595             */
596            public static final String PERSON_ID = "person";
597        }
598    }
599
600    /**
601     * Columns from the groups table.
602     */
603    public interface GroupsColumns {
604        /**
605         * The group name.
606         * <P>Type: TEXT</P>
607         */
608        public static final String NAME = "name";
609
610        /**
611         * Notes about the group.
612         * <P>Type: TEXT</P>
613         */
614        public static final String NOTES = "notes";
615
616        /**
617         * Whether this group should be synced if the SYNC_EVERYTHING settings is false
618         * for this group's account.
619         * <P>Type: INTEGER (boolean)</P>
620         */
621        public static final String SHOULD_SYNC = "should_sync";
622
623        /**
624         * The ID of this group if it is a System Group, null otherwise.
625         * <P>Type: TEXT</P>
626         */
627        public static final String SYSTEM_ID = "system_id";
628    }
629
630    /**
631     * This table contains the groups for an account.
632     */
633    public static final class Groups
634            implements BaseColumns, SyncConstValue, GroupsColumns {
635        /**
636         * no public constructor since this is a utility class
637         */
638        private Groups() {}
639
640        /**
641         * The content:// style URL for this table
642         */
643        public static final Uri CONTENT_URI =
644            Uri.parse("content://contacts/groups");
645
646        /**
647         * The content:// style URL for the table that holds the deleted
648         * groups.
649         */
650        public static final Uri DELETED_CONTENT_URI =
651            Uri.parse("content://contacts/deleted_groups");
652
653        /**
654         * The MIME type of {@link #CONTENT_URI} providing a directory of
655         * groups.
656         */
657        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroup";
658
659        /**
660         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
661         * group.
662         */
663        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contactsgroup";
664
665        /**
666         * The default sort order for this table
667         */
668        public static final String DEFAULT_SORT_ORDER = NAME + " ASC";
669
670        /**
671         *
672         */
673        public static final String GROUP_ANDROID_STARRED = "Starred in Android";
674
675        /**
676         * The "My Contacts" system group.
677         */
678        public static final String GROUP_MY_CONTACTS = "Contacts";
679    }
680
681    /**
682     * Columns from the Phones table that other columns join into themselves.
683     */
684    public interface PhonesColumns {
685        /**
686         * The type of the the phone number.
687         * <P>Type: INTEGER (one of the constants below)</P>
688         */
689        public static final String TYPE = "type";
690
691        public static final int TYPE_CUSTOM = 0;
692        public static final int TYPE_HOME = 1;
693        public static final int TYPE_MOBILE = 2;
694        public static final int TYPE_WORK = 3;
695        public static final int TYPE_FAX_WORK = 4;
696        public static final int TYPE_FAX_HOME = 5;
697        public static final int TYPE_PAGER = 6;
698        public static final int TYPE_OTHER = 7;
699
700        /**
701         * The user provided label for the phone number, only used if TYPE is TYPE_CUSTOM.
702         * <P>Type: TEXT</P>
703         */
704        public static final String LABEL = "label";
705
706        /**
707         * The phone number as the user entered it.
708         * <P>Type: TEXT</P>
709         */
710        public static final String NUMBER = "number";
711
712        /**
713         * The normalized phone number
714         * <P>Type: TEXT</P>
715         */
716        public static final String NUMBER_KEY = "number_key";
717
718        /**
719         * Whether this is the primary phone number
720         * <P>Type: INTEGER (if set, non-0 means true)</P>
721         */
722        public static final String ISPRIMARY = "isprimary";
723    }
724
725    /**
726     * This table stores phone numbers and a reference to the person that the
727     * contact method belongs to. Phone numbers are stored separately from
728     * other contact methods to make caller ID lookup more efficient.
729     */
730    public static final class Phones
731            implements BaseColumns, PhonesColumns, PeopleColumns {
732        /**
733         * no public constructor since this is a utility class
734         */
735        private Phones() {}
736
737        public static final CharSequence getDisplayLabel(Context context, int type,
738                CharSequence label, CharSequence[] labelArray) {
739            CharSequence display = "";
740
741            if (type != People.Phones.TYPE_CUSTOM) {
742                CharSequence[] labels = labelArray != null? labelArray
743                        : context.getResources().getTextArray(
744                                com.android.internal.R.array.phoneTypes);
745                try {
746                    display = labels[type - 1];
747                } catch (ArrayIndexOutOfBoundsException e) {
748                    display = labels[People.Phones.TYPE_HOME - 1];
749                }
750            } else {
751                if (!TextUtils.isEmpty(label)) {
752                    display = label;
753                }
754            }
755            return display;
756        }
757
758        public static final CharSequence getDisplayLabel(Context context, int type,
759                CharSequence label) {
760            return getDisplayLabel(context, type, label, null);
761        }
762
763        /**
764         * The content:// style URL for this table
765         */
766        public static final Uri CONTENT_URI =
767            Uri.parse("content://contacts/phones");
768
769        /**
770         * The content:// style URL for filtering phone numbers
771         */
772        public static final Uri CONTENT_FILTER_URL =
773            Uri.parse("content://contacts/phones/filter");
774
775        /**
776         * The MIME type of {@link #CONTENT_URI} providing a directory of
777         * phones.
778         */
779        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone";
780
781        /**
782         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
783         * phone.
784         */
785        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone";
786
787        /**
788         * The default sort order for this table
789         */
790        public static final String DEFAULT_SORT_ORDER = "name ASC";
791
792        /**
793         * The ID of the person this phone number is assigned to.
794         * <P>Type: INTEGER (long)</P>
795         */
796        public static final String PERSON_ID = "person";
797    }
798
799    public static final class GroupMembership implements BaseColumns, GroupsColumns {
800        /**
801         * no public constructor since this is a utility class
802         */
803        private GroupMembership() {}
804
805        /**
806         * The content:// style URL for this table
807         */
808        public static final Uri CONTENT_URI =
809            Uri.parse("content://contacts/groupmembership");
810
811        /**
812         * The content:// style URL for this table
813         */
814        public static final Uri RAW_CONTENT_URI =
815            Uri.parse("content://contacts/groupmembershipraw");
816
817        /**
818         * The directory twig for this sub-table
819         */
820        public static final String CONTENT_DIRECTORY = "groupmembership";
821        /**
822         * The MIME type of {@link #CONTENT_URI} providing a directory of all
823         * person groups.
824         */
825        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroupmembership";
826
827        /**
828         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
829         * person group.
830         */
831        public static final String CONTENT_ITEM_TYPE =
832                "vnd.android.cursor.item/contactsgroupmembership";
833
834        /**
835         * The default sort order for this table
836         */
837        public static final String DEFAULT_SORT_ORDER = "group_id ASC";
838
839        /**
840         * The row id of the accounts group.
841         * <P>Type: TEXT</P>
842         */
843        public static final String GROUP_ID = "group_id";
844
845        /**
846         * The sync id of the group.
847         * <P>Type: TEXT</P>
848         */
849        public static final String GROUP_SYNC_ID = "group_sync_id";
850
851        /**
852         * The account of the group.
853         * <P>Type: TEXT</P>
854         */
855        public static final String GROUP_SYNC_ACCOUNT = "group_sync_account";
856
857        /**
858         * The account type of the group.
859         * <P>Type: TEXT</P>
860         */
861        public static final String GROUP_SYNC_ACCOUNT_TYPE = "group_sync_account_type";
862
863        /**
864         * The row id of the person.
865         * <P>Type: TEXT</P>
866         */
867        public static final String PERSON_ID = "person";
868    }
869
870    /**
871     * Columns from the ContactMethods table that other tables join into
872     * themseleves.
873     */
874    public interface ContactMethodsColumns {
875        /**
876         * The kind of the the contact method. For example, email address,
877         * postal address, etc.
878         * <P>Type: INTEGER (one of the values below)</P>
879         */
880        public static final String KIND = "kind";
881
882        /**
883         * The type of the contact method, must be one of the types below.
884         * <P>Type: INTEGER (one of the values below)</P>
885         */
886        public static final String TYPE = "type";
887        public static final int TYPE_CUSTOM = 0;
888        public static final int TYPE_HOME = 1;
889        public static final int TYPE_WORK = 2;
890        public static final int TYPE_OTHER = 3;
891
892        /**
893         * @hide This is temporal. TYPE_MOBILE should be added to TYPE in the future.
894         */
895        public static final int MOBILE_EMAIL_TYPE_INDEX = 2;
896
897        /**
898         * @hide This is temporal. TYPE_MOBILE should be added to TYPE in the future.
899         * This is not "mobile" but "CELL" since vCard uses it for identifying mobile phone.
900         */
901        public static final String MOBILE_EMAIL_TYPE_NAME = "_AUTO_CELL";
902
903        /**
904         * The user defined label for the the contact method.
905         * <P>Type: TEXT</P>
906         */
907        public static final String LABEL = "label";
908
909        /**
910         * The data for the contact method.
911         * <P>Type: TEXT</P>
912         */
913        public static final String DATA = "data";
914
915        /**
916         * Auxiliary data for the contact method.
917         * <P>Type: TEXT</P>
918         */
919        public static final String AUX_DATA = "aux_data";
920
921        /**
922         * Whether this is the primary organization
923         * <P>Type: INTEGER (if set, non-0 means true)</P>
924         */
925        public static final String ISPRIMARY = "isprimary";
926    }
927
928    /**
929     * This table stores all non-phone contact methods and a reference to the
930     * person that the contact method belongs to.
931     */
932    public static final class ContactMethods
933            implements BaseColumns, ContactMethodsColumns, PeopleColumns {
934        /**
935         * The column with latitude data for postal locations
936         * <P>Type: REAL</P>
937         */
938        public static final String POSTAL_LOCATION_LATITUDE = DATA;
939
940        /**
941         * The column with longitude data for postal locations
942         * <P>Type: REAL</P>
943         */
944        public static final String POSTAL_LOCATION_LONGITUDE = AUX_DATA;
945
946        /**
947         * The predefined IM protocol types. The protocol can either be non-present, one
948         * of these types, or a free-form string. These cases are encoded in the AUX_DATA
949         * column as:
950         *  - null
951         *  - pre:<an integer, one of the protocols below>
952         *  - custom:<a string>
953         */
954        public static final int PROTOCOL_AIM = 0;
955        public static final int PROTOCOL_MSN = 1;
956        public static final int PROTOCOL_YAHOO = 2;
957        public static final int PROTOCOL_SKYPE = 3;
958        public static final int PROTOCOL_QQ = 4;
959        public static final int PROTOCOL_GOOGLE_TALK = 5;
960        public static final int PROTOCOL_ICQ = 6;
961        public static final int PROTOCOL_JABBER = 7;
962
963        public static String encodePredefinedImProtocol(int protocol) {
964            return "pre:" + protocol;
965        }
966
967        public static String encodeCustomImProtocol(String protocolString) {
968            return "custom:" + protocolString;
969        }
970
971        public static Object decodeImProtocol(String encodedString) {
972            if (encodedString == null) {
973                return null;
974            }
975
976            if (encodedString.startsWith("pre:")) {
977                return Integer.parseInt(encodedString.substring(4));
978            }
979
980            if (encodedString.startsWith("custom:")) {
981                return encodedString.substring(7);
982            }
983
984            throw new IllegalArgumentException(
985                    "the value is not a valid encoded protocol, " + encodedString);
986        }
987
988        /**
989         * This looks up the provider name defined in
990         * {@link android.provider.Im.ProviderNames} from the predefined IM protocol id.
991         * This is used for interacting with the IM application.
992         *
993         * @param protocol the protocol ID
994         * @return the provider name the IM app uses for the given protocol, or null if no
995         * provider is defined for the given protocol
996         * @hide
997         */
998        public static String lookupProviderNameFromId(int protocol) {
999            switch (protocol) {
1000                case PROTOCOL_GOOGLE_TALK:
1001                    return Im.ProviderNames.GTALK;
1002                case PROTOCOL_AIM:
1003                    return Im.ProviderNames.AIM;
1004                case PROTOCOL_MSN:
1005                    return Im.ProviderNames.MSN;
1006                case PROTOCOL_YAHOO:
1007                    return Im.ProviderNames.YAHOO;
1008                case PROTOCOL_ICQ:
1009                    return Im.ProviderNames.ICQ;
1010                case PROTOCOL_JABBER:
1011                    return Im.ProviderNames.JABBER;
1012                case PROTOCOL_SKYPE:
1013                    return Im.ProviderNames.SKYPE;
1014                case PROTOCOL_QQ:
1015                    return Im.ProviderNames.QQ;
1016            }
1017            return null;
1018        }
1019
1020        /**
1021         * no public constructor since this is a utility class
1022         */
1023        private ContactMethods() {}
1024
1025        public static final CharSequence getDisplayLabel(Context context, int kind,
1026                int type, CharSequence label) {
1027            CharSequence display = "";
1028            switch (kind) {
1029                case KIND_EMAIL: {
1030                    if (type != People.ContactMethods.TYPE_CUSTOM) {
1031                        CharSequence[] labels = context.getResources().getTextArray(
1032                                com.android.internal.R.array.emailAddressTypes);
1033                        try {
1034                            display = labels[type - 1];
1035                        } catch (ArrayIndexOutOfBoundsException e) {
1036                            display = labels[ContactMethods.TYPE_HOME - 1];
1037                        }
1038                    } else {
1039                        if (!TextUtils.isEmpty(label)) {
1040                            display = label;
1041                        }
1042                    }
1043                    break;
1044                }
1045
1046                case KIND_POSTAL: {
1047                    if (type != People.ContactMethods.TYPE_CUSTOM) {
1048                        CharSequence[] labels = context.getResources().getTextArray(
1049                                com.android.internal.R.array.postalAddressTypes);
1050                        try {
1051                            display = labels[type - 1];
1052                        } catch (ArrayIndexOutOfBoundsException e) {
1053                            display = labels[ContactMethods.TYPE_HOME - 1];
1054                        }
1055                    } else {
1056                        if (!TextUtils.isEmpty(label)) {
1057                            display = label;
1058                        }
1059                    }
1060                    break;
1061                }
1062
1063                default:
1064                    display = context.getString(R.string.untitled);
1065            }
1066            return display;
1067        }
1068
1069        /**
1070         * Add a longitude and latitude location to a postal address.
1071         *
1072         * @param context the context to use when updating the database
1073         * @param postalId the address to update
1074         * @param latitude the latitude for the address
1075         * @param longitude the longitude for the address
1076         */
1077        public void addPostalLocation(Context context, long postalId,
1078                double latitude, double longitude) {
1079            final ContentResolver resolver = context.getContentResolver();
1080            // Insert the location
1081            ContentValues values = new ContentValues(2);
1082            values.put(POSTAL_LOCATION_LATITUDE, latitude);
1083            values.put(POSTAL_LOCATION_LONGITUDE, longitude);
1084            Uri loc = resolver.insert(CONTENT_URI, values);
1085            long locId = ContentUris.parseId(loc);
1086
1087            // Update the postal address
1088            values.clear();
1089            values.put(AUX_DATA, locId);
1090            resolver.update(ContentUris.withAppendedId(CONTENT_URI, postalId), values, null, null);
1091        }
1092
1093        /**
1094         * The content:// style URL for this table
1095         */
1096        public static final Uri CONTENT_URI =
1097            Uri.parse("content://contacts/contact_methods");
1098
1099        /**
1100         * The content:// style URL for sub-directory of e-mail addresses.
1101         */
1102        public static final Uri CONTENT_EMAIL_URI =
1103            Uri.parse("content://contacts/contact_methods/email");
1104
1105        /**
1106         * The MIME type of {@link #CONTENT_URI} providing a directory of
1107         * phones.
1108         */
1109        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact-methods";
1110
1111        /**
1112         * The MIME type of a {@link #CONTENT_EMAIL_URI} sub-directory of\
1113         * multiple {@link Contacts#KIND_EMAIL} entries.
1114         */
1115        public static final String CONTENT_EMAIL_TYPE = "vnd.android.cursor.dir/email";
1116
1117        /**
1118         * The MIME type of a {@link #CONTENT_EMAIL_URI} sub-directory of\
1119         * multiple {@link Contacts#KIND_POSTAL} entries.
1120         */
1121        public static final String CONTENT_POSTAL_TYPE = "vnd.android.cursor.dir/postal-address";
1122
1123        /**
1124         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
1125         * {@link Contacts#KIND_EMAIL} entry.
1126         */
1127        public static final String CONTENT_EMAIL_ITEM_TYPE = "vnd.android.cursor.item/email";
1128
1129        /**
1130         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
1131         * {@link Contacts#KIND_POSTAL} entry.
1132         */
1133        public static final String CONTENT_POSTAL_ITEM_TYPE
1134                = "vnd.android.cursor.item/postal-address";
1135
1136        /**
1137         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
1138         * {@link Contacts#KIND_IM} entry.
1139         */
1140        public static final String CONTENT_IM_ITEM_TYPE = "vnd.android.cursor.item/jabber-im";
1141
1142        /**
1143         * The default sort order for this table
1144         */
1145        public static final String DEFAULT_SORT_ORDER = "name ASC";
1146
1147        /**
1148         * The ID of the person this contact method is assigned to.
1149         * <P>Type: INTEGER (long)</P>
1150         */
1151        public static final String PERSON_ID = "person";
1152    }
1153
1154    /**
1155     * The IM presence columns with some contacts specific columns mixed in.
1156     */
1157    public interface PresenceColumns extends Im.CommonPresenceColumns {
1158        /**
1159         * The IM service the presence is coming from. Formatted using either
1160         * {@link Contacts.ContactMethods#encodePredefinedImProtocol} or
1161         * {@link Contacts.ContactMethods#encodeCustomImProtocol}.
1162         * <P>Type: STRING</P>
1163         */
1164        public static final String IM_PROTOCOL = "im_protocol";
1165
1166        /**
1167         * The IM handle the presence item is for. The handle is scoped to
1168         * the {@link #IM_PROTOCOL}.
1169         * <P>Type: STRING</P>
1170         */
1171        public static final String IM_HANDLE = "im_handle";
1172
1173        /**
1174         * The IM account for the local user that the presence data came from.
1175         * <P>Type: STRING</P>
1176         */
1177        public static final String IM_ACCOUNT = "im_account";
1178    }
1179
1180    /**
1181     * Contains presence information about contacts.
1182     * @hide
1183     */
1184    public static final class Presence
1185            implements BaseColumns, PresenceColumns, PeopleColumns {
1186        /**
1187         * The content:// style URL for this table
1188         */
1189        public static final Uri CONTENT_URI =
1190            Uri.parse("content://contacts/presence");
1191
1192        /**
1193         * The ID of the person this presence item is assigned to.
1194         * <P>Type: INTEGER (long)</P>
1195         */
1196        public static final String PERSON_ID = "person";
1197
1198        /**
1199         * Gets the resource ID for the proper presence icon.
1200         *
1201         * @param status the status to get the icon for
1202         * @return the resource ID for the proper presence icon
1203         */
1204        public static final int getPresenceIconResourceId(int status) {
1205            switch (status) {
1206                case Contacts.People.AVAILABLE:
1207                    return com.android.internal.R.drawable.presence_online;
1208
1209                case Contacts.People.IDLE:
1210                case Contacts.People.AWAY:
1211                    return com.android.internal.R.drawable.presence_away;
1212
1213                case Contacts.People.DO_NOT_DISTURB:
1214                    return com.android.internal.R.drawable.presence_busy;
1215
1216                case Contacts.People.INVISIBLE:
1217                    return com.android.internal.R.drawable.presence_invisible;
1218
1219                case Contacts.People.OFFLINE:
1220                default:
1221                    return com.android.internal.R.drawable.presence_offline;
1222            }
1223        }
1224
1225        /**
1226         * Sets a presence icon to the proper graphic
1227         *
1228         * @param icon the icon to to set
1229         * @param serverStatus that status
1230         */
1231        public static final void setPresenceIcon(ImageView icon, int serverStatus) {
1232            icon.setImageResource(getPresenceIconResourceId(serverStatus));
1233        }
1234    }
1235
1236    /**
1237     * Columns from the Organizations table that other columns join into themselves.
1238     */
1239    public interface OrganizationColumns {
1240        /**
1241         * The type of the organizations.
1242         * <P>Type: INTEGER (one of the constants below)</P>
1243         */
1244        public static final String TYPE = "type";
1245
1246        public static final int TYPE_CUSTOM = 0;
1247        public static final int TYPE_WORK = 1;
1248        public static final int TYPE_OTHER = 2;
1249
1250        /**
1251         * The user provided label, only used if TYPE is TYPE_CUSTOM.
1252         * <P>Type: TEXT</P>
1253         */
1254        public static final String LABEL = "label";
1255
1256        /**
1257         * The name of the company for this organization.
1258         * <P>Type: TEXT</P>
1259         */
1260        public static final String COMPANY = "company";
1261
1262        /**
1263         * The title within this organization.
1264         * <P>Type: TEXT</P>
1265         */
1266        public static final String TITLE = "title";
1267
1268        /**
1269         * The person this organization is tied to.
1270         * <P>Type: TEXT</P>
1271         */
1272        public static final String PERSON_ID = "person";
1273
1274        /**
1275         * Whether this is the primary organization
1276         * <P>Type: INTEGER (if set, non-0 means true)</P>
1277         */
1278        public static final String ISPRIMARY = "isprimary";
1279    }
1280
1281    /**
1282     * A sub directory of a single person that contains all of their Phones.
1283     */
1284    public static final class Organizations implements BaseColumns, OrganizationColumns {
1285        /**
1286         * no public constructor since this is a utility class
1287         */
1288        private Organizations() {}
1289
1290        public static final CharSequence getDisplayLabel(Context context, int type,
1291                CharSequence label) {
1292            CharSequence display = "";
1293
1294            if (type != TYPE_CUSTOM) {
1295                CharSequence[] labels = context.getResources().getTextArray(
1296                        com.android.internal.R.array.organizationTypes);
1297                try {
1298                    display = labels[type - 1];
1299                } catch (ArrayIndexOutOfBoundsException e) {
1300                    display = labels[Organizations.TYPE_WORK - 1];
1301                }
1302            } else {
1303                if (!TextUtils.isEmpty(label)) {
1304                    display = label;
1305                }
1306            }
1307            return display;
1308        }
1309
1310        /**
1311         * The content:// style URL for this table
1312         */
1313        public static final Uri CONTENT_URI =
1314            Uri.parse("content://contacts/organizations");
1315
1316        /**
1317         * The directory twig for this sub-table
1318         */
1319        public static final String CONTENT_DIRECTORY = "organizations";
1320
1321        /**
1322         * The default sort order for this table
1323         */
1324        public static final String DEFAULT_SORT_ORDER = "company, title, isprimary ASC";
1325    }
1326
1327    /**
1328     * Columns from the Photos table that other columns join into themselves.
1329     */
1330    public interface PhotosColumns {
1331        /**
1332         * The _SYNC_VERSION of the photo that was last downloaded
1333         * <P>Type: TEXT</P>
1334         */
1335        public static final String LOCAL_VERSION = "local_version";
1336
1337        /**
1338         * The person this photo is associated with.
1339         * <P>Type: TEXT</P>
1340         */
1341        public static final String PERSON_ID = "person";
1342
1343        /**
1344         * non-zero if a download is required and the photo isn't marked as a bad resource.
1345         * You must specify this in the columns in order to use it in the where clause.
1346         * <P>Type: INTEGER(boolean)</P>
1347         */
1348        public static final String DOWNLOAD_REQUIRED = "download_required";
1349
1350        /**
1351         * non-zero if this photo is known to exist on the server
1352         * <P>Type: INTEGER(boolean)</P>
1353         */
1354        public static final String EXISTS_ON_SERVER = "exists_on_server";
1355
1356        /**
1357         * Contains the description of the upload or download error from
1358         * the previous attempt. If null then the previous attempt succeeded.
1359         * <P>Type: TEXT</P>
1360         */
1361        public static final String SYNC_ERROR = "sync_error";
1362
1363        /**
1364         * The image data, or null if there is no image.
1365         * <P>Type: BLOB</P>
1366         */
1367        public static final String DATA = "data";
1368
1369    }
1370
1371    /**
1372     * The photos over all of the people
1373     */
1374    public static final class Photos implements BaseColumns, PhotosColumns, SyncConstValue {
1375        /**
1376         * no public constructor since this is a utility class
1377         */
1378        private Photos() {}
1379
1380        /**
1381         * The content:// style URL for this table
1382         */
1383        public static final Uri CONTENT_URI =
1384            Uri.parse("content://contacts/photos");
1385
1386        /**
1387         * The directory twig for this sub-table
1388         */
1389        public static final String CONTENT_DIRECTORY = "photo";
1390
1391        /**
1392         * The default sort order for this table
1393         */
1394        public static final String DEFAULT_SORT_ORDER = "person ASC";
1395    }
1396
1397    public interface ExtensionsColumns {
1398        /**
1399         * The name of this extension. May not be null. There may be at most one row for each name.
1400         * <P>Type: TEXT</P>
1401         */
1402        public static final String NAME = "name";
1403
1404        /**
1405         * The value of this extension. May not be null.
1406         * <P>Type: TEXT</P>
1407         */
1408        public static final String VALUE = "value";
1409    }
1410
1411    /**
1412     * The extensions for a person
1413     */
1414    public static final class Extensions implements BaseColumns, ExtensionsColumns {
1415        /**
1416         * no public constructor since this is a utility class
1417         */
1418        private Extensions() {}
1419
1420        /**
1421         * The content:// style URL for this table
1422         */
1423        public static final Uri CONTENT_URI =
1424            Uri.parse("content://contacts/extensions");
1425
1426        /**
1427         * The MIME type of {@link #CONTENT_URI} providing a directory of
1428         * phones.
1429         */
1430        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_extensions";
1431
1432        /**
1433         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
1434         * phone.
1435         */
1436        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_extensions";
1437        /**
1438         * The default sort order for this table
1439         */
1440        public static final String DEFAULT_SORT_ORDER = "person, name ASC";
1441
1442        /**
1443         * The ID of the person this phone number is assigned to.
1444         * <P>Type: INTEGER (long)</P>
1445         */
1446        public static final String PERSON_ID = "person";
1447    }
1448
1449    /**
1450     * Contains helper classes used to create or manage {@link android.content.Intent Intents}
1451     * that involve contacts.
1452     */
1453    public static final class Intents {
1454        /**
1455         * This is the intent that is fired when a search suggestion is clicked on.
1456         */
1457        public static final String SEARCH_SUGGESTION_CLICKED =
1458                ContactsContract.Intents.SEARCH_SUGGESTION_CLICKED;
1459
1460        /**
1461         * This is the intent that is fired when a search suggestion for dialing a number
1462         * is clicked on.
1463         */
1464        public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED =
1465                ContactsContract.Intents.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED;
1466
1467        /**
1468         * This is the intent that is fired when a search suggestion for creating a contact
1469         * is clicked on.
1470         */
1471        public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED =
1472                ContactsContract.Intents.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED;
1473
1474        /**
1475         * Starts an Activity that lets the user pick a contact to attach an image to.
1476         * After picking the contact it launches the image cropper in face detection mode.
1477         */
1478        public static final String ATTACH_IMAGE = ContactsContract.Intents.ATTACH_IMAGE;
1479
1480        /**
1481         * Takes as input a data URI with a mailto: or tel: scheme. If a single
1482         * contact exists with the given data it will be shown. If no contact
1483         * exists, a dialog will ask the user if they want to create a new
1484         * contact with the provided details filled in. If multiple contacts
1485         * share the data the user will be prompted to pick which contact they
1486         * want to view.
1487         * <p>
1488         * For <code>mailto:</code> URIs, the scheme specific portion must be a
1489         * raw email address, such as one built using
1490         * {@link Uri#fromParts(String, String, String)}.
1491         * <p>
1492         * For <code>tel:</code> URIs, the scheme specific portion is compared
1493         * to existing numbers using the standard caller ID lookup algorithm.
1494         * The number must be properly encoded, for example using
1495         * {@link Uri#fromParts(String, String, String)}.
1496         * <p>
1497         * Any extras from the {@link Insert} class will be passed along to the
1498         * create activity if there are no contacts to show.
1499         * <p>
1500         * Passing true for the {@link #EXTRA_FORCE_CREATE} extra will skip
1501         * prompting the user when the contact doesn't exist.
1502         */
1503        public static final String SHOW_OR_CREATE_CONTACT =
1504                ContactsContract.Intents.SHOW_OR_CREATE_CONTACT;
1505
1506        /**
1507         * Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new
1508         * contact if no matching contact found. Otherwise, default behavior is
1509         * to prompt user with dialog before creating.
1510         * <p>
1511         * Type: BOOLEAN
1512         */
1513        public static final String EXTRA_FORCE_CREATE = ContactsContract.Intents.EXTRA_FORCE_CREATE;
1514
1515        /**
1516         * Used with {@link #SHOW_OR_CREATE_CONTACT} to specify an exact
1517         * description to be shown when prompting user about creating a new
1518         * contact.
1519         * <p>
1520         * Type: STRING
1521         */
1522        public static final String EXTRA_CREATE_DESCRIPTION =
1523                ContactsContract.Intents.EXTRA_CREATE_DESCRIPTION;
1524
1525        /**
1526         * Intents related to the Contacts app UI.
1527         */
1528        public static final class UI {
1529            /**
1530             * The action for the default contacts list tab.
1531             */
1532            public static final String LIST_DEFAULT = ContactsContract.Intents.UI.LIST_DEFAULT;
1533
1534            /**
1535             * The action for the contacts list tab.
1536             */
1537            public static final String LIST_GROUP_ACTION =
1538                    ContactsContract.Intents.UI.LIST_GROUP_ACTION;
1539
1540            /**
1541             * When in LIST_GROUP_ACTION mode, this is the group to display.
1542             */
1543            public static final String GROUP_NAME_EXTRA_KEY =
1544                    ContactsContract.Intents.UI.GROUP_NAME_EXTRA_KEY;
1545            /**
1546             * The action for the all contacts list tab.
1547             */
1548            public static final String LIST_ALL_CONTACTS_ACTION =
1549                    ContactsContract.Intents.UI.LIST_ALL_CONTACTS_ACTION;
1550
1551            /**
1552             * The action for the contacts with phone numbers list tab.
1553             */
1554            public static final String LIST_CONTACTS_WITH_PHONES_ACTION =
1555                    ContactsContract.Intents.UI.LIST_CONTACTS_WITH_PHONES_ACTION;
1556
1557            /**
1558             * The action for the starred contacts list tab.
1559             */
1560            public static final String LIST_STARRED_ACTION =
1561                    ContactsContract.Intents.UI.LIST_STARRED_ACTION;
1562
1563            /**
1564             * The action for the frequent contacts list tab.
1565             */
1566            public static final String LIST_FREQUENT_ACTION =
1567                    ContactsContract.Intents.UI.LIST_FREQUENT_ACTION;
1568
1569            /**
1570             * The action for the "strequent" contacts list tab. It first lists the starred
1571             * contacts in alphabetical order and then the frequent contacts in descending
1572             * order of the number of times they have been contacted.
1573             */
1574            public static final String LIST_STREQUENT_ACTION =
1575                    ContactsContract.Intents.UI.LIST_STREQUENT_ACTION;
1576
1577            /**
1578             * A key for to be used as an intent extra to set the activity
1579             * title to a custom String value.
1580             */
1581            public static final String TITLE_EXTRA_KEY =
1582                    ContactsContract.Intents.UI.TITLE_EXTRA_KEY;
1583
1584            /**
1585             * Activity Action: Display a filtered list of contacts
1586             * <p>
1587             * Input: Extra field {@link #FILTER_TEXT_EXTRA_KEY} is the text to use for
1588             * filtering
1589             * <p>
1590             * Output: Nothing.
1591             */
1592            public static final String FILTER_CONTACTS_ACTION =
1593                    ContactsContract.Intents.UI.FILTER_CONTACTS_ACTION;
1594
1595            /**
1596             * Used as an int extra field in {@link #FILTER_CONTACTS_ACTION}
1597             * intents to supply the text on which to filter.
1598             */
1599            public static final String FILTER_TEXT_EXTRA_KEY =
1600                    ContactsContract.Intents.UI.FILTER_TEXT_EXTRA_KEY;
1601        }
1602
1603        /**
1604         * Convenience class that contains string constants used
1605         * to create contact {@link android.content.Intent Intents}.
1606         */
1607        public static final class Insert {
1608            /** The action code to use when adding a contact */
1609            public static final String ACTION = ContactsContract.Intents.Insert.ACTION;
1610            /**
1611             * If present, forces a bypass of quick insert mode.
1612             */
1613            public static final String FULL_MODE = ContactsContract.Intents.Insert.FULL_MODE;
1614            /**
1615             * The extra field for the contact name.
1616             * <P>Type: String</P>
1617             */
1618            public static final String NAME = ContactsContract.Intents.Insert.NAME;
1619
1620            /**
1621             * The extra field for the contact phonetic name.
1622             * <P>Type: String</P>
1623             */
1624            public static final String PHONETIC_NAME =
1625                    ContactsContract.Intents.Insert.PHONETIC_NAME;
1626
1627            /**
1628             * The extra field for the contact company.
1629             * <P>Type: String</P>
1630             */
1631            public static final String COMPANY = ContactsContract.Intents.Insert.COMPANY;
1632
1633            /**
1634             * The extra field for the contact job title.
1635             * <P>Type: String</P>
1636             */
1637            public static final String JOB_TITLE = ContactsContract.Intents.Insert.JOB_TITLE;
1638
1639            /**
1640             * The extra field for the contact notes.
1641             * <P>Type: String</P>
1642             */
1643            public static final String NOTES = ContactsContract.Intents.Insert.NOTES;
1644
1645            /**
1646             * The extra field for the contact phone number.
1647             * <P>Type: String</P>
1648             */
1649            public static final String PHONE = ContactsContract.Intents.Insert.PHONE;
1650
1651            /**
1652             * The extra field for the contact phone number type.
1653             * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
1654             *  or a string specifying a custom label.</P>
1655             */
1656            public static final String PHONE_TYPE = ContactsContract.Intents.Insert.PHONE_TYPE;
1657
1658            /**
1659             * The extra field for the phone isprimary flag.
1660             * <P>Type: boolean</P>
1661             */
1662            public static final String PHONE_ISPRIMARY =
1663                    ContactsContract.Intents.Insert.PHONE_ISPRIMARY;
1664
1665            /**
1666             * The extra field for an optional second contact phone number.
1667             * <P>Type: String</P>
1668             */
1669            public static final String SECONDARY_PHONE =
1670                    ContactsContract.Intents.Insert.SECONDARY_PHONE;
1671
1672            /**
1673             * The extra field for an optional second contact phone number type.
1674             * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
1675             *  or a string specifying a custom label.</P>
1676             */
1677            public static final String SECONDARY_PHONE_TYPE =
1678                    ContactsContract.Intents.Insert.SECONDARY_PHONE_TYPE;
1679
1680            /**
1681             * The extra field for an optional third contact phone number.
1682             * <P>Type: String</P>
1683             */
1684            public static final String TERTIARY_PHONE =
1685                    ContactsContract.Intents.Insert.TERTIARY_PHONE;
1686
1687            /**
1688             * The extra field for an optional third contact phone number type.
1689             * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
1690             *  or a string specifying a custom label.</P>
1691             */
1692            public static final String TERTIARY_PHONE_TYPE =
1693                    ContactsContract.Intents.Insert.TERTIARY_PHONE_TYPE;
1694
1695            /**
1696             * The extra field for the contact email address.
1697             * <P>Type: String</P>
1698             */
1699            public static final String EMAIL = ContactsContract.Intents.Insert.EMAIL;
1700
1701            /**
1702             * The extra field for the contact email type.
1703             * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
1704             *  or a string specifying a custom label.</P>
1705             */
1706            public static final String EMAIL_TYPE = ContactsContract.Intents.Insert.EMAIL_TYPE;
1707
1708            /**
1709             * The extra field for the email isprimary flag.
1710             * <P>Type: boolean</P>
1711             */
1712            public static final String EMAIL_ISPRIMARY =
1713                    ContactsContract.Intents.Insert.EMAIL_ISPRIMARY;
1714
1715            /**
1716             * The extra field for an optional second contact email address.
1717             * <P>Type: String</P>
1718             */
1719            public static final String SECONDARY_EMAIL =
1720                    ContactsContract.Intents.Insert.SECONDARY_EMAIL;
1721
1722            /**
1723             * The extra field for an optional second contact email type.
1724             * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
1725             *  or a string specifying a custom label.</P>
1726             */
1727            public static final String SECONDARY_EMAIL_TYPE =
1728                    ContactsContract.Intents.Insert.SECONDARY_EMAIL_TYPE;
1729
1730            /**
1731             * The extra field for an optional third contact email address.
1732             * <P>Type: String</P>
1733             */
1734            public static final String TERTIARY_EMAIL =
1735                    ContactsContract.Intents.Insert.TERTIARY_EMAIL;
1736
1737            /**
1738             * The extra field for an optional third contact email type.
1739             * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
1740             *  or a string specifying a custom label.</P>
1741             */
1742            public static final String TERTIARY_EMAIL_TYPE =
1743                    ContactsContract.Intents.Insert.TERTIARY_EMAIL_TYPE;
1744
1745            /**
1746             * The extra field for the contact postal address.
1747             * <P>Type: String</P>
1748             */
1749            public static final String POSTAL = ContactsContract.Intents.Insert.POSTAL;
1750
1751            /**
1752             * The extra field for the contact postal address type.
1753             * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
1754             *  or a string specifying a custom label.</P>
1755             */
1756            public static final String POSTAL_TYPE = ContactsContract.Intents.Insert.POSTAL_TYPE;
1757
1758            /**
1759             * The extra field for the postal isprimary flag.
1760             * <P>Type: boolean</P>
1761             */
1762            public static final String POSTAL_ISPRIMARY = ContactsContract.Intents.Insert.POSTAL_ISPRIMARY;
1763
1764            /**
1765             * The extra field for an IM handle.
1766             * <P>Type: String</P>
1767             */
1768            public static final String IM_HANDLE = ContactsContract.Intents.Insert.IM_HANDLE;
1769
1770            /**
1771             * The extra field for the IM protocol
1772             * <P>Type: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol}
1773             * or {@link Contacts.ContactMethods#encodeCustomImProtocol}.</P>
1774             */
1775            public static final String IM_PROTOCOL = ContactsContract.Intents.Insert.IM_PROTOCOL;
1776
1777            /**
1778             * The extra field for the IM isprimary flag.
1779             * <P>Type: boolean</P>
1780             */
1781            public static final String IM_ISPRIMARY = ContactsContract.Intents.Insert.IM_ISPRIMARY;
1782        }
1783    }
1784}
1785