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