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