1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package android.provider;
18 
19 import android.accounts.Account;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.RequiresPermission;
23 import android.annotation.SdkConstant;
24 import android.annotation.SdkConstant.SdkConstantType;
25 import android.annotation.SystemApi;
26 import android.annotation.TestApi;
27 import android.app.Activity;
28 import android.compat.annotation.UnsupportedAppUsage;
29 import android.content.BroadcastReceiver;
30 import android.content.ComponentName;
31 import android.content.ContentProviderClient;
32 import android.content.ContentProviderOperation;
33 import android.content.ContentResolver;
34 import android.content.ContentUris;
35 import android.content.ContentValues;
36 import android.content.Context;
37 import android.content.ContextWrapper;
38 import android.content.CursorEntityIterator;
39 import android.content.Entity;
40 import android.content.Entity.NamedContentValues;
41 import android.content.EntityIterator;
42 import android.content.Intent;
43 import android.content.IntentFilter;
44 import android.content.res.AssetFileDescriptor;
45 import android.content.res.Resources;
46 import android.database.Cursor;
47 import android.database.CursorWrapper;
48 import android.database.DatabaseUtils;
49 import android.graphics.Rect;
50 import android.net.Uri;
51 import android.os.Build;
52 import android.os.Bundle;
53 import android.os.Parcel;
54 import android.os.Parcelable;
55 import android.os.RemoteException;
56 import android.telecom.PhoneAccountHandle;
57 import android.text.TextUtils;
58 import android.util.DisplayMetrics;
59 import android.util.Log;
60 import android.util.Pair;
61 import android.view.View;
62 
63 import com.google.android.collect.Sets;
64 
65 import java.io.ByteArrayInputStream;
66 import java.io.IOException;
67 import java.io.InputStream;
68 import java.util.ArrayList;
69 import java.util.HashMap;
70 import java.util.List;
71 import java.util.Map;
72 import java.util.Objects;
73 import java.util.Set;
74 
75 /**
76  * <p>
77  * The contract between the contacts provider and applications. Contains
78  * definitions for the supported URIs and columns. These APIs supersede
79  * {@link Contacts}.
80  * </p>
81  * <h3>Overview</h3>
82  * <p>
83  * ContactsContract defines an extensible database of contact-related
84  * information. Contact information is stored in a three-tier data model:
85  * </p>
86  * <ul>
87  * <li>
88  * A row in the {@link Data} table can store any kind of personal data, such
89  * as a phone number or email addresses.  The set of data kinds that can be
90  * stored in this table is open-ended. There is a predefined set of common
91  * kinds, but any application can add its own data kinds.
92  * </li>
93  * <li>
94  * A row in the {@link RawContacts} table represents a set of data describing a
95  * person and associated with a single account (for example, one of the user's
96  * Gmail accounts).
97  * </li>
98  * <li>
99  * A row in the {@link Contacts} table represents an aggregate of one or more
100  * RawContacts presumably describing the same person.  When data in or associated with
101  * the RawContacts table is changed, the affected aggregate contacts are updated as
102  * necessary.
103  * </li>
104  * </ul>
105  * <p>
106  * Other tables include:
107  * </p>
108  * <ul>
109  * <li>
110  * {@link Groups}, which contains information about raw contact groups
111  * such as Gmail contact groups.  The
112  * current API does not support the notion of groups spanning multiple accounts.
113  * </li>
114  * <li>
115  * {@link StatusUpdates}, which contains social status updates including IM
116  * availability.
117  * </li>
118  * <li>
119  * {@link AggregationExceptions}, which is used for manual aggregation and
120  * disaggregation of raw contacts
121  * </li>
122  * <li>
123  * {@link Settings}, which contains visibility and sync settings for accounts
124  * and groups.
125  * </li>
126  * <li>
127  * {@link SyncState}, which contains free-form data maintained on behalf of sync
128  * adapters
129  * </li>
130  * <li>
131  * {@link PhoneLookup}, which is used for quick caller-ID lookup</li>
132  * </ul>
133  */
134 @SuppressWarnings("unused")
135 public final class ContactsContract {
136     /** The authority for the contacts provider */
137     public static final String AUTHORITY = "com.android.contacts";
138     /** A content:// style uri to the authority for the contacts provider */
139     public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
140 
141     /**
142      * Prefix for column names that are not visible to client apps.
143      * @hide
144      */
145     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
146     @TestApi
147     public static final String HIDDEN_COLUMN_PREFIX = "x_";
148 
149     /**
150      * An optional URI parameter for insert, update, or delete queries
151      * that allows the caller
152      * to specify that it is a sync adapter. The default value is false. If true
153      * {@link RawContacts#DIRTY} is not automatically set and the
154      * "syncToNetwork" parameter is set to false when calling
155      * {@link
156      * ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}.
157      * This prevents an unnecessary extra synchronization, see the discussion of
158      * the delete operation in {@link RawContacts}.
159      */
160     public static final String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
161 
162     /**
163      * Query parameter that should be used by the client to access a specific
164      * {@link Directory}. The parameter value should be the _ID of the corresponding
165      * directory, e.g.
166      * {@code content://com.android.contacts/data/emails/filter/acme?directory=3}
167      */
168     public static final String DIRECTORY_PARAM_KEY = "directory";
169 
170     /**
171      * A query parameter that limits the number of results returned for supported URIs. The
172      * parameter value should be an integer.
173      *
174      * <p>This parameter is not supported by all URIs.  Supported URIs include, but not limited to,
175      * {@link Contacts#CONTENT_URI},
176      * {@link RawContacts#CONTENT_URI},
177      * {@link Data#CONTENT_URI},
178      * {@link CommonDataKinds.Phone#CONTENT_URI},
179      * {@link CommonDataKinds.Callable#CONTENT_URI},
180      * {@link CommonDataKinds.Email#CONTENT_URI},
181      * {@link CommonDataKinds.Contactables#CONTENT_URI},
182      *
183      * <p>In order to limit the number of rows returned by a non-supported URI, you can implement a
184      * {@link CursorWrapper} and override the {@link CursorWrapper#getCount()} methods.
185      */
186     public static final String LIMIT_PARAM_KEY = "limit";
187 
188     /**
189      * A query parameter specifing a primary account. This parameter should be used with
190      * {@link #PRIMARY_ACCOUNT_TYPE}. The contacts provider handling a query may rely on
191      * this information to optimize its query results.
192      *
193      * For example, in an email composition screen, its implementation can specify an account when
194      * obtaining possible recipients, letting the provider know which account is selected during
195      * the composition. The provider may use the "primary account" information to optimize
196      * the search result.
197      */
198     public static final String PRIMARY_ACCOUNT_NAME = "name_for_primary_account";
199 
200     /**
201      * A query parameter specifing a primary account. This parameter should be used with
202      * {@link #PRIMARY_ACCOUNT_NAME}. See the doc in {@link #PRIMARY_ACCOUNT_NAME}.
203      */
204     public static final String PRIMARY_ACCOUNT_TYPE = "type_for_primary_account";
205 
206     /**
207      * A boolean parameter for {@link Contacts#CONTENT_STREQUENT_URI} and
208      * {@link Contacts#CONTENT_STREQUENT_FILTER_URI}, which requires the ContactsProvider to
209      * return only phone-related results.
210      */
211     public static final String STREQUENT_PHONE_ONLY = "strequent_phone_only";
212 
213     /**
214      * A key to a boolean in the "extras" bundle of the cursor.
215      * The boolean indicates that the provider did not create a snippet and that the client asking
216      * for the snippet should do it (true means the snippeting was deferred to the client).
217      *
218      * @see SearchSnippets
219      */
220     public static final String DEFERRED_SNIPPETING = "deferred_snippeting";
221 
222     /**
223      * Key to retrieve the original deferred snippeting from the cursor on the client side.
224      *
225      * @see SearchSnippets
226      * @see #DEFERRED_SNIPPETING
227      */
228     public static final String DEFERRED_SNIPPETING_QUERY = "deferred_snippeting_query";
229 
230     /**
231      * A boolean parameter for {@link CommonDataKinds.Phone#CONTENT_URI Phone.CONTENT_URI},
232      * {@link CommonDataKinds.Email#CONTENT_URI Email.CONTENT_URI}, and
233      * {@link CommonDataKinds.StructuredPostal#CONTENT_URI StructuredPostal.CONTENT_URI}.
234      * This enables a content provider to remove duplicate entries in results.
235      */
236     public static final String REMOVE_DUPLICATE_ENTRIES = "remove_duplicate_entries";
237 
238     /**
239      * <p>
240      * API for obtaining a pre-authorized version of a URI that normally requires special
241      * permission (beyond READ_CONTACTS) to read.  The caller obtaining the pre-authorized URI
242      * must already have the necessary permissions to access the URI; otherwise a
243      * {@link SecurityException} will be thrown. Unlike {@link Context#grantUriPermission},
244      * this can be used to grant permissions that aren't explicitly required for the URI inside
245      * AndroidManifest.xml. For example, permissions that are only required when reading URIs
246      * that refer to the user's profile.
247      * </p>
248      * <p>
249      * The authorized URI returned in the bundle contains an expiring token that allows the
250      * caller to execute the query without having the special permissions that would normally
251      * be required. The token expires in five minutes.
252      * </p>
253      * <p>
254      * This API does not access disk, and should be safe to invoke from the UI thread.
255      * </p>
256      * <p>
257      * Example usage:
258      * <pre>
259      * Uri profileUri = ContactsContract.Profile.CONTENT_VCARD_URI;
260      * Bundle uriBundle = new Bundle();
261      * uriBundle.putParcelable(ContactsContract.Authorization.KEY_URI_TO_AUTHORIZE, uri);
262      * Bundle authResponse = getContext().getContentResolver().call(
263      *         ContactsContract.AUTHORITY_URI,
264      *         ContactsContract.Authorization.AUTHORIZATION_METHOD,
265      *         null, // String arg, not used.
266      *         uriBundle);
267      * if (authResponse != null) {
268      *     Uri preauthorizedProfileUri = (Uri) authResponse.getParcelable(
269      *             ContactsContract.Authorization.KEY_AUTHORIZED_URI);
270      *     // This pre-authorized URI can be queried by a caller without READ_PROFILE
271      *     // permission.
272      * }
273      * </pre>
274      * </p>
275      *
276      * @hide
277      */
278     public static final class Authorization {
279         /**
280          * The method to invoke to create a pre-authorized URI out of the input argument.
281          */
282         public static final String AUTHORIZATION_METHOD = "authorize";
283 
284         /**
285          * The key to set in the outbound Bundle with the URI that should be authorized.
286          */
287         public static final String KEY_URI_TO_AUTHORIZE = "uri_to_authorize";
288 
289         /**
290          * The key to retrieve from the returned Bundle to obtain the pre-authorized URI.
291          */
292         public static final String KEY_AUTHORIZED_URI = "authorized_uri";
293     }
294 
295     /**
296      * A Directory represents a contacts corpus, e.g. Local contacts,
297      * Google Apps Global Address List or Corporate Global Address List.
298      * <p>
299      * A Directory is implemented as a content provider with its unique authority and
300      * the same API as the main Contacts Provider.  However, there is no expectation that
301      * every directory provider will implement this Contract in its entirety.  If a
302      * directory provider does not have an implementation for a specific request, it
303      * should throw an UnsupportedOperationException.
304      * </p>
305      * <p>
306      * The most important use case for Directories is search.  A Directory provider is
307      * expected to support at least {@link ContactsContract.Contacts#CONTENT_FILTER_URI
308      * Contacts.CONTENT_FILTER_URI}.  If a Directory provider wants to participate
309      * in email and phone lookup functionalities, it should also implement
310      * {@link CommonDataKinds.Email#CONTENT_FILTER_URI CommonDataKinds.Email.CONTENT_FILTER_URI}
311      * and
312      * {@link CommonDataKinds.Phone#CONTENT_FILTER_URI CommonDataKinds.Phone.CONTENT_FILTER_URI}.
313      * </p>
314      * <p>
315      * A directory provider should return NULL for every projection field it does not
316      * recognize, rather than throwing an exception.  This way it will not be broken
317      * if ContactsContract is extended with new fields in the future.
318      * </p>
319      * <p>
320      * The client interacts with a directory via Contacts Provider by supplying an
321      * optional {@code directory=} query parameter.
322      * <p>
323      * <p>
324      * When the Contacts Provider receives the request, it transforms the URI and forwards
325      * the request to the corresponding directory content provider.
326      * The URI is transformed in the following fashion:
327      * <ul>
328      * <li>The URI authority is replaced with the corresponding {@link #DIRECTORY_AUTHORITY}.</li>
329      * <li>The {@code accountName=} and {@code accountType=} parameters are added or
330      * replaced using the corresponding {@link #ACCOUNT_TYPE} and {@link #ACCOUNT_NAME} values.</li>
331      * </ul>
332      * </p>
333      * <p>
334      * Clients should send directory requests to Contacts Provider and let it
335      * forward them to the respective providers rather than constructing
336      * directory provider URIs by themselves. This level of indirection allows
337      * Contacts Provider to implement additional system-level features and
338      * optimizations. Access to Contacts Provider is protected by the
339      * READ_CONTACTS permission, but access to the directory provider is protected by
340      * BIND_DIRECTORY_SEARCH. This permission was introduced at the API level 17, for previous
341      * platform versions the provider should perform the following check to make sure the call
342      * is coming from the ContactsProvider:
343      * <pre>
344      * private boolean isCallerAllowed() {
345      *   PackageManager pm = getContext().getPackageManager();
346      *   for (String packageName: pm.getPackagesForUid(Binder.getCallingUid())) {
347      *     if (packageName.equals("com.android.providers.contacts")) {
348      *       return true;
349      *     }
350      *   }
351      *   return false;
352      * }
353      * </pre>
354      * </p>
355      * <p>
356      * The Directory table is read-only and is maintained by the Contacts Provider
357      * automatically.
358      * </p>
359      * <p>It always has at least these two rows:
360      * <ul>
361      * <li>
362      * The local directory. It has {@link Directory#_ID Directory._ID} =
363      * {@link Directory#DEFAULT Directory.DEFAULT}. This directory can be used to access locally
364      * stored contacts. The same can be achieved by omitting the {@code directory=}
365      * parameter altogether.
366      * </li>
367      * <li>
368      * The local invisible contacts. The corresponding directory ID is
369      * {@link Directory#LOCAL_INVISIBLE Directory.LOCAL_INVISIBLE}.
370      * </li>
371      * </ul>
372      * </p>
373      * <p>Custom Directories are discovered by the Contacts Provider following this procedure:
374      * <ul>
375      * <li>It finds all installed content providers with meta data identifying them
376      * as directory providers in AndroidManifest.xml:
377      * <code>
378      * &lt;meta-data android:name="android.content.ContactDirectory"
379      *               android:value="true" /&gt;
380      * </code>
381      * <p>
382      * This tag should be placed inside the corresponding content provider declaration.
383      * </p>
384      * </li>
385      * <li>
386      * Then Contacts Provider sends a {@link Directory#CONTENT_URI Directory.CONTENT_URI}
387      * query to each of the directory authorities.  A directory provider must implement
388      * this query and return a list of directories.  Each directory returned by
389      * the provider must have a unique combination for the {@link #ACCOUNT_NAME} and
390      * {@link #ACCOUNT_TYPE} columns (nulls are allowed).  Since directory IDs are assigned
391      * automatically, the _ID field will not be part of the query projection.
392      * </li>
393      * <li>Contacts Provider compiles directory lists received from all directory
394      * providers into one, assigns each individual directory a globally unique ID and
395      * stores all directory records in the Directory table.
396      * </li>
397      * </ul>
398      * </p>
399      * <p>Contacts Provider automatically interrogates newly installed or replaced packages.
400      * Thus simply installing a package containing a directory provider is sufficient
401      * to have that provider registered.  A package supplying a directory provider does
402      * not have to contain launchable activities.
403      * </p>
404      * <p>
405      * Every row in the Directory table is automatically associated with the corresponding package
406      * (apk).  If the package is later uninstalled, all corresponding directory rows
407      * are automatically removed from the Contacts Provider.
408      * </p>
409      * <p>
410      * When the list of directories handled by a directory provider changes
411      * (for instance when the user adds a new Directory account), the directory provider
412      * should call {@link #notifyDirectoryChange} to notify the Contacts Provider of the change.
413      * In response, the Contacts Provider will requery the directory provider to obtain the
414      * new list of directories.
415      * </p>
416      * <p>
417      * A directory row can be optionally associated with an existing account
418      * (see {@link android.accounts.AccountManager}). If the account is later removed,
419      * the corresponding directory rows are automatically removed from the Contacts Provider.
420      * </p>
421      */
422     public static final class Directory implements BaseColumns {
423 
424         /**
425          * Not instantiable.
426          */
Directory()427         private Directory() {
428         }
429 
430         /**
431          * The content:// style URI for this table.  Requests to this URI can be
432          * performed on the UI thread because they are always unblocking.
433          */
434         public static final Uri CONTENT_URI =
435                 Uri.withAppendedPath(AUTHORITY_URI, "directories");
436 
437         /**
438          * URI used for getting all directories from both the calling user and the managed profile
439          * that is linked to it.
440          * <p>
441          * It supports the same semantics as {@link #CONTENT_URI} and returns the same columns.<br>
442          * If the device has no managed profile that is linked to the calling user, it behaves
443          * in the exact same way as {@link #CONTENT_URI}.<br>
444          * If there is a managed profile linked to the calling user, it will return merged results
445          * from both.
446          * <p>
447          * Note: this query returns the calling user results before the managed profile results,
448          * and this order is not affected by the sorting parameter.
449          *
450          */
451         public static final Uri ENTERPRISE_CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
452                 "directories_enterprise");
453 
454         /**
455          * Access file provided by remote directory. It allows both calling user and managed profile
456          * remote directory, but not local and invisible directory.
457          * <p>
458          * It is supported only by a few specific places for referring to contact pictures in the
459          * remote directory. Contact picture URIs, e.g.
460          * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}, may contain this kind of URI.
461          *
462          * @hide
463          */
464         public static final Uri ENTERPRISE_FILE_URI = Uri.withAppendedPath(AUTHORITY_URI,
465                 "directory_file_enterprise");
466 
467 
468         /**
469          * The MIME-type of {@link #CONTENT_URI} providing a directory of
470          * contact directories.
471          */
472         public static final String CONTENT_TYPE =
473                 "vnd.android.cursor.dir/contact_directories";
474 
475         /**
476          * The MIME type of a {@link #CONTENT_URI} item.
477          */
478         public static final String CONTENT_ITEM_TYPE =
479                 "vnd.android.cursor.item/contact_directory";
480 
481         /**
482          * _ID of the default directory, which represents locally stored contacts.
483          * <b>This is only supported by {@link ContactsContract.Contacts#CONTENT_URI} and
484          * {@link ContactsContract.Contacts#CONTENT_FILTER_URI}.
485          * Other URLs do not support the concept of "visible" or "invisible" contacts.
486          */
487         public static final long DEFAULT = 0;
488 
489         /**
490          * _ID of the directory that represents locally stored invisible contacts.
491          */
492         public static final long LOCAL_INVISIBLE = 1;
493 
494         /**
495          * _ID of the managed profile default directory, which represents locally stored contacts.
496          */
497         public static final long ENTERPRISE_DEFAULT = Directory.ENTERPRISE_DIRECTORY_ID_BASE
498                 + DEFAULT;
499 
500         /**
501          * _ID of the managed profile directory that represents locally stored invisible contacts.
502          */
503         public static final long ENTERPRISE_LOCAL_INVISIBLE = Directory.ENTERPRISE_DIRECTORY_ID_BASE
504                 + LOCAL_INVISIBLE;
505 
506         /**
507          * The name of the package that owns this directory. Contacts Provider
508          * fill it in with the name of the package containing the directory provider.
509          * If the package is later uninstalled, the directories it owns are
510          * automatically removed from this table.
511          *
512          * <p>TYPE: TEXT</p>
513          */
514         public static final String PACKAGE_NAME = "packageName";
515 
516         /**
517          * The type of directory captured as a resource ID in the context of the
518          * package {@link #PACKAGE_NAME}, e.g. "Corporate Directory"
519          *
520          * <p>TYPE: INTEGER</p>
521          */
522         public static final String TYPE_RESOURCE_ID = "typeResourceId";
523 
524         /**
525          * An optional name that can be used in the UI to represent this directory,
526          * e.g. "Acme Corp"
527          * <p>TYPE: text</p>
528          */
529         public static final String DISPLAY_NAME = "displayName";
530 
531         /**
532          * <p>
533          * The authority of the Directory Provider. Contacts Provider will
534          * use this authority to forward requests to the directory provider.
535          * A directory provider can leave this column empty - Contacts Provider will fill it in.
536          * </p>
537          * <p>
538          * Clients of this API should not send requests directly to this authority.
539          * All directory requests must be routed through Contacts Provider.
540          * </p>
541          *
542          * <p>TYPE: text</p>
543          */
544         public static final String DIRECTORY_AUTHORITY = "authority";
545 
546         /**
547          * The account type which this directory is associated.
548          *
549          * <p>TYPE: text</p>
550          */
551         public static final String ACCOUNT_TYPE = "accountType";
552 
553         /**
554          * The account with which this directory is associated. If the account is later
555          * removed, the directories it owns are automatically removed from this table.
556          *
557          * <p>TYPE: text</p>
558          */
559         public static final String ACCOUNT_NAME = "accountName";
560 
561         /**
562          * Mimimal ID for managed profile directory returned from
563          * {@link Directory#ENTERPRISE_CONTENT_URI}.
564          *
565          * @hide
566          */
567         // slightly smaller than 2 ** 30
568         public static final long ENTERPRISE_DIRECTORY_ID_BASE = 1000000000;
569 
570         /**
571          * One of {@link #EXPORT_SUPPORT_NONE}, {@link #EXPORT_SUPPORT_ANY_ACCOUNT},
572          * {@link #EXPORT_SUPPORT_SAME_ACCOUNT_ONLY}. This is the expectation the
573          * directory has for data exported from it.  Clients must obey this setting.
574          */
575         public static final String EXPORT_SUPPORT = "exportSupport";
576 
577         /**
578          * An {@link #EXPORT_SUPPORT} setting that indicates that the directory
579          * does not allow any data to be copied out of it.
580          */
581         public static final int EXPORT_SUPPORT_NONE = 0;
582 
583         /**
584          * An {@link #EXPORT_SUPPORT} setting that indicates that the directory
585          * allow its data copied only to the account specified by
586          * {@link #ACCOUNT_TYPE}/{@link #ACCOUNT_NAME}.
587          */
588         public static final int EXPORT_SUPPORT_SAME_ACCOUNT_ONLY = 1;
589 
590         /**
591          * An {@link #EXPORT_SUPPORT} setting that indicates that the directory
592          * allow its data copied to any contacts account.
593          */
594         public static final int EXPORT_SUPPORT_ANY_ACCOUNT = 2;
595 
596         /**
597          * One of {@link #SHORTCUT_SUPPORT_NONE}, {@link #SHORTCUT_SUPPORT_DATA_ITEMS_ONLY},
598          * {@link #SHORTCUT_SUPPORT_FULL}. This is the expectation the directory
599          * has for shortcuts created for its elements. Clients must obey this setting.
600          */
601         public static final String SHORTCUT_SUPPORT = "shortcutSupport";
602 
603         /**
604          * An {@link #SHORTCUT_SUPPORT} setting that indicates that the directory
605          * does not allow any shortcuts created for its contacts.
606          */
607         public static final int SHORTCUT_SUPPORT_NONE = 0;
608 
609         /**
610          * An {@link #SHORTCUT_SUPPORT} setting that indicates that the directory
611          * allow creation of shortcuts for data items like email, phone or postal address,
612          * but not the entire contact.
613          */
614         public static final int SHORTCUT_SUPPORT_DATA_ITEMS_ONLY = 1;
615 
616         /**
617          * An {@link #SHORTCUT_SUPPORT} setting that indicates that the directory
618          * allow creation of shortcuts for contact as well as their constituent elements.
619          */
620         public static final int SHORTCUT_SUPPORT_FULL = 2;
621 
622         /**
623          * One of {@link #PHOTO_SUPPORT_NONE}, {@link #PHOTO_SUPPORT_THUMBNAIL_ONLY},
624          * {@link #PHOTO_SUPPORT_FULL}. This is a feature flag indicating the extent
625          * to which the directory supports contact photos.
626          */
627         public static final String PHOTO_SUPPORT = "photoSupport";
628 
629         /**
630          * An {@link #PHOTO_SUPPORT} setting that indicates that the directory
631          * does not provide any photos.
632          */
633         public static final int PHOTO_SUPPORT_NONE = 0;
634 
635         /**
636          * An {@link #PHOTO_SUPPORT} setting that indicates that the directory
637          * can only produce small size thumbnails of contact photos.
638          */
639         public static final int PHOTO_SUPPORT_THUMBNAIL_ONLY = 1;
640 
641         /**
642          * An {@link #PHOTO_SUPPORT} setting that indicates that the directory
643          * has full-size contact photos, but cannot provide scaled thumbnails.
644          */
645         public static final int PHOTO_SUPPORT_FULL_SIZE_ONLY = 2;
646 
647         /**
648          * An {@link #PHOTO_SUPPORT} setting that indicates that the directory
649          * can produce thumbnails as well as full-size contact photos.
650          */
651         public static final int PHOTO_SUPPORT_FULL = 3;
652 
653         /**
654          * Return TRUE if it is a remote stored directory.
655          */
isRemoteDirectoryId(long directoryId)656         public static boolean isRemoteDirectoryId(long directoryId) {
657             return directoryId != Directory.DEFAULT
658                     && directoryId != Directory.LOCAL_INVISIBLE
659                     && directoryId != Directory.ENTERPRISE_DEFAULT
660                     && directoryId != Directory.ENTERPRISE_LOCAL_INVISIBLE;
661         }
662 
663         /**
664          * Return TRUE if it is a remote stored directory. TODO: Remove this method once all
665          * internal apps are not using this API.
666          *
667          * @hide
668          */
isRemoteDirectory(long directoryId)669         public static boolean isRemoteDirectory(long directoryId) {
670             return isRemoteDirectoryId(directoryId);
671         }
672 
673         /**
674          * Return TRUE if a directory ID is from the contacts provider on the enterprise profile.
675          *
676          */
isEnterpriseDirectoryId(long directoryId)677         public static boolean isEnterpriseDirectoryId(long directoryId) {
678             return directoryId >= ENTERPRISE_DIRECTORY_ID_BASE;
679         }
680 
681         /**
682          * Notifies the system of a change in the list of directories handled by
683          * a particular directory provider. The Contacts provider will turn around
684          * and send a query to the directory provider for the full list of directories,
685          * which will replace the previous list.
686          */
notifyDirectoryChange(ContentResolver resolver)687         public static void notifyDirectoryChange(ContentResolver resolver) {
688             // This is done to trigger a query by Contacts Provider back to the directory provider.
689             // No data needs to be sent back, because the provider can infer the calling
690             // package from binder.
691             ContentValues contentValues = new ContentValues();
692             resolver.update(Directory.CONTENT_URI, contentValues, null, null);
693         }
694 
695         /**
696          * A query parameter that's passed to directory providers which indicates the client
697          * package name that has made the query requests.
698          */
699         public static final String CALLER_PACKAGE_PARAM_KEY = "callerPackage";
700     }
701 
702     /**
703      * @hide should be removed when users are updated to refer to SyncState
704      * @deprecated use SyncState instead
705      */
706     @Deprecated
707     public interface SyncStateColumns extends SyncStateContract.Columns {
708     }
709 
710     /**
711      * A table provided for sync adapters to use for storing private sync state data for contacts.
712      *
713      * @see SyncStateContract
714      */
715     public static final class SyncState implements SyncStateContract.Columns {
716         /**
717          * This utility class cannot be instantiated
718          */
SyncState()719         private SyncState() {}
720 
721         public static final String CONTENT_DIRECTORY =
722                 SyncStateContract.Constants.CONTENT_DIRECTORY;
723 
724         /**
725          * The content:// style URI for this table
726          */
727         public static final Uri CONTENT_URI =
728                 Uri.withAppendedPath(AUTHORITY_URI, CONTENT_DIRECTORY);
729 
730         /**
731          * @see android.provider.SyncStateContract.Helpers#get
732          */
get(ContentProviderClient provider, Account account)733         public static byte[] get(ContentProviderClient provider, Account account)
734                 throws RemoteException {
735             return SyncStateContract.Helpers.get(provider, CONTENT_URI, account);
736         }
737 
738         /**
739          * @see android.provider.SyncStateContract.Helpers#get
740          */
getWithUri(ContentProviderClient provider, Account account)741         public static Pair<Uri, byte[]> getWithUri(ContentProviderClient provider, Account account)
742                 throws RemoteException {
743             return SyncStateContract.Helpers.getWithUri(provider, CONTENT_URI, account);
744         }
745 
746         /**
747          * @see android.provider.SyncStateContract.Helpers#set
748          */
set(ContentProviderClient provider, Account account, byte[] data)749         public static void set(ContentProviderClient provider, Account account, byte[] data)
750                 throws RemoteException {
751             SyncStateContract.Helpers.set(provider, CONTENT_URI, account, data);
752         }
753 
754         /**
755          * @see android.provider.SyncStateContract.Helpers#newSetOperation
756          */
newSetOperation(Account account, byte[] data)757         public static ContentProviderOperation newSetOperation(Account account, byte[] data) {
758             return SyncStateContract.Helpers.newSetOperation(CONTENT_URI, account, data);
759         }
760     }
761 
762 
763     /**
764      * A table provided for sync adapters to use for storing private sync state data for the
765      * user's personal profile.
766      *
767      * @see SyncStateContract
768      */
769     public static final class ProfileSyncState implements SyncStateContract.Columns {
770         /**
771          * This utility class cannot be instantiated
772          */
ProfileSyncState()773         private ProfileSyncState() {}
774 
775         public static final String CONTENT_DIRECTORY =
776                 SyncStateContract.Constants.CONTENT_DIRECTORY;
777 
778         /**
779          * The content:// style URI for this table
780          */
781         public static final Uri CONTENT_URI =
782                 Uri.withAppendedPath(Profile.CONTENT_URI, CONTENT_DIRECTORY);
783 
784         /**
785          * @see android.provider.SyncStateContract.Helpers#get
786          */
get(ContentProviderClient provider, Account account)787         public static byte[] get(ContentProviderClient provider, Account account)
788                 throws RemoteException {
789             return SyncStateContract.Helpers.get(provider, CONTENT_URI, account);
790         }
791 
792         /**
793          * @see android.provider.SyncStateContract.Helpers#get
794          */
getWithUri(ContentProviderClient provider, Account account)795         public static Pair<Uri, byte[]> getWithUri(ContentProviderClient provider, Account account)
796                 throws RemoteException {
797             return SyncStateContract.Helpers.getWithUri(provider, CONTENT_URI, account);
798         }
799 
800         /**
801          * @see android.provider.SyncStateContract.Helpers#set
802          */
set(ContentProviderClient provider, Account account, byte[] data)803         public static void set(ContentProviderClient provider, Account account, byte[] data)
804                 throws RemoteException {
805             SyncStateContract.Helpers.set(provider, CONTENT_URI, account, data);
806         }
807 
808         /**
809          * @see android.provider.SyncStateContract.Helpers#newSetOperation
810          */
newSetOperation(Account account, byte[] data)811         public static ContentProviderOperation newSetOperation(Account account, byte[] data) {
812             return SyncStateContract.Helpers.newSetOperation(CONTENT_URI, account, data);
813         }
814     }
815 
816     /**
817      * Generic columns for use by sync adapters. The specific functions of
818      * these columns are private to the sync adapter. Other clients of the API
819      * should not attempt to either read or write this column.
820      *
821      * @see RawContacts
822      * @see Groups
823      */
824     protected interface BaseSyncColumns {
825 
826         /** Generic column for use by sync adapters. */
827         public static final String SYNC1 = "sync1";
828         /** Generic column for use by sync adapters. */
829         public static final String SYNC2 = "sync2";
830         /** Generic column for use by sync adapters. */
831         public static final String SYNC3 = "sync3";
832         /** Generic column for use by sync adapters. */
833         public static final String SYNC4 = "sync4";
834     }
835 
836     /**
837      * Columns that appear when each row of a table belongs to a specific
838      * account, including sync information that an account may need.
839      *
840      * @see RawContacts
841      * @see Groups
842      */
843     protected interface SyncColumns extends BaseSyncColumns {
844         /**
845          * The name of the account instance to which this row belongs, which when paired with
846          * {@link #ACCOUNT_TYPE} identifies a specific account.
847          * <P>Type: TEXT</P>
848          */
849         public static final String ACCOUNT_NAME = "account_name";
850 
851         /**
852          * The type of account to which this row belongs, which when paired with
853          * {@link #ACCOUNT_NAME} identifies a specific account.
854          * <P>Type: TEXT</P>
855          */
856         public static final String ACCOUNT_TYPE = "account_type";
857 
858         /**
859          * String that uniquely identifies this row to its source account.
860          * <P>Type: TEXT</P>
861          */
862         public static final String SOURCE_ID = "sourceid";
863 
864         /**
865          * Version number that is updated whenever this row or its related data
866          * changes.
867          * <P>Type: INTEGER</P>
868          */
869         public static final String VERSION = "version";
870 
871         /**
872          * Flag indicating that {@link #VERSION} has changed, and this row needs
873          * to be synchronized by its owning account.
874          * <P>Type: INTEGER (boolean)</P>
875          */
876         public static final String DIRTY = "dirty";
877     }
878 
879     /**
880      * Columns of {@link ContactsContract.Contacts} that track the user's
881      * preferences for, or interactions with, the contact.
882      *
883      * @see Contacts
884      * @see RawContacts
885      * @see ContactsContract.Data
886      * @see PhoneLookup
887      * @see ContactsContract.Contacts.AggregationSuggestions
888      */
889     protected interface ContactOptionsColumns {
890         /**
891          * The number of times a contact has been contacted.
892          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
893          * this field is obsolete, regardless of Android version. For more information, see the
894          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
895          * page.</p>
896          * <P>Type: INTEGER</P>
897          *
898          * @deprecated Contacts affinity information is no longer supported as of
899          * Android version {@link android.os.Build.VERSION_CODES#Q}. This column
900          * always contains 0.
901          */
902         @Deprecated
903         public static final String TIMES_CONTACTED = "times_contacted";
904 
905         /**
906          * The last time a contact was contacted.
907          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
908          * this field is obsolete, regardless of Android version. For more information, see the
909          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
910          * page.</p>
911          * <P>Type: INTEGER</P>
912          *
913          * @deprecated Contacts affinity information is no longer supported as of
914          * Android version {@link android.os.Build.VERSION_CODES#Q}. This column
915          * always contains 0.
916          */
917         @Deprecated
918         public static final String LAST_TIME_CONTACTED = "last_time_contacted";
919 
920         /** @hide Raw value. */
921         public static final String RAW_TIMES_CONTACTED = HIDDEN_COLUMN_PREFIX + TIMES_CONTACTED;
922 
923         /** @hide Raw value. */
924         public static final String RAW_LAST_TIME_CONTACTED =
925                 HIDDEN_COLUMN_PREFIX + LAST_TIME_CONTACTED;
926 
927         /**
928          * @hide
929          * Low res version.  Same as {@link #TIMES_CONTACTED} but use it in CP2 for clarification.
930          */
931         public static final String LR_TIMES_CONTACTED = TIMES_CONTACTED;
932 
933         /**
934          * @hide
935          * Low res version.  Same as {@link #TIMES_CONTACTED} but use it in CP2 for clarification.
936          */
937         public static final String LR_LAST_TIME_CONTACTED = LAST_TIME_CONTACTED;
938 
939         /**
940          * Is the contact starred?
941          * <P>Type: INTEGER (boolean)</P>
942          */
943         public static final String STARRED = "starred";
944 
945         /**
946          * The position at which the contact is pinned. If {@link PinnedPositions#UNPINNED},
947          * the contact is not pinned. Also see {@link PinnedPositions}.
948          * <P>Type: INTEGER </P>
949          */
950         public static final String PINNED = "pinned";
951 
952         /**
953          * URI for a custom ringtone associated with the contact. If null or missing,
954          * the default ringtone is used.
955          * <P>Type: TEXT (URI to the ringtone)</P>
956          */
957         public static final String CUSTOM_RINGTONE = "custom_ringtone";
958 
959         /**
960          * Whether the contact should always be sent to voicemail. If missing,
961          * defaults to false.
962          * <P>Type: INTEGER (0 for false, 1 for true)</P>
963          */
964         public static final String SEND_TO_VOICEMAIL = "send_to_voicemail";
965     }
966 
967     /**
968      * Columns of {@link ContactsContract.Contacts} that refer to intrinsic
969      * properties of the contact, as opposed to the user-specified options
970      * found in {@link ContactOptionsColumns}.
971      *
972      * @see Contacts
973      * @see ContactsContract.Data
974      * @see PhoneLookup
975      * @see ContactsContract.Contacts.AggregationSuggestions
976      */
977     protected interface ContactsColumns {
978         /**
979          * The display name for the contact.
980          * <P>Type: TEXT</P>
981          */
982         public static final String DISPLAY_NAME = ContactNameColumns.DISPLAY_NAME_PRIMARY;
983 
984         /**
985          * Reference to the row in the RawContacts table holding the contact name.
986          * <P>Type: INTEGER REFERENCES raw_contacts(_id)</P>
987          */
988         public static final String NAME_RAW_CONTACT_ID = "name_raw_contact_id";
989 
990         /**
991          * Reference to the row in the data table holding the photo.  A photo can
992          * be referred to either by ID (this field) or by URI (see {@link #PHOTO_THUMBNAIL_URI}
993          * and {@link #PHOTO_URI}).
994          * If PHOTO_ID is null, consult {@link #PHOTO_URI} or {@link #PHOTO_THUMBNAIL_URI},
995          * which is a more generic mechanism for referencing the contact photo, especially for
996          * contacts returned by non-local directories (see {@link Directory}).
997          *
998          * <P>Type: INTEGER REFERENCES data(_id)</P>
999          */
1000         public static final String PHOTO_ID = "photo_id";
1001 
1002         /**
1003          * Photo file ID of the full-size photo.  If present, this will be used to populate
1004          * {@link #PHOTO_URI}.  The ID can also be used with
1005          * {@link ContactsContract.DisplayPhoto#CONTENT_URI} to create a URI to the photo.
1006          * If this is present, {@link #PHOTO_ID} is also guaranteed to be populated.
1007          *
1008          * <P>Type: INTEGER</P>
1009          */
1010         public static final String PHOTO_FILE_ID = "photo_file_id";
1011 
1012         /**
1013          * A URI that can be used to retrieve the contact's full-size photo.
1014          * If PHOTO_FILE_ID is not null, this will be populated with a URI based off
1015          * {@link ContactsContract.DisplayPhoto#CONTENT_URI}.  Otherwise, this will
1016          * be populated with the same value as {@link #PHOTO_THUMBNAIL_URI}.
1017          * A photo can be referred to either by a URI (this field) or by ID
1018          * (see {@link #PHOTO_ID}). If either PHOTO_FILE_ID or PHOTO_ID is not null,
1019          * PHOTO_URI and PHOTO_THUMBNAIL_URI shall not be null (but not necessarily
1020          * vice versa).  Thus using PHOTO_URI is a more robust method of retrieving
1021          * contact photos.
1022          *
1023          * <P>Type: TEXT</P>
1024          */
1025         public static final String PHOTO_URI = "photo_uri";
1026 
1027         /**
1028          * A URI that can be used to retrieve a thumbnail of the contact's photo.
1029          * A photo can be referred to either by a URI (this field or {@link #PHOTO_URI})
1030          * or by ID (see {@link #PHOTO_ID}). If PHOTO_ID is not null, PHOTO_URI and
1031          * PHOTO_THUMBNAIL_URI shall not be null (but not necessarily vice versa).
1032          * If the content provider does not differentiate between full-size photos
1033          * and thumbnail photos, PHOTO_THUMBNAIL_URI and {@link #PHOTO_URI} can contain
1034          * the same value, but either both shall be null or both not null.
1035          *
1036          * <P>Type: TEXT</P>
1037          */
1038         public static final String PHOTO_THUMBNAIL_URI = "photo_thumb_uri";
1039 
1040         /**
1041          * Flag that reflects whether the contact exists inside the default directory.
1042          * Ie, whether the contact is designed to only be visible outside search.
1043          */
1044         public static final String IN_DEFAULT_DIRECTORY = "in_default_directory";
1045 
1046         /**
1047          * Flag that reflects the {@link Groups#GROUP_VISIBLE} state of any
1048          * {@link CommonDataKinds.GroupMembership} for this contact.
1049          */
1050         public static final String IN_VISIBLE_GROUP = "in_visible_group";
1051 
1052         /**
1053          * Flag that reflects whether this contact represents the user's
1054          * personal profile entry.
1055          */
1056         public static final String IS_USER_PROFILE = "is_user_profile";
1057 
1058         /**
1059          * An indicator of whether this contact has at least one phone number. "1" if there is
1060          * at least one phone number, "0" otherwise.
1061          * <P>Type: INTEGER</P>
1062          */
1063         public static final String HAS_PHONE_NUMBER = "has_phone_number";
1064 
1065         /**
1066          * An opaque value that contains hints on how to find the contact if
1067          * its row id changed as a result of a sync or aggregation.
1068          */
1069         public static final String LOOKUP_KEY = "lookup";
1070 
1071         /**
1072          * Timestamp (milliseconds since epoch) of when this contact was last updated.  This
1073          * includes updates to all data associated with this contact including raw contacts.  Any
1074          * modification (including deletes and inserts) of underlying contact data are also
1075          * reflected in this timestamp.
1076          */
1077         public static final String CONTACT_LAST_UPDATED_TIMESTAMP =
1078                 "contact_last_updated_timestamp";
1079     }
1080 
1081     /**
1082      * @see Contacts
1083      */
1084     protected interface ContactStatusColumns {
1085         /**
1086          * Contact presence status. See {@link StatusUpdates} for individual status
1087          * definitions.
1088          * <p>Type: NUMBER</p>
1089          */
1090         public static final String CONTACT_PRESENCE = "contact_presence";
1091 
1092         /**
1093          * Contact Chat Capabilities. See {@link StatusUpdates} for individual
1094          * definitions.
1095          * <p>Type: NUMBER</p>
1096          */
1097         public static final String CONTACT_CHAT_CAPABILITY = "contact_chat_capability";
1098 
1099         /**
1100          * Contact's latest status update.
1101          * <p>Type: TEXT</p>
1102          */
1103         public static final String CONTACT_STATUS = "contact_status";
1104 
1105         /**
1106          * The absolute time in milliseconds when the latest status was
1107          * inserted/updated.
1108          * <p>Type: NUMBER</p>
1109          */
1110         public static final String CONTACT_STATUS_TIMESTAMP = "contact_status_ts";
1111 
1112         /**
1113          * The package containing resources for this status: label and icon.
1114          * <p>Type: TEXT</p>
1115          */
1116         public static final String CONTACT_STATUS_RES_PACKAGE = "contact_status_res_package";
1117 
1118         /**
1119          * The resource ID of the label describing the source of contact
1120          * status, e.g. "Google Talk". This resource is scoped by the
1121          * {@link #CONTACT_STATUS_RES_PACKAGE}.
1122          * <p>Type: NUMBER</p>
1123          */
1124         public static final String CONTACT_STATUS_LABEL = "contact_status_label";
1125 
1126         /**
1127          * The resource ID of the icon for the source of contact status. This
1128          * resource is scoped by the {@link #CONTACT_STATUS_RES_PACKAGE}.
1129          * <p>Type: NUMBER</p>
1130          */
1131         public static final String CONTACT_STATUS_ICON = "contact_status_icon";
1132     }
1133 
1134     /**
1135      * Constants for various styles of combining given name, family name etc into
1136      * a full name.  For example, the western tradition follows the pattern
1137      * 'given name' 'middle name' 'family name' with the alternative pattern being
1138      * 'family name', 'given name' 'middle name'.  The CJK tradition is
1139      * 'family name' 'middle name' 'given name', with Japanese favoring a space between
1140      * the names and Chinese omitting the space.
1141      */
1142     public interface FullNameStyle {
1143         public static final int UNDEFINED = 0;
1144         public static final int WESTERN = 1;
1145 
1146         /**
1147          * Used if the name is written in Hanzi/Kanji/Hanja and we could not determine
1148          * which specific language it belongs to: Chinese, Japanese or Korean.
1149          */
1150         public static final int CJK = 2;
1151 
1152         public static final int CHINESE = 3;
1153         public static final int JAPANESE = 4;
1154         public static final int KOREAN = 5;
1155     }
1156 
1157     /**
1158      * Constants for various styles of capturing the pronunciation of a person's name.
1159      */
1160     public interface PhoneticNameStyle {
1161         public static final int UNDEFINED = 0;
1162 
1163         /**
1164          * Pinyin is a phonetic method of entering Chinese characters. Typically not explicitly
1165          * shown in UIs, but used for searches and sorting.
1166          */
1167         public static final int PINYIN = 3;
1168 
1169         /**
1170          * Hiragana and Katakana are two common styles of writing out the pronunciation
1171          * of a Japanese names.
1172          */
1173         public static final int JAPANESE = 4;
1174 
1175         /**
1176          * Hangul is the Korean phonetic alphabet.
1177          */
1178         public static final int KOREAN = 5;
1179     }
1180 
1181     /**
1182      * Types of data used to produce the display name for a contact. In the order
1183      * of increasing priority: {@link #EMAIL}, {@link #PHONE},
1184      * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_PHONETIC_NAME},
1185      * {@link #STRUCTURED_NAME}.
1186      */
1187     public interface DisplayNameSources {
1188         public static final int UNDEFINED = 0;
1189         public static final int EMAIL = 10;
1190         public static final int PHONE = 20;
1191         public static final int ORGANIZATION = 30;
1192         public static final int NICKNAME = 35;
1193         /** Display name comes from a structured name that only has phonetic components. */
1194         public static final int STRUCTURED_PHONETIC_NAME = 37;
1195         public static final int STRUCTURED_NAME = 40;
1196     }
1197 
1198     /**
1199      * Contact name and contact name metadata columns in the RawContacts table.
1200      *
1201      * @see Contacts
1202      * @see RawContacts
1203      */
1204     protected interface ContactNameColumns {
1205 
1206         /**
1207          * The kind of data that is used as the display name for the contact, such as
1208          * structured name or email address.  See {@link DisplayNameSources}.
1209          */
1210         public static final String DISPLAY_NAME_SOURCE = "display_name_source";
1211 
1212         /**
1213          * <p>
1214          * The standard text shown as the contact's display name, based on the best
1215          * available information for the contact (for example, it might be the email address
1216          * if the name is not available).
1217          * The information actually used to compute the name is stored in
1218          * {@link #DISPLAY_NAME_SOURCE}.
1219          * </p>
1220          * <p>
1221          * A contacts provider is free to choose whatever representation makes most
1222          * sense for its target market.
1223          * For example in the default Android Open Source Project implementation,
1224          * if the display name is
1225          * based on the structured name and the structured name follows
1226          * the Western full-name style, then this field contains the "given name first"
1227          * version of the full name.
1228          * <p>
1229          *
1230          * @see ContactsContract.ContactNameColumns#DISPLAY_NAME_ALTERNATIVE
1231          */
1232         public static final String DISPLAY_NAME_PRIMARY = "display_name";
1233 
1234         /**
1235          * <p>
1236          * An alternative representation of the display name, such as "family name first"
1237          * instead of "given name first" for Western names.  If an alternative is not
1238          * available, the values should be the same as {@link #DISPLAY_NAME_PRIMARY}.
1239          * </p>
1240          * <p>
1241          * A contacts provider is free to provide alternatives as necessary for
1242          * its target market.
1243          * For example the default Android Open Source Project contacts provider
1244          * currently provides an
1245          * alternative in a single case:  if the display name is
1246          * based on the structured name and the structured name follows
1247          * the Western full name style, then the field contains the "family name first"
1248          * version of the full name.
1249          * Other cases may be added later.
1250          * </p>
1251          */
1252         public static final String DISPLAY_NAME_ALTERNATIVE = "display_name_alt";
1253 
1254         /**
1255          * The phonetic alphabet used to represent the {@link #PHONETIC_NAME}.  See
1256          * {@link PhoneticNameStyle}.
1257          */
1258         public static final String PHONETIC_NAME_STYLE = "phonetic_name_style";
1259 
1260         /**
1261          * <p>
1262          * Pronunciation of the full name in the phonetic alphabet specified by
1263          * {@link #PHONETIC_NAME_STYLE}.
1264          * </p>
1265          * <p>
1266          * The value may be set manually by the user. This capability is of
1267          * interest only in countries with commonly used phonetic alphabets,
1268          * such as Japan and Korea. See {@link PhoneticNameStyle}.
1269          * </p>
1270          */
1271         public static final String PHONETIC_NAME = "phonetic_name";
1272 
1273         /**
1274          * Sort key that takes into account locale-based traditions for sorting
1275          * names in address books.  The default
1276          * sort key is {@link #DISPLAY_NAME_PRIMARY}.  For Chinese names
1277          * the sort key is the name's Pinyin spelling, and for Japanese names
1278          * it is the Hiragana version of the phonetic name.
1279          */
1280         public static final String SORT_KEY_PRIMARY = "sort_key";
1281 
1282         /**
1283          * Sort key based on the alternative representation of the full name,
1284          * {@link #DISPLAY_NAME_ALTERNATIVE}.  Thus for Western names,
1285          * it is the one using the "family name first" format.
1286          */
1287         public static final String SORT_KEY_ALTERNATIVE = "sort_key_alt";
1288     }
1289 
1290     interface ContactCounts {
1291 
1292         /**
1293          * Add this query parameter to a URI to get back row counts grouped by the address book
1294          * index as cursor extras. For most languages it is the first letter of the sort key. This
1295          * parameter does not affect the main content of the cursor.
1296          *
1297          * <p>
1298          * <pre>
1299          * Example:
1300          *
1301          * import android.provider.ContactsContract.Contacts;
1302          *
1303          * Uri uri = Contacts.CONTENT_URI.buildUpon()
1304          *          .appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true")
1305          *          .build();
1306          * Cursor cursor = getContentResolver().query(uri,
1307          *          new String[] {Contacts.DISPLAY_NAME},
1308          *          null, null, null);
1309          * Bundle bundle = cursor.getExtras();
1310          * if (bundle.containsKey(Contacts.EXTRA_ADDRESS_BOOK_INDEX_TITLES) &&
1311          *         bundle.containsKey(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS)) {
1312          *     String sections[] =
1313          *             bundle.getStringArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_TITLES);
1314          *     int counts[] = bundle.getIntArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS);
1315          * }
1316          * </pre>
1317          * </p>
1318          */
1319         public static final String EXTRA_ADDRESS_BOOK_INDEX =
1320                 "android.provider.extra.ADDRESS_BOOK_INDEX";
1321 
1322         /**
1323          * The array of address book index titles, which are returned in the
1324          * same order as the data in the cursor.
1325          * <p>TYPE: String[]</p>
1326          */
1327         public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES =
1328                 "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
1329 
1330         /**
1331          * The array of group counts for the corresponding group.  Contains the same number
1332          * of elements as the EXTRA_ADDRESS_BOOK_INDEX_TITLES array.
1333          * <p>TYPE: int[]</p>
1334          */
1335         public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS =
1336                 "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
1337     }
1338 
1339     /**
1340      * Constants for the contacts table, which contains a record per aggregate
1341      * of raw contacts representing the same person.
1342      * <h3>Operations</h3>
1343      * <dl>
1344      * <dt><b>Insert</b></dt>
1345      * <dd>A Contact cannot be created explicitly. When a raw contact is
1346      * inserted, the provider will first try to find a Contact representing the
1347      * same person. If one is found, the raw contact's
1348      * {@link RawContacts#CONTACT_ID} column gets the _ID of the aggregate
1349      * Contact. If no match is found, the provider automatically inserts a new
1350      * Contact and puts its _ID into the {@link RawContacts#CONTACT_ID} column
1351      * of the newly inserted raw contact.</dd>
1352      * <dt><b>Update</b></dt>
1353      * <dd>Only certain columns of Contact are modifiable:
1354      * {@link #STARRED}, {@link #CUSTOM_RINGTONE}, {@link #SEND_TO_VOICEMAIL}. Changing any of
1355      * these columns on the Contact also changes them on all constituent raw
1356      * contacts.</dd>
1357      * <dt><b>Delete</b></dt>
1358      * <dd>Be careful with deleting Contacts! Deleting an aggregate contact
1359      * deletes all constituent raw contacts. The corresponding sync adapters
1360      * will notice the deletions of their respective raw contacts and remove
1361      * them from their back end storage.</dd>
1362      * <dt><b>Query</b></dt>
1363      * <dd>
1364      * <ul>
1365      * <li>If you need to read an individual contact, consider using
1366      * {@link #CONTENT_LOOKUP_URI} instead of {@link #CONTENT_URI}.</li>
1367      * <li>If you need to look up a contact by the phone number, use
1368      * {@link PhoneLookup#CONTENT_FILTER_URI PhoneLookup.CONTENT_FILTER_URI},
1369      * which is optimized for this purpose.</li>
1370      * <li>If you need to look up a contact by partial name, e.g. to produce
1371      * filter-as-you-type suggestions, use the {@link #CONTENT_FILTER_URI} URI.
1372      * <li>If you need to look up a contact by some data element like email
1373      * address, nickname, etc, use a query against the {@link ContactsContract.Data} table.
1374      * The result will contain contact ID, name etc.
1375      * </ul>
1376      * </dd>
1377      * </dl>
1378      * <h2>Columns</h2>
1379      * <table class="jd-sumtable">
1380      * <tr>
1381      * <th colspan='4'>Contacts</th>
1382      * </tr>
1383      * <tr>
1384      * <td>long</td>
1385      * <td>{@link #_ID}</td>
1386      * <td>read-only</td>
1387      * <td>Row ID. Consider using {@link #LOOKUP_KEY} instead.</td>
1388      * </tr>
1389      * <tr>
1390      * <td>String</td>
1391      * <td>{@link #LOOKUP_KEY}</td>
1392      * <td>read-only</td>
1393      * <td>An opaque value that contains hints on how to find the contact if its
1394      * row id changed as a result of a sync or aggregation.</td>
1395      * </tr>
1396      * <tr>
1397      * <td>long</td>
1398      * <td>NAME_RAW_CONTACT_ID</td>
1399      * <td>read-only</td>
1400      * <td>The ID of the raw contact that contributes the display name
1401      * to the aggregate contact. During aggregation one of the constituent
1402      * raw contacts is chosen using a heuristic: a longer name or a name
1403      * with more diacritic marks or more upper case characters is chosen.</td>
1404      * </tr>
1405      * <tr>
1406      * <td>String</td>
1407      * <td>DISPLAY_NAME_PRIMARY</td>
1408      * <td>read-only</td>
1409      * <td>The display name for the contact. It is the display name
1410      * contributed by the raw contact referred to by the NAME_RAW_CONTACT_ID
1411      * column.</td>
1412      * </tr>
1413      * <tr>
1414      * <td>long</td>
1415      * <td>{@link #PHOTO_ID}</td>
1416      * <td>read-only</td>
1417      * <td>Reference to the row in the {@link ContactsContract.Data} table holding the photo.
1418      * That row has the mime type
1419      * {@link CommonDataKinds.Photo#CONTENT_ITEM_TYPE}. The value of this field
1420      * is computed automatically based on the
1421      * {@link CommonDataKinds.Photo#IS_SUPER_PRIMARY} field of the data rows of
1422      * that mime type.</td>
1423      * </tr>
1424      * <tr>
1425      * <td>long</td>
1426      * <td>{@link #PHOTO_URI}</td>
1427      * <td>read-only</td>
1428      * <td>A URI that can be used to retrieve the contact's full-size photo. This
1429      * column is the preferred method of retrieving the contact photo.</td>
1430      * </tr>
1431      * <tr>
1432      * <td>long</td>
1433      * <td>{@link #PHOTO_THUMBNAIL_URI}</td>
1434      * <td>read-only</td>
1435      * <td>A URI that can be used to retrieve the thumbnail of contact's photo.  This
1436      * column is the preferred method of retrieving the contact photo.</td>
1437      * </tr>
1438      * <tr>
1439      * <td>int</td>
1440      * <td>{@link #IN_VISIBLE_GROUP}</td>
1441      * <td>read-only</td>
1442      * <td>An indicator of whether this contact is supposed to be visible in the
1443      * UI. "1" if the contact has at least one raw contact that belongs to a
1444      * visible group; "0" otherwise.</td>
1445      * </tr>
1446      * <tr>
1447      * <td>int</td>
1448      * <td>{@link #HAS_PHONE_NUMBER}</td>
1449      * <td>read-only</td>
1450      * <td>An indicator of whether this contact has at least one phone number.
1451      * "1" if there is at least one phone number, "0" otherwise.</td>
1452      * </tr>
1453      * <tr>
1454      * <td>int</td>
1455      * <td>{@link #STARRED}</td>
1456      * <td>read/write</td>
1457      * <td>An indicator for favorite contacts: '1' if favorite, '0' otherwise.
1458      * When raw contacts are aggregated, this field is automatically computed:
1459      * if any constituent raw contacts are starred, then this field is set to
1460      * '1'. Setting this field automatically changes the corresponding field on
1461      * all constituent raw contacts.</td>
1462      * </tr>
1463      * <tr>
1464      * <td>String</td>
1465      * <td>{@link #CUSTOM_RINGTONE}</td>
1466      * <td>read/write</td>
1467      * <td>A custom ringtone associated with a contact. Typically this is the
1468      * URI returned by an activity launched with the
1469      * {@link android.media.RingtoneManager#ACTION_RINGTONE_PICKER} intent.</td>
1470      * </tr>
1471      * <tr>
1472      * <td>int</td>
1473      * <td>{@link #SEND_TO_VOICEMAIL}</td>
1474      * <td>read/write</td>
1475      * <td>An indicator of whether calls from this contact should be forwarded
1476      * directly to voice mail ('1') or not ('0'). When raw contacts are
1477      * aggregated, this field is automatically computed: if <i>all</i>
1478      * constituent raw contacts have SEND_TO_VOICEMAIL=1, then this field is set
1479      * to '1'. Setting this field automatically changes the corresponding field
1480      * on all constituent raw contacts.</td>
1481      * </tr>
1482      * <tr>
1483      * <td>int</td>
1484      * <td>{@link #CONTACT_PRESENCE}</td>
1485      * <td>read-only</td>
1486      * <td>Contact IM presence status. See {@link StatusUpdates} for individual
1487      * status definitions. Automatically computed as the highest presence of all
1488      * constituent raw contacts. The provider may choose not to store this value
1489      * in persistent storage. The expectation is that presence status will be
1490      * updated on a regular basis.</td>
1491      * </tr>
1492      * <tr>
1493      * <td>String</td>
1494      * <td>{@link #CONTACT_STATUS}</td>
1495      * <td>read-only</td>
1496      * <td>Contact's latest status update. Automatically computed as the latest
1497      * of all constituent raw contacts' status updates.</td>
1498      * </tr>
1499      * <tr>
1500      * <td>long</td>
1501      * <td>{@link #CONTACT_STATUS_TIMESTAMP}</td>
1502      * <td>read-only</td>
1503      * <td>The absolute time in milliseconds when the latest status was
1504      * inserted/updated.</td>
1505      * </tr>
1506      * <tr>
1507      * <td>String</td>
1508      * <td>{@link #CONTACT_STATUS_RES_PACKAGE}</td>
1509      * <td>read-only</td>
1510      * <td> The package containing resources for this status: label and icon.</td>
1511      * </tr>
1512      * <tr>
1513      * <td>long</td>
1514      * <td>{@link #CONTACT_STATUS_LABEL}</td>
1515      * <td>read-only</td>
1516      * <td>The resource ID of the label describing the source of contact status,
1517      * e.g. "Google Talk". This resource is scoped by the
1518      * {@link #CONTACT_STATUS_RES_PACKAGE}.</td>
1519      * </tr>
1520      * <tr>
1521      * <td>long</td>
1522      * <td>{@link #CONTACT_STATUS_ICON}</td>
1523      * <td>read-only</td>
1524      * <td>The resource ID of the icon for the source of contact status. This
1525      * resource is scoped by the {@link #CONTACT_STATUS_RES_PACKAGE}.</td>
1526      * </tr>
1527      * </table>
1528      */
1529     public static class Contacts implements BaseColumns, ContactsColumns,
1530             ContactOptionsColumns, ContactNameColumns, ContactStatusColumns, ContactCounts {
1531         /**
1532          * This utility class cannot be instantiated
1533          */
Contacts()1534         private Contacts()  {}
1535 
1536         /**
1537          * The content:// style URI for this table
1538          */
1539         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "contacts");
1540 
1541         /**
1542          * URI used for getting all contacts from both the calling user and the managed profile
1543          * that is linked to it.
1544          * <p>
1545          * It supports the same semantics as {@link #CONTENT_URI} and returns the same columns.<br>
1546          * If the calling user has no managed profile, it behaves in the exact same way as
1547          * {@link #CONTENT_URI}.<br>
1548          * If there is a managed profile linked to the calling user, it will return merged results
1549          * from both.
1550          * <p>
1551          * Note: this query returns the calling user results before the managed profile results,
1552          * and this order is not affected by the sorting parameter.
1553          * <p>
1554          * If a result is from the managed profile, the following changes are made to the data:
1555          * <ul>
1556          *     <li>{@link #PHOTO_THUMBNAIL_URI} and {@link #PHOTO_URI} will be rewritten to special
1557          *     URIs. Use {@link ContentResolver#openAssetFileDescriptor} or its siblings to
1558          *     load pictures from them.
1559          *     <li>{@link #PHOTO_ID} and {@link #PHOTO_FILE_ID} will be set to null. Don't use them.
1560          *     <li>{@link #_ID} and {@link #LOOKUP_KEY} will be replaced with artificial values.
1561          *     These values will be consistent across multiple queries, but do not use them in
1562          *     places that do not explicitly say they accept them. If they are used in the
1563          *     {@code selection} param in {@link android.content.ContentProvider#query}, the result
1564          *     is undefined.
1565          *     <li>In order to tell whether a contact is from the managed profile, use
1566          *     {@link ContactsContract.Contacts#isEnterpriseContactId(long)}.
1567          */
1568         public static final @NonNull Uri ENTERPRISE_CONTENT_URI = Uri.withAppendedPath(
1569                 CONTENT_URI, "enterprise");
1570 
1571         /**
1572          * Special contacts URI to refer to contacts on the managed profile from the calling user.
1573          * <p>
1574          * It's supported only by a few specific places for referring to contact pictures that
1575          * are in the managed profile provider for enterprise caller-ID. Contact picture URIs
1576          * returned from {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI} and similar APIs may
1577          * contain this kind of URI.
1578          *
1579          * @hide
1580          */
1581         @UnsupportedAppUsage
1582         public static final Uri CORP_CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
1583                 "contacts_corp");
1584 
1585         /**
1586          * A content:// style URI for this table that should be used to create
1587          * shortcuts or otherwise create long-term links to contacts. This URI
1588          * should always be followed by a "/" and the contact's {@link #LOOKUP_KEY}.
1589          * It can optionally also have a "/" and last known contact ID appended after
1590          * that. This "complete" format is an important optimization and is highly recommended.
1591          * <p>
1592          * As long as the contact's row ID remains the same, this URI is
1593          * equivalent to {@link #CONTENT_URI}. If the contact's row ID changes
1594          * as a result of a sync or aggregation, this URI will look up the
1595          * contact using indirect information (sync IDs or constituent raw
1596          * contacts).
1597          * <p>
1598          * Lookup key should be appended unencoded - it is stored in the encoded
1599          * form, ready for use in a URI.
1600          */
1601         public static final Uri CONTENT_LOOKUP_URI = Uri.withAppendedPath(CONTENT_URI,
1602                 "lookup");
1603 
1604         /**
1605          * Base {@link Uri} for referencing a single {@link Contacts} entry,
1606          * created by appending {@link #LOOKUP_KEY} using
1607          * {@link Uri#withAppendedPath(Uri, String)}. Provides
1608          * {@link OpenableColumns} columns when queried, or returns the
1609          * referenced contact formatted as a vCard when opened through
1610          * {@link ContentResolver#openAssetFileDescriptor(Uri, String)}.
1611          */
1612         public static final Uri CONTENT_VCARD_URI = Uri.withAppendedPath(CONTENT_URI,
1613                 "as_vcard");
1614 
1615        /**
1616         * Boolean parameter that may be used with {@link #CONTENT_VCARD_URI}
1617         * and {@link #CONTENT_MULTI_VCARD_URI} to indicate that the returned
1618         * vcard should not contain a photo.
1619         *
1620         * This is useful for obtaining a space efficient vcard.
1621         */
1622         public static final String QUERY_PARAMETER_VCARD_NO_PHOTO = "no_photo";
1623 
1624         /**
1625          * Base {@link Uri} for referencing multiple {@link Contacts} entry,
1626          * created by appending {@link #LOOKUP_KEY} using
1627          * {@link Uri#withAppendedPath(Uri, String)}. The lookup keys have to be
1628          * joined with the colon (":") separator, and the resulting string encoded.
1629          *
1630          * Provides {@link OpenableColumns} columns when queried, or returns the
1631          * referenced contact formatted as a vCard when opened through
1632          * {@link ContentResolver#openAssetFileDescriptor(Uri, String)}.
1633          *
1634          * <p>
1635          * Usage example:
1636          * <dl>
1637          * <dt>The following code snippet creates a multi-vcard URI that references all the
1638          * contacts in a user's database.</dt>
1639          * <dd>
1640          *
1641          * <pre>
1642          * public Uri getAllContactsVcardUri() {
1643          *     Cursor cursor = getActivity().getContentResolver().query(Contacts.CONTENT_URI,
1644          *         new String[] {Contacts.LOOKUP_KEY}, null, null, null);
1645          *     if (cursor == null) {
1646          *         return null;
1647          *     }
1648          *     try {
1649          *         StringBuilder uriListBuilder = new StringBuilder();
1650          *         int index = 0;
1651          *         while (cursor.moveToNext()) {
1652          *             if (index != 0) uriListBuilder.append(':');
1653          *             uriListBuilder.append(cursor.getString(0));
1654          *             index++;
1655          *         }
1656          *         return Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI,
1657          *                 Uri.encode(uriListBuilder.toString()));
1658          *     } finally {
1659          *         cursor.close();
1660          *     }
1661          * }
1662          * </pre>
1663          *
1664          * </p>
1665          */
1666         public static final Uri CONTENT_MULTI_VCARD_URI = Uri.withAppendedPath(CONTENT_URI,
1667                 "as_multi_vcard");
1668 
1669         /**
1670          * Builds a {@link #CONTENT_LOOKUP_URI} style {@link Uri} describing the
1671          * requested {@link Contacts} entry.
1672          *
1673          * @param contactUri A {@link #CONTENT_URI} row, or an existing
1674          *            {@link #CONTENT_LOOKUP_URI} to attempt refreshing.
1675          */
getLookupUri(ContentResolver resolver, Uri contactUri)1676         public static Uri getLookupUri(ContentResolver resolver, Uri contactUri) {
1677             final Cursor c = resolver.query(contactUri, new String[] {
1678                     Contacts.LOOKUP_KEY, Contacts._ID
1679             }, null, null, null);
1680             if (c == null) {
1681                 return null;
1682             }
1683 
1684             try {
1685                 if (c.moveToFirst()) {
1686                     final String lookupKey = c.getString(0);
1687                     final long contactId = c.getLong(1);
1688                     return getLookupUri(contactId, lookupKey);
1689                 }
1690             } finally {
1691                 c.close();
1692             }
1693             return null;
1694         }
1695 
1696         /**
1697          * Build a {@link #CONTENT_LOOKUP_URI} lookup {@link Uri} using the
1698          * given {@link ContactsContract.Contacts#_ID} and {@link #LOOKUP_KEY}.
1699          * <p>
1700          * Returns null if unable to construct a valid lookup URI from the
1701          * provided parameters.
1702          */
getLookupUri(long contactId, String lookupKey)1703         public static Uri getLookupUri(long contactId, String lookupKey) {
1704             if (TextUtils.isEmpty(lookupKey)) {
1705                 return null;
1706             }
1707             return ContentUris.withAppendedId(Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI,
1708                     lookupKey), contactId);
1709         }
1710 
1711         /**
1712          * Computes a content URI (see {@link #CONTENT_URI}) given a lookup URI.
1713          * <p>
1714          * Returns null if the contact cannot be found.
1715          */
lookupContact(ContentResolver resolver, Uri lookupUri)1716         public static Uri lookupContact(ContentResolver resolver, Uri lookupUri) {
1717             if (lookupUri == null) {
1718                 return null;
1719             }
1720 
1721             Cursor c = resolver.query(lookupUri, new String[]{Contacts._ID}, null, null, null);
1722             if (c == null) {
1723                 return null;
1724             }
1725 
1726             try {
1727                 if (c.moveToFirst()) {
1728                     long contactId = c.getLong(0);
1729                     return ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
1730                 }
1731             } finally {
1732                 c.close();
1733             }
1734             return null;
1735         }
1736 
1737         /**
1738          * Mark a contact as having been contacted. Updates two fields:
1739          * {@link #TIMES_CONTACTED} and {@link #LAST_TIME_CONTACTED}. The
1740          * TIMES_CONTACTED field is incremented by 1 and the LAST_TIME_CONTACTED
1741          * field is populated with the current system time.
1742          *
1743          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
1744          * this field is obsolete, regardless of Android version. For more information, see the
1745          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
1746          * page.</p>
1747          *
1748          * @param resolver the ContentResolver to use
1749          * @param contactId the person who was contacted
1750          *
1751          * @deprecated Contacts affinity information is no longer supported as of
1752          * Android version {@link android.os.Build.VERSION_CODES#Q}. This method
1753          * is no-op.
1754          */
1755         @Deprecated
markAsContacted(ContentResolver resolver, long contactId)1756         public static void markAsContacted(ContentResolver resolver, long contactId) {
1757         }
1758 
1759         /**
1760          * The content:// style URI used for "type-to-filter" functionality on the
1761          * {@link #CONTENT_URI} URI. The filter string will be used to match
1762          * various parts of the contact name. The filter argument should be passed
1763          * as an additional path segment after this URI.
1764          */
1765         public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(
1766                 CONTENT_URI, "filter");
1767 
1768         /**
1769          * It supports the similar semantics as {@link #CONTENT_FILTER_URI} and returns the same
1770          * columns. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in parameters,
1771          * otherwise it will throw IllegalArgumentException. The passed directory can belong either
1772          * to the calling user or to a managed profile that is linked to it.
1773          */
1774         public static final Uri ENTERPRISE_CONTENT_FILTER_URI = Uri.withAppendedPath(
1775                 CONTENT_URI, "filter_enterprise");
1776 
1777         /**
1778          * The content:// style URI for this table joined with useful data from
1779          * {@link ContactsContract.Data}, filtered to include only starred contacts.
1780          * Frequent contacts are no longer included in the result as of
1781          * Android version {@link android.os.Build.VERSION_CODES#Q}.
1782          *
1783          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
1784          * field doesn't sort results based on contacts frequency. For more information, see the
1785          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
1786          * page.
1787          */
1788         public static final Uri CONTENT_STREQUENT_URI = Uri.withAppendedPath(
1789                 CONTENT_URI, "strequent");
1790 
1791         /**
1792          * The content:// style URI for showing a list of frequently contacted people.
1793          *
1794          * @deprecated Frequent contacts are no longer supported as of
1795          * Android version {@link android.os.Build.VERSION_CODES#Q}.
1796          * This URI always returns an empty cursor.
1797          *
1798          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
1799          * field doesn't sort results based on contacts frequency. For more information, see the
1800          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
1801          * page.
1802          */
1803         @Deprecated
1804         public static final Uri CONTENT_FREQUENT_URI = Uri.withAppendedPath(
1805                 CONTENT_URI, "frequent");
1806 
1807         /**
1808          * <p>The content:// style URI used for "type-to-filter" functionality on the
1809          * {@link #CONTENT_STREQUENT_URI} URI. The filter string will be used to match
1810          * various parts of the contact name. The filter argument should be passed
1811          * as an additional path segment after this URI.
1812          *
1813          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
1814          * field doesn't sort results based on contacts frequency. For more information, see the
1815          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
1816          * page.
1817          */
1818         public static final Uri CONTENT_STREQUENT_FILTER_URI = Uri.withAppendedPath(
1819                 CONTENT_STREQUENT_URI, "filter");
1820 
1821         public static final Uri CONTENT_GROUP_URI = Uri.withAppendedPath(
1822                 CONTENT_URI, "group");
1823 
1824         /**
1825          * The MIME type of {@link #CONTENT_URI} providing a directory of
1826          * people.
1827          */
1828         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact";
1829 
1830         /**
1831          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
1832          * person.
1833          */
1834         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact";
1835 
1836         /**
1837          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
1838          * person.
1839          */
1840         public static final String CONTENT_VCARD_TYPE = "text/x-vcard";
1841 
1842         /**
1843          * Mimimal ID for managed profile contacts returned from
1844          * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI} and similar APIs
1845          *
1846          * @hide
1847          */
1848         public static long ENTERPRISE_CONTACT_ID_BASE = 1000000000; // slightly smaller than 2 ** 30
1849 
1850         /**
1851          * Prefix for managed profile contacts returned from
1852          * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI} and similar APIs.
1853          *
1854          * @hide
1855          */
1856         public static String ENTERPRISE_CONTACT_LOOKUP_PREFIX = "c-";
1857 
1858         /**
1859          * Return {@code true} if a contact ID is from the contacts provider on the managed profile.
1860          *
1861          * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI} and similar APIs may return such IDs.
1862          */
isEnterpriseContactId(long contactId)1863         public static boolean isEnterpriseContactId(long contactId) {
1864             return (contactId >= ENTERPRISE_CONTACT_ID_BASE) && (contactId < Profile.MIN_ID);
1865         }
1866 
1867         /**
1868          * A sub-directory of a single contact that contains all of the constituent raw contact
1869          * {@link ContactsContract.Data} rows.  This directory can be used either
1870          * with a {@link #CONTENT_URI} or {@link #CONTENT_LOOKUP_URI}.
1871          */
1872         public static final class Data implements BaseColumns, DataColumns {
1873             /**
1874              * no public constructor since this is a utility class
1875              */
Data()1876             private Data() {}
1877 
1878             /**
1879              * The directory twig for this sub-table
1880              */
1881             public static final String CONTENT_DIRECTORY = "data";
1882         }
1883 
1884         /**
1885          * <p>
1886          * A sub-directory of a contact that contains all of its
1887          * {@link ContactsContract.RawContacts} as well as
1888          * {@link ContactsContract.Data} rows. To access this directory append
1889          * {@link #CONTENT_DIRECTORY} to the contact URI.
1890          * </p>
1891          * <p>
1892          * Entity has three ID fields: {@link #CONTACT_ID} for the contact,
1893          * {@link #RAW_CONTACT_ID} for the raw contact and {@link #DATA_ID} for
1894          * the data rows. Entity always contains at least one row per
1895          * constituent raw contact, even if there are no actual data rows. In
1896          * this case the {@link #DATA_ID} field will be null.
1897          * </p>
1898          * <p>
1899          * Entity reads all data for the entire contact in one transaction, to
1900          * guarantee consistency.  There is significant data duplication
1901          * in the Entity (each row repeats all Contact columns and all RawContact
1902          * columns), so the benefits of transactional consistency should be weighed
1903          * against the cost of transferring large amounts of denormalized data
1904          * from the Provider.
1905          * </p>
1906          * <p>
1907          * To reduce the amount of data duplication the contacts provider and directory
1908          * providers implementing this protocol are allowed to provide common Contacts
1909          * and RawContacts fields in the first row returned for each raw contact only and
1910          * leave them as null in subsequent rows.
1911          * </p>
1912          */
1913         public static final class Entity implements BaseColumns, ContactsColumns,
1914                 ContactNameColumns, RawContactsColumns, BaseSyncColumns, SyncColumns, DataColumns,
1915                 StatusColumns, ContactOptionsColumns, ContactStatusColumns, DataUsageStatColumns {
1916             /**
1917              * no public constructor since this is a utility class
1918              */
Entity()1919             private Entity() {
1920             }
1921 
1922             /**
1923              * The directory twig for this sub-table
1924              */
1925             public static final String CONTENT_DIRECTORY = "entities";
1926 
1927             /**
1928              * The ID of the raw contact row.
1929              * <P>Type: INTEGER</P>
1930              */
1931             public static final String RAW_CONTACT_ID = "raw_contact_id";
1932 
1933             /**
1934              * The ID of the data row. The value will be null if this raw contact has no
1935              * data rows.
1936              * <P>Type: INTEGER</P>
1937              */
1938             public static final String DATA_ID = "data_id";
1939         }
1940 
1941         /**
1942          * <p>
1943          * A sub-directory of a single contact that contains all of the constituent raw contact
1944          * {@link ContactsContract.StreamItems} rows.  This directory can be used either
1945          * with a {@link #CONTENT_URI} or {@link #CONTENT_LOOKUP_URI}.
1946          * </p>
1947          * <p>
1948          * Querying for social stream data requires android.permission.READ_SOCIAL_STREAM
1949          * permission.
1950          * </p>
1951          *
1952          * @deprecated - Do not use. This will not be supported in the future. In the future,
1953          * cursors returned from related queries will be empty.
1954          *
1955          * @removed
1956          */
1957         @Deprecated
1958         public static final class StreamItems implements StreamItemsColumns {
1959             /**
1960              * no public constructor since this is a utility class
1961              *
1962              * @deprecated - Do not use. This will not be supported in the future. In the future,
1963              * cursors returned from related queries will be empty.
1964              */
1965             @Deprecated
StreamItems()1966             private StreamItems() {}
1967 
1968             /**
1969              * The directory twig for this sub-table
1970              *
1971              * @deprecated - Do not use. This will not be supported in the future. In the future,
1972              * cursors returned from related queries will be empty.
1973              */
1974             @Deprecated
1975             public static final String CONTENT_DIRECTORY = "stream_items";
1976         }
1977 
1978         /**
1979          * <p>
1980          * A <i>read-only</i> sub-directory of a single contact aggregate that
1981          * contains all aggregation suggestions (other contacts). The
1982          * aggregation suggestions are computed based on approximate data
1983          * matches with this contact.
1984          * </p>
1985          * <p>
1986          * <i>Note: this query may be expensive! If you need to use it in bulk,
1987          * make sure the user experience is acceptable when the query runs for a
1988          * long time.</i>
1989          * <p>
1990          * Usage example:
1991          *
1992          * <pre>
1993          * Uri uri = Contacts.CONTENT_URI.buildUpon()
1994          *          .appendEncodedPath(String.valueOf(contactId))
1995          *          .appendPath(Contacts.AggregationSuggestions.CONTENT_DIRECTORY)
1996          *          .appendQueryParameter(&quot;limit&quot;, &quot;3&quot;)
1997          *          .build()
1998          * Cursor cursor = getContentResolver().query(suggestionsUri,
1999          *          new String[] {Contacts.DISPLAY_NAME, Contacts._ID, Contacts.LOOKUP_KEY},
2000          *          null, null, null);
2001          * </pre>
2002          *
2003          * </p>
2004          * <p>
2005          * This directory can be used either with a {@link #CONTENT_URI} or
2006          * {@link #CONTENT_LOOKUP_URI}.
2007          * </p>
2008          */
2009         public static final class AggregationSuggestions implements BaseColumns, ContactsColumns,
2010                 ContactOptionsColumns, ContactStatusColumns {
2011             /**
2012              * No public constructor since this is a utility class
2013              */
AggregationSuggestions()2014             private AggregationSuggestions() {}
2015 
2016             /**
2017              * The directory twig for this sub-table. The URI can be followed by an optional
2018              * type-to-filter, similar to
2019              * {@link android.provider.ContactsContract.Contacts#CONTENT_FILTER_URI}.
2020              */
2021             public static final String CONTENT_DIRECTORY = "suggestions";
2022 
2023             /**
2024              * Used to specify what kind of data is supplied for the suggestion query.
2025              *
2026              * @hide
2027              */
2028             public static final String PARAMETER_MATCH_NAME = "name";
2029 
2030             /**
2031              * A convenience builder for aggregation suggestion content URIs.
2032              */
2033             public static final class Builder {
2034                 private long mContactId;
2035                 private final ArrayList<String> mValues = new ArrayList<String>();
2036                 private int mLimit;
2037 
2038                 /**
2039                  * Optional existing contact ID.  If it is not provided, the search
2040                  * will be based exclusively on the values supplied with {@link #addNameParameter}.
2041                  *
2042                  * @param contactId contact to find aggregation suggestions for
2043                  * @return This Builder object to allow for chaining of calls to builder methods
2044                  */
setContactId(long contactId)2045                 public Builder setContactId(long contactId) {
2046                     this.mContactId = contactId;
2047                     return this;
2048                 }
2049 
2050                 /**
2051                  * Add a name to be used when searching for aggregation suggestions.
2052                  *
2053                  * @param name name to find aggregation suggestions for
2054                  * @return This Builder object to allow for chaining of calls to builder methods
2055                  */
addNameParameter(String name)2056                 public Builder addNameParameter(String name) {
2057                     mValues.add(name);
2058                     return this;
2059                 }
2060 
2061                 /**
2062                  * Sets the Maximum number of suggested aggregations that should be returned.
2063                  * @param limit The maximum number of suggested aggregations
2064                  *
2065                  * @return This Builder object to allow for chaining of calls to builder methods
2066                  */
setLimit(int limit)2067                 public Builder setLimit(int limit) {
2068                     mLimit = limit;
2069                     return this;
2070                 }
2071 
2072                 /**
2073                  * Combine all of the options that have been set and return a new {@link Uri}
2074                  * object for fetching aggregation suggestions.
2075                  */
build()2076                 public Uri build() {
2077                     android.net.Uri.Builder builder = Contacts.CONTENT_URI.buildUpon();
2078                     builder.appendEncodedPath(String.valueOf(mContactId));
2079                     builder.appendPath(Contacts.AggregationSuggestions.CONTENT_DIRECTORY);
2080                     if (mLimit != 0) {
2081                         builder.appendQueryParameter("limit", String.valueOf(mLimit));
2082                     }
2083 
2084                     int count = mValues.size();
2085                     for (int i = 0; i < count; i++) {
2086                         builder.appendQueryParameter("query", PARAMETER_MATCH_NAME
2087                                 + ":" + mValues.get(i));
2088                     }
2089 
2090                     return builder.build();
2091                 }
2092             }
2093 
2094             /**
2095              * @hide
2096              */
2097             @UnsupportedAppUsage
builder()2098             public static final Builder builder() {
2099                 return new Builder();
2100             }
2101         }
2102 
2103         /**
2104          * A <i>read-only</i> sub-directory of a single contact that contains
2105          * the contact's primary photo.  The photo may be stored in up to two ways -
2106          * the default "photo" is a thumbnail-sized image stored directly in the data
2107          * row, while the "display photo", if present, is a larger version stored as
2108          * a file.
2109          * <p>
2110          * Usage example:
2111          * <dl>
2112          * <dt>Retrieving the thumbnail-sized photo</dt>
2113          * <dd>
2114          * <pre>
2115          * public InputStream openPhoto(long contactId) {
2116          *     Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
2117          *     Uri photoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.CONTENT_DIRECTORY);
2118          *     Cursor cursor = getContentResolver().query(photoUri,
2119          *          new String[] {Contacts.Photo.PHOTO}, null, null, null);
2120          *     if (cursor == null) {
2121          *         return null;
2122          *     }
2123          *     try {
2124          *         if (cursor.moveToFirst()) {
2125          *             byte[] data = cursor.getBlob(0);
2126          *             if (data != null) {
2127          *                 return new ByteArrayInputStream(data);
2128          *             }
2129          *         }
2130          *     } finally {
2131          *         cursor.close();
2132          *     }
2133          *     return null;
2134          * }
2135          * </pre>
2136          * </dd>
2137          * <dt>Retrieving the larger photo version</dt>
2138          * <dd>
2139          * <pre>
2140          * public InputStream openDisplayPhoto(long contactId) {
2141          *     Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
2142          *     Uri displayPhotoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.DISPLAY_PHOTO);
2143          *     try {
2144          *         AssetFileDescriptor fd =
2145          *             getContentResolver().openAssetFileDescriptor(displayPhotoUri, "r");
2146          *         return fd.createInputStream();
2147          *     } catch (IOException e) {
2148          *         return null;
2149          *     }
2150          * }
2151          * </pre>
2152          * </dd>
2153          * </dl>
2154          *
2155          * </p>
2156          * <p>You may also consider using the convenience method
2157          * {@link ContactsContract.Contacts#openContactPhotoInputStream(ContentResolver, Uri, boolean)}
2158          * to retrieve the raw photo contents of either the thumbnail-sized or the full-sized photo.
2159          * </p>
2160          * <p>
2161          * This directory can be used either with a {@link #CONTENT_URI} or
2162          * {@link #CONTENT_LOOKUP_URI}.
2163          * </p>
2164          */
2165         public static final class Photo implements BaseColumns, DataColumnsWithJoins {
2166             /**
2167              * no public constructor since this is a utility class
2168              */
Photo()2169             private Photo() {}
2170 
2171             /**
2172              * The directory twig for this sub-table
2173              */
2174             public static final String CONTENT_DIRECTORY = "photo";
2175 
2176             /**
2177              * The directory twig for retrieving the full-size display photo.
2178              */
2179             public static final String DISPLAY_PHOTO = "display_photo";
2180 
2181             /**
2182              * Full-size photo file ID of the raw contact.
2183              * See {@link ContactsContract.DisplayPhoto}.
2184              * <p>
2185              * Type: NUMBER
2186              */
2187             public static final String PHOTO_FILE_ID = DATA14;
2188 
2189             /**
2190              * Thumbnail photo of the raw contact. This is the raw bytes of an image
2191              * that could be inflated using {@link android.graphics.BitmapFactory}.
2192              * <p>
2193              * Type: BLOB
2194              */
2195             public static final String PHOTO = DATA15;
2196         }
2197 
2198         /**
2199          * Opens an InputStream for the contacts's photo and returns the
2200          * photo as a byte stream.
2201          * @param cr The content resolver to use for querying
2202          * @param contactUri the contact whose photo should be used. This can be used with
2203          * either a {@link #CONTENT_URI} or a {@link #CONTENT_LOOKUP_URI} URI.
2204          * @param preferHighres If this is true and the contact has a higher resolution photo
2205          * available, it is returned. If false, this function always tries to get the thumbnail
2206          * @return an InputStream of the photo, or null if no photo is present
2207          */
openContactPhotoInputStream(ContentResolver cr, Uri contactUri, boolean preferHighres)2208         public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri,
2209                 boolean preferHighres) {
2210             if (preferHighres) {
2211                 final Uri displayPhotoUri = Uri.withAppendedPath(contactUri,
2212                         Contacts.Photo.DISPLAY_PHOTO);
2213                 try {
2214                     AssetFileDescriptor fd = cr.openAssetFileDescriptor(displayPhotoUri, "r");
2215                     if (fd != null) {
2216                         return fd.createInputStream();
2217                     }
2218                 } catch (IOException e) {
2219                     // fallback to the thumbnail code
2220                 }
2221            }
2222 
2223             Uri photoUri = Uri.withAppendedPath(contactUri, Photo.CONTENT_DIRECTORY);
2224             if (photoUri == null) {
2225                 return null;
2226             }
2227             Cursor cursor = cr.query(photoUri,
2228                     new String[] {
2229                         ContactsContract.CommonDataKinds.Photo.PHOTO
2230                     }, null, null, null);
2231             try {
2232                 if (cursor == null || !cursor.moveToNext()) {
2233                     return null;
2234                 }
2235                 byte[] data = cursor.getBlob(0);
2236                 if (data == null) {
2237                     return null;
2238                 }
2239                 return new ByteArrayInputStream(data);
2240             } finally {
2241                 if (cursor != null) {
2242                     cursor.close();
2243                 }
2244             }
2245         }
2246 
2247         /**
2248          * Opens an InputStream for the contacts's thumbnail photo and returns the
2249          * photo as a byte stream.
2250          * @param cr The content resolver to use for querying
2251          * @param contactUri the contact whose photo should be used. This can be used with
2252          * either a {@link #CONTENT_URI} or a {@link #CONTENT_LOOKUP_URI} URI.
2253          * @return an InputStream of the photo, or null if no photo is present
2254          * @see #openContactPhotoInputStream(ContentResolver, Uri, boolean), if instead
2255          * of the thumbnail the high-res picture is preferred
2256          */
openContactPhotoInputStream(ContentResolver cr, Uri contactUri)2257         public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri) {
2258             return openContactPhotoInputStream(cr, contactUri, false);
2259         }
2260 
2261         /**
2262          * Creates and returns a corp lookup URI from the given enterprise lookup URI by removing
2263          * {@link #ENTERPRISE_CONTACT_LOOKUP_PREFIX} from the key. Returns {@code null} if the given
2264          * URI is not an enterprise lookup URI.
2265          *
2266          * @hide
2267          */
2268         @Nullable
createCorpLookupUriFromEnterpriseLookupUri( @onNull Uri enterpriseLookupUri)2269         public static Uri createCorpLookupUriFromEnterpriseLookupUri(
2270                 @NonNull Uri enterpriseLookupUri) {
2271             final List<String> pathSegments = enterpriseLookupUri.getPathSegments();
2272             if (pathSegments == null || pathSegments.size() <= 2) {
2273                 return null;
2274             }
2275             final String key = pathSegments.get(2);
2276             if (TextUtils.isEmpty(key) || !key.startsWith(ENTERPRISE_CONTACT_LOOKUP_PREFIX)) {
2277                 return null;
2278             }
2279             final String actualKey = key.substring(ENTERPRISE_CONTACT_LOOKUP_PREFIX.length());
2280             return Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, actualKey);
2281         }
2282     }
2283 
2284     /**
2285      * <p>
2286      * Constants for the user's profile data, which is represented as a single contact on
2287      * the device that represents the user.  The profile contact is not aggregated
2288      * together automatically in the same way that normal contacts are; instead, each
2289      * account (including data set, if applicable) on the device may contribute a single
2290      * raw contact representing the user's personal profile data from that source.
2291      * </p>
2292      * <p>
2293      * Access to the profile entry through these URIs (or incidental access to parts of
2294      * the profile if retrieved directly via ID) requires additional permissions beyond
2295      * the read/write contact permissions required by the provider.  Querying for profile
2296      * data requires android.permission.READ_PROFILE permission, and inserting or
2297      * updating profile data requires android.permission.WRITE_PROFILE permission.
2298      * </p>
2299      * <h3>Operations</h3>
2300      * <dl>
2301      * <dt><b>Insert</b></dt>
2302      * <dd>The user's profile entry cannot be created explicitly (attempting to do so
2303      * will throw an exception). When a raw contact is inserted into the profile, the
2304      * provider will check for the existence of a profile on the device.  If one is
2305      * found, the raw contact's {@link RawContacts#CONTACT_ID} column gets the _ID of
2306      * the profile Contact. If no match is found, the profile Contact is created and
2307      * its _ID is put into the {@link RawContacts#CONTACT_ID} column of the newly
2308      * inserted raw contact.</dd>
2309      * <dt><b>Update</b></dt>
2310      * <dd>The profile Contact has the same update restrictions as Contacts in general,
2311      * but requires the android.permission.WRITE_PROFILE permission.</dd>
2312      * <dt><b>Delete</b></dt>
2313      * <dd>The profile Contact cannot be explicitly deleted.  It will be removed
2314      * automatically if all of its constituent raw contact entries are deleted.</dd>
2315      * <dt><b>Query</b></dt>
2316      * <dd>
2317      * <ul>
2318      * <li>The {@link #CONTENT_URI} for profiles behaves in much the same way as
2319      * retrieving a contact by ID, except that it will only ever return the user's
2320      * profile contact.
2321      * </li>
2322      * <li>
2323      * The profile contact supports all of the same sub-paths as an individual contact
2324      * does - the content of the profile contact can be retrieved as entities or
2325      * data rows.  Similarly, specific raw contact entries can be retrieved by appending
2326      * the desired raw contact ID within the profile.
2327      * </li>
2328      * </ul>
2329      * </dd>
2330      * </dl>
2331      */
2332     public static final class Profile implements BaseColumns, ContactsColumns,
2333             ContactOptionsColumns, ContactNameColumns, ContactStatusColumns {
2334         /**
2335          * This utility class cannot be instantiated
2336          */
Profile()2337         private Profile() {
2338         }
2339 
2340         /**
2341          * The content:// style URI for this table, which requests the contact entry
2342          * representing the user's personal profile data.
2343          */
2344         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "profile");
2345 
2346         /**
2347          * {@link Uri} for referencing the user's profile {@link Contacts} entry,
2348          * Provides {@link OpenableColumns} columns when queried, or returns the
2349          * user's profile contact formatted as a vCard when opened through
2350          * {@link ContentResolver#openAssetFileDescriptor(Uri, String)}.
2351          */
2352         public static final Uri CONTENT_VCARD_URI = Uri.withAppendedPath(CONTENT_URI,
2353                 "as_vcard");
2354 
2355         /**
2356          * {@link Uri} for referencing the raw contacts that make up the user's profile
2357          * {@link Contacts} entry.  An individual raw contact entry within the profile
2358          * can be addressed by appending the raw contact ID.  The entities or data within
2359          * that specific raw contact can be requested by appending the entity or data
2360          * path as well.
2361          */
2362         public static final Uri CONTENT_RAW_CONTACTS_URI = Uri.withAppendedPath(CONTENT_URI,
2363                 "raw_contacts");
2364 
2365         /**
2366          * The minimum ID for any entity that belongs to the profile.  This essentially
2367          * defines an ID-space in which profile data is stored, and is used by the provider
2368          * to determine whether a request via a non-profile-specific URI should be directed
2369          * to the profile data rather than general contacts data, along with all the special
2370          * permission checks that entails.
2371          *
2372          * Callers may use {@link #isProfileId} to check whether a specific ID falls into
2373          * the set of data intended for the profile.
2374          */
2375         public static final long MIN_ID = Long.MAX_VALUE - (long) Integer.MAX_VALUE;
2376     }
2377 
2378     /**
2379      * This method can be used to identify whether the given ID is associated with profile
2380      * data.  It does not necessarily indicate that the ID is tied to valid data, merely
2381      * that accessing data using this ID will result in profile access checks and will only
2382      * return data from the profile.
2383      *
2384      * @param id The ID to check.
2385      * @return Whether the ID is associated with profile data.
2386      */
isProfileId(long id)2387     public static boolean isProfileId(long id) {
2388         return id >= Profile.MIN_ID;
2389     }
2390 
2391     protected interface DeletedContactsColumns {
2392 
2393         /**
2394          * A reference to the {@link ContactsContract.Contacts#_ID} that was deleted.
2395          * <P>Type: INTEGER</P>
2396          */
2397         public static final String CONTACT_ID = "contact_id";
2398 
2399         /**
2400          * Time (milliseconds since epoch) that the contact was deleted.
2401          */
2402         public static final String CONTACT_DELETED_TIMESTAMP = "contact_deleted_timestamp";
2403     }
2404 
2405     /**
2406      * Constants for the deleted contact table.  This table holds a log of deleted contacts.
2407      * <p>
2408      * Log older than {@link #DAYS_KEPT_MILLISECONDS} may be deleted.
2409      */
2410     public static final class DeletedContacts implements DeletedContactsColumns {
2411 
2412         /**
2413          * This utility class cannot be instantiated
2414          */
DeletedContacts()2415         private DeletedContacts() {
2416         }
2417 
2418         /**
2419          * The content:// style URI for this table, which requests a directory of raw contact rows
2420          * matching the selection criteria.
2421          */
2422         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
2423                 "deleted_contacts");
2424 
2425         /**
2426          * Number of days that the delete log will be kept.  After this time, delete records may be
2427          * deleted.
2428          *
2429          * @hide
2430          */
2431         private static final int DAYS_KEPT = 30;
2432 
2433         /**
2434          * Milliseconds that the delete log will be kept.  After this time, delete records may be
2435          * deleted.
2436          */
2437         public static final long DAYS_KEPT_MILLISECONDS = 1000L * 60L * 60L * 24L * (long)DAYS_KEPT;
2438     }
2439 
2440     protected interface RawContactsColumns {
2441         /**
2442          * A reference to the {@link ContactsContract.Contacts#_ID} that this
2443          * data belongs to.
2444          * <P>Type: INTEGER</P>
2445          */
2446         public static final String CONTACT_ID = "contact_id";
2447 
2448         /**
2449          * Persistent unique id for each raw_contact within its account.
2450          * This id is provided by its own data source, and can be used to backup metadata
2451          * to the server.
2452          * This should be unique within each set of account_name/account_type/data_set
2453          */
2454         public static final String BACKUP_ID = "backup_id";
2455 
2456         /**
2457          * The data set within the account that this row belongs to.  This allows
2458          * multiple sync adapters for the same account type to distinguish between
2459          * each others' data.
2460          *
2461          * This is empty by default, and is completely optional.  It only needs to
2462          * be populated if multiple sync adapters are entering distinct data for
2463          * the same account type and account name.
2464          * <P>Type: TEXT</P>
2465          */
2466         public static final String DATA_SET = "data_set";
2467 
2468         /**
2469          * A concatenation of the account type and data set (delimited by a forward
2470          * slash) - if the data set is empty, this will be the same as the account
2471          * type.  For applications that need to be aware of the data set, this can
2472          * be used instead of account type to distinguish sets of data.  This is
2473          * never intended to be used for specifying accounts.
2474          * <p>
2475          * This column does *not* escape forward slashes in the account type or the data set.
2476          * If this is an issue, consider using
2477          * {@link ContactsContract.RawContacts#ACCOUNT_TYPE} and
2478          * {@link ContactsContract.RawContacts#DATA_SET} directly.
2479          */
2480         public static final String ACCOUNT_TYPE_AND_DATA_SET = "account_type_and_data_set";
2481 
2482         /**
2483          * The aggregation mode for this contact.
2484          * <P>Type: INTEGER</P>
2485          */
2486         public static final String AGGREGATION_MODE = "aggregation_mode";
2487 
2488         /**
2489          * The "deleted" flag: "0" by default, "1" if the row has been marked
2490          * for deletion. When {@link android.content.ContentResolver#delete} is
2491          * called on a raw contact, it is marked for deletion and removed from its
2492          * aggregate contact. The sync adaptor deletes the raw contact on the server and
2493          * then calls ContactResolver.delete once more, this time passing the
2494          * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to finalize
2495          * the data removal.
2496          * <P>Type: INTEGER</P>
2497          */
2498         public static final String DELETED = "deleted";
2499 
2500         /**
2501          * The "read-only" flag: "0" by default, "1" if the row cannot be modified or
2502          * deleted except by a sync adapter.  See {@link ContactsContract#CALLER_IS_SYNCADAPTER}.
2503          * <P>Type: INTEGER</P>
2504          */
2505         public static final String RAW_CONTACT_IS_READ_ONLY = "raw_contact_is_read_only";
2506 
2507         /**
2508          * Flag that reflects whether this raw contact belongs to the user's
2509          * personal profile entry.
2510          */
2511         public static final String RAW_CONTACT_IS_USER_PROFILE = "raw_contact_is_user_profile";
2512 
2513         /**
2514          * Flag indicating that a raw contact's metadata has changed, and its metadata
2515          * needs to be synchronized by the server.
2516          * <P>Type: INTEGER (boolean)</P>
2517          *
2518          * @deprecated This column never actually worked since added. It will not supported as
2519          * of Android version {@link android.os.Build.VERSION_CODES#R}.
2520          */
2521         @Deprecated
2522         public static final String METADATA_DIRTY = "metadata_dirty";
2523     }
2524 
2525     /**
2526      * Constants for the raw contacts table, which contains one row of contact
2527      * information for each person in each synced account. Sync adapters and
2528      * contact management apps
2529      * are the primary consumers of this API.
2530      *
2531      * <h3>Aggregation</h3>
2532      * <p>
2533      * As soon as a raw contact is inserted or whenever its constituent data
2534      * changes, the provider will check if the raw contact matches other
2535      * existing raw contacts and if so will aggregate it with those. The
2536      * aggregation is reflected in the {@link RawContacts} table by the change of the
2537      * {@link #CONTACT_ID} field, which is the reference to the aggregate contact.
2538      * </p>
2539      * <p>
2540      * Changes to the structured name, organization, phone number, email address,
2541      * or nickname trigger a re-aggregation.
2542      * </p>
2543      * <p>
2544      * See also {@link AggregationExceptions} for a mechanism to control
2545      * aggregation programmatically.
2546      * </p>
2547      *
2548      * <h3>Operations</h3>
2549      * <dl>
2550      * <dt><b>Insert</b></dt>
2551      * <dd>
2552      * <p>
2553      * Raw contacts can be inserted incrementally or in a batch.
2554      * The incremental method is more traditional but less efficient.
2555      * It should be used
2556      * only if no {@link Data} values are available at the time the raw contact is created:
2557      * <pre>
2558      * ContentValues values = new ContentValues();
2559      * values.put(RawContacts.ACCOUNT_TYPE, accountType);
2560      * values.put(RawContacts.ACCOUNT_NAME, accountName);
2561      * Uri rawContactUri = getContentResolver().insert(RawContacts.CONTENT_URI, values);
2562      * long rawContactId = ContentUris.parseId(rawContactUri);
2563      * </pre>
2564      * </p>
2565      * <p>
2566      * Once {@link Data} values become available, insert those.
2567      * For example, here's how you would insert a name:
2568      *
2569      * <pre>
2570      * values.clear();
2571      * values.put(Data.RAW_CONTACT_ID, rawContactId);
2572      * values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
2573      * values.put(StructuredName.DISPLAY_NAME, &quot;Mike Sullivan&quot;);
2574      * getContentResolver().insert(Data.CONTENT_URI, values);
2575      * </pre>
2576      * </p>
2577      * <p>
2578      * The batch method is by far preferred.  It inserts the raw contact and its
2579      * constituent data rows in a single database transaction
2580      * and causes at most one aggregation pass.
2581      * <pre>
2582      * ArrayList&lt;ContentProviderOperation&gt; ops =
2583      *          new ArrayList&lt;ContentProviderOperation&gt;();
2584      * ...
2585      * int rawContactInsertIndex = ops.size();
2586      * ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
2587      *          .withValue(RawContacts.ACCOUNT_TYPE, accountType)
2588      *          .withValue(RawContacts.ACCOUNT_NAME, accountName)
2589      *          .build());
2590      *
2591      * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
2592      *          .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
2593      *          .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
2594      *          .withValue(StructuredName.DISPLAY_NAME, &quot;Mike Sullivan&quot;)
2595      *          .build());
2596      *
2597      * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
2598      * </pre>
2599      * </p>
2600      * <p>
2601      * Note the use of {@link ContentProviderOperation.Builder#withValueBackReference(String, int)}
2602      * to refer to the as-yet-unknown index value of the raw contact inserted in the
2603      * first operation.
2604      * </p>
2605      *
2606      * <dt><b>Update</b></dt>
2607      * <dd><p>
2608      * Raw contacts can be updated incrementally or in a batch.
2609      * Batch mode should be used whenever possible.
2610      * The procedures and considerations are analogous to those documented above for inserts.
2611      * </p></dd>
2612      * <dt><b>Delete</b></dt>
2613      * <dd><p>When a raw contact is deleted, all of its Data rows as well as StatusUpdates,
2614      * AggregationExceptions, PhoneLookup rows are deleted automatically. When all raw
2615      * contacts associated with a {@link Contacts} row are deleted, the {@link Contacts} row
2616      * itself is also deleted automatically.
2617      * </p>
2618      * <p>
2619      * The invocation of {@code resolver.delete(...)}, does not immediately delete
2620      * a raw contacts row.
2621      * Instead, it sets the {@link #DELETED} flag on the raw contact and
2622      * removes the raw contact from its aggregate contact.
2623      * The sync adapter then deletes the raw contact from the server and
2624      * finalizes phone-side deletion by calling {@code resolver.delete(...)}
2625      * again and passing the {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter.<p>
2626      * <p>Some sync adapters are read-only, meaning that they only sync server-side
2627      * changes to the phone, but not the reverse.  If one of those raw contacts
2628      * is marked for deletion, it will remain on the phone.  However it will be
2629      * effectively invisible, because it will not be part of any aggregate contact.
2630      * </dd>
2631      *
2632      * <dt><b>Query</b></dt>
2633      * <dd>
2634      * <p>
2635      * It is easy to find all raw contacts in a Contact:
2636      * <pre>
2637      * Cursor c = getContentResolver().query(RawContacts.CONTENT_URI,
2638      *          new String[]{RawContacts._ID},
2639      *          RawContacts.CONTACT_ID + "=?",
2640      *          new String[]{String.valueOf(contactId)}, null);
2641      * </pre>
2642      * </p>
2643      * <p>
2644      * To find raw contacts within a specific account,
2645      * you can either put the account name and type in the selection or pass them as query
2646      * parameters.  The latter approach is preferable, especially when you can reuse the
2647      * URI:
2648      * <pre>
2649      * Uri rawContactUri = RawContacts.CONTENT_URI.buildUpon()
2650      *          .appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName)
2651      *          .appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType)
2652      *          .build();
2653      * Cursor c1 = getContentResolver().query(rawContactUri,
2654      *          RawContacts.STARRED + "&lt;&gt;0", null, null, null);
2655      * ...
2656      * Cursor c2 = getContentResolver().query(rawContactUri,
2657      *          RawContacts.DELETED + "&lt;&gt;0", null, null, null);
2658      * </pre>
2659      * </p>
2660      * <p>The best way to read a raw contact along with all the data associated with it is
2661      * by using the {@link Entity} directory. If the raw contact has data rows,
2662      * the Entity cursor will contain a row for each data row.  If the raw contact has no
2663      * data rows, the cursor will still contain one row with the raw contact-level information.
2664      * <pre>
2665      * Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
2666      * Uri entityUri = Uri.withAppendedPath(rawContactUri, Entity.CONTENT_DIRECTORY);
2667      * Cursor c = getContentResolver().query(entityUri,
2668      *          new String[]{RawContacts.SOURCE_ID, Entity.DATA_ID, Entity.MIMETYPE, Entity.DATA1},
2669      *          null, null, null);
2670      * try {
2671      *     while (c.moveToNext()) {
2672      *         String sourceId = c.getString(0);
2673      *         if (!c.isNull(1)) {
2674      *             String mimeType = c.getString(2);
2675      *             String data = c.getString(3);
2676      *             ...
2677      *         }
2678      *     }
2679      * } finally {
2680      *     c.close();
2681      * }
2682      * </pre>
2683      * </p>
2684      * </dd>
2685      * </dl>
2686      * <h2>Columns</h2>
2687      *
2688      * <table class="jd-sumtable">
2689      * <tr>
2690      * <th colspan='4'>RawContacts</th>
2691      * </tr>
2692      * <tr>
2693      * <td>long</td>
2694      * <td>{@link #_ID}</td>
2695      * <td>read-only</td>
2696      * <td>Row ID. Sync adapters should try to preserve row IDs during updates. In other words,
2697      * it is much better for a sync adapter to update a raw contact rather than to delete and
2698      * re-insert it.</td>
2699      * </tr>
2700      * <tr>
2701      * <td>long</td>
2702      * <td>{@link #CONTACT_ID}</td>
2703      * <td>read-only</td>
2704      * <td>The ID of the row in the {@link ContactsContract.Contacts} table
2705      * that this raw contact belongs
2706      * to. Raw contacts are linked to contacts by the aggregation process, which can be controlled
2707      * by the {@link #AGGREGATION_MODE} field and {@link AggregationExceptions}.</td>
2708      * </tr>
2709      * <tr>
2710      * <td>int</td>
2711      * <td>{@link #AGGREGATION_MODE}</td>
2712      * <td>read/write</td>
2713      * <td>A mechanism that allows programmatic control of the aggregation process. The allowed
2714      * values are {@link #AGGREGATION_MODE_DEFAULT}, {@link #AGGREGATION_MODE_DISABLED}
2715      * and {@link #AGGREGATION_MODE_SUSPENDED}. See also {@link AggregationExceptions}.</td>
2716      * </tr>
2717      * <tr>
2718      * <td>int</td>
2719      * <td>{@link #DELETED}</td>
2720      * <td>read/write</td>
2721      * <td>The "deleted" flag: "0" by default, "1" if the row has been marked
2722      * for deletion. When {@link android.content.ContentResolver#delete} is
2723      * called on a raw contact, it is marked for deletion and removed from its
2724      * aggregate contact. The sync adaptor deletes the raw contact on the server and
2725      * then calls ContactResolver.delete once more, this time passing the
2726      * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to finalize
2727      * the data removal.</td>
2728      * </tr>
2729      * <tr>
2730      * <td>int</td>
2731      * <td>{@link #STARRED}</td>
2732      * <td>read/write</td>
2733      * <td>An indicator for favorite contacts: '1' if favorite, '0' otherwise.
2734      * Changing this field immediately affects the corresponding aggregate contact:
2735      * if any raw contacts in that aggregate contact are starred, then the contact
2736      * itself is marked as starred.</td>
2737      * </tr>
2738      * <tr>
2739      * <td>String</td>
2740      * <td>{@link #CUSTOM_RINGTONE}</td>
2741      * <td>read/write</td>
2742      * <td>A custom ringtone associated with a raw contact. Typically this is the
2743      * URI returned by an activity launched with the
2744      * {@link android.media.RingtoneManager#ACTION_RINGTONE_PICKER} intent.
2745      * To have an effect on the corresponding value of the aggregate contact, this field
2746      * should be set at the time the raw contact is inserted. To set a custom
2747      * ringtone on a contact, use the field {@link ContactsContract.Contacts#CUSTOM_RINGTONE
2748      * Contacts.CUSTOM_RINGTONE}
2749      * instead.</td>
2750      * </tr>
2751      * <tr>
2752      * <td>int</td>
2753      * <td>{@link #SEND_TO_VOICEMAIL}</td>
2754      * <td>read/write</td>
2755      * <td>An indicator of whether calls from this raw contact should be forwarded
2756      * directly to voice mail ('1') or not ('0'). To have an effect
2757      * on the corresponding value of the aggregate contact, this field
2758      * should be set at the time the raw contact is inserted.</td>
2759      * </tr>
2760      * <tr>
2761      * <td>String</td>
2762      * <td>{@link #ACCOUNT_NAME}</td>
2763      * <td>read/write-once</td>
2764      * <td>The name of the account instance to which this row belongs, which when paired with
2765      * {@link #ACCOUNT_TYPE} identifies a specific account.
2766      * For example, this will be the Gmail address if it is a Google account.
2767      * It should be set at the time the raw contact is inserted and never
2768      * changed afterwards.</td>
2769      * </tr>
2770      * <tr>
2771      * <td>String</td>
2772      * <td>{@link #ACCOUNT_TYPE}</td>
2773      * <td>read/write-once</td>
2774      * <td>
2775      * <p>
2776      * The type of account to which this row belongs, which when paired with
2777      * {@link #ACCOUNT_NAME} identifies a specific account.
2778      * It should be set at the time the raw contact is inserted and never
2779      * changed afterwards.
2780      * </p>
2781      * <p>
2782      * To ensure uniqueness, new account types should be chosen according to the
2783      * Java package naming convention.  Thus a Google account is of type "com.google".
2784      * </p>
2785      * </td>
2786      * </tr>
2787      * <tr>
2788      * <td>String</td>
2789      * <td>{@link #DATA_SET}</td>
2790      * <td>read/write-once</td>
2791      * <td>
2792      * <p>
2793      * The data set within the account that this row belongs to.  This allows
2794      * multiple sync adapters for the same account type to distinguish between
2795      * each others' data.  The combination of {@link #ACCOUNT_TYPE},
2796      * {@link #ACCOUNT_NAME}, and {@link #DATA_SET} identifies a set of data
2797      * that is associated with a single sync adapter.
2798      * </p>
2799      * <p>
2800      * This is empty by default, and is completely optional.  It only needs to
2801      * be populated if multiple sync adapters are entering distinct data for
2802      * the same account type and account name.
2803      * </p>
2804      * <p>
2805      * It should be set at the time the raw contact is inserted and never
2806      * changed afterwards.
2807      * </p>
2808      * </td>
2809      * </tr>
2810      * <tr>
2811      * <td>String</td>
2812      * <td>{@link #SOURCE_ID}</td>
2813      * <td>read/write</td>
2814      * <td>String that uniquely identifies this row to its source account.
2815      * Typically it is set at the time the raw contact is inserted and never
2816      * changed afterwards. The one notable exception is a new raw contact: it
2817      * will have an account name and type (and possibly a data set), but no
2818      * source id. This indicates to the sync adapter that a new contact needs
2819      * to be created server-side and its ID stored in the corresponding
2820      * SOURCE_ID field on the phone.
2821      * </td>
2822      * </tr>
2823      * <tr>
2824      * <td>int</td>
2825      * <td>{@link #VERSION}</td>
2826      * <td>read-only</td>
2827      * <td>Version number that is updated whenever this row or its related data
2828      * changes. This field can be used for optimistic locking of a raw contact.
2829      * </td>
2830      * </tr>
2831      * <tr>
2832      * <td>int</td>
2833      * <td>{@link #DIRTY}</td>
2834      * <td>read/write</td>
2835      * <td>Flag indicating that {@link #VERSION} has changed, and this row needs
2836      * to be synchronized by its owning account.  The value is set to "1" automatically
2837      * whenever the raw contact changes, unless the URI has the
2838      * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter specified.
2839      * The sync adapter should always supply this query parameter to prevent
2840      * unnecessary synchronization: user changes some data on the server,
2841      * the sync adapter updates the contact on the phone (without the
2842      * CALLER_IS_SYNCADAPTER flag) flag, which sets the DIRTY flag,
2843      * which triggers a sync to bring the changes to the server.
2844      * </td>
2845      * </tr>
2846      * <tr>
2847      * <td>String</td>
2848      * <td>{@link #SYNC1}</td>
2849      * <td>read/write</td>
2850      * <td>Generic column provided for arbitrary use by sync adapters.
2851      * The content provider
2852      * stores this information on behalf of the sync adapter but does not
2853      * interpret it in any way.
2854      * </td>
2855      * </tr>
2856      * <tr>
2857      * <td>String</td>
2858      * <td>{@link #SYNC2}</td>
2859      * <td>read/write</td>
2860      * <td>Generic column for use by sync adapters.
2861      * </td>
2862      * </tr>
2863      * <tr>
2864      * <td>String</td>
2865      * <td>{@link #SYNC3}</td>
2866      * <td>read/write</td>
2867      * <td>Generic column for use by sync adapters.
2868      * </td>
2869      * </tr>
2870      * <tr>
2871      * <td>String</td>
2872      * <td>{@link #SYNC4}</td>
2873      * <td>read/write</td>
2874      * <td>Generic column for use by sync adapters.
2875      * </td>
2876      * </tr>
2877      * </table>
2878      */
2879     public static final class RawContacts implements BaseColumns, RawContactsColumns,
2880             ContactOptionsColumns, ContactNameColumns, SyncColumns  {
2881         /**
2882          * This utility class cannot be instantiated
2883          */
RawContacts()2884         private RawContacts() {
2885         }
2886 
2887         /**
2888          * The content:// style URI for this table, which requests a directory of
2889          * raw contact rows matching the selection criteria.
2890          */
2891         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "raw_contacts");
2892 
2893         /**
2894          * The MIME type of the results from {@link #CONTENT_URI} when a specific
2895          * ID value is not provided, and multiple raw contacts may be returned.
2896          */
2897         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact";
2898 
2899         /**
2900          * The MIME type of the results when a raw contact ID is appended to {@link #CONTENT_URI},
2901          * yielding a subdirectory of a single person.
2902          */
2903         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/raw_contact";
2904 
2905         /**
2906          * Aggregation mode: aggregate immediately after insert or update operation(s) are complete.
2907          */
2908         public static final int AGGREGATION_MODE_DEFAULT = 0;
2909 
2910         /**
2911          * Aggregation mode: aggregate at the time the raw contact is inserted/updated.
2912          * @deprecated Aggregation is synchronous, this historic value is a no-op
2913          */
2914         @Deprecated
2915         public static final int AGGREGATION_MODE_IMMEDIATE = 1;
2916 
2917         /**
2918          * <p>
2919          * Aggregation mode: aggregation suspended temporarily, and is likely to be resumed later.
2920          * Changes to the raw contact will update the associated aggregate contact but will not
2921          * result in any change in how the contact is aggregated. Similar to
2922          * {@link #AGGREGATION_MODE_DISABLED}, but maintains a link to the corresponding
2923          * {@link Contacts} aggregate.
2924          * </p>
2925          * <p>
2926          * This can be used to postpone aggregation until after a series of updates, for better
2927          * performance and/or user experience.
2928          * </p>
2929          * <p>
2930          * Note that changing
2931          * {@link #AGGREGATION_MODE} from {@link #AGGREGATION_MODE_SUSPENDED} to
2932          * {@link #AGGREGATION_MODE_DEFAULT} does not trigger an aggregation pass, but any
2933          * subsequent
2934          * change to the raw contact's data will.
2935          * </p>
2936          */
2937         public static final int AGGREGATION_MODE_SUSPENDED = 2;
2938 
2939         /**
2940          * <p>
2941          * Aggregation mode: never aggregate this raw contact.  The raw contact will not
2942          * have a corresponding {@link Contacts} aggregate and therefore will not be included in
2943          * {@link Contacts} query results.
2944          * </p>
2945          * <p>
2946          * For example, this mode can be used for a raw contact that is marked for deletion while
2947          * waiting for the deletion to occur on the server side.
2948          * </p>
2949          *
2950          * @see #AGGREGATION_MODE_SUSPENDED
2951          */
2952         public static final int AGGREGATION_MODE_DISABLED = 3;
2953 
2954         /**
2955          * Build a {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}
2956          * style {@link Uri} for the parent {@link android.provider.ContactsContract.Contacts}
2957          * entry of the given {@link RawContacts} entry.
2958          */
getContactLookupUri(ContentResolver resolver, Uri rawContactUri)2959         public static Uri getContactLookupUri(ContentResolver resolver, Uri rawContactUri) {
2960             // TODO: use a lighter query by joining rawcontacts with contacts in provider
2961             final Uri dataUri = Uri.withAppendedPath(rawContactUri, Data.CONTENT_DIRECTORY);
2962             final Cursor cursor = resolver.query(dataUri, new String[] {
2963                     RawContacts.CONTACT_ID, Contacts.LOOKUP_KEY
2964             }, null, null, null);
2965 
2966             Uri lookupUri = null;
2967             try {
2968                 if (cursor != null && cursor.moveToFirst()) {
2969                     final long contactId = cursor.getLong(0);
2970                     final String lookupKey = cursor.getString(1);
2971                     return Contacts.getLookupUri(contactId, lookupKey);
2972                 }
2973             } finally {
2974                 if (cursor != null) cursor.close();
2975             }
2976             return lookupUri;
2977         }
2978 
2979         /**
2980          * The default value used for {@link #ACCOUNT_NAME} of raw contacts when they are inserted
2981          * without a value for this column.
2982          *
2983          * <p>This account is used to identify contacts that are only stored locally in the
2984          * contacts database instead of being associated with an {@link Account} managed by an
2985          * installed application.
2986          *
2987          * <p>When this returns null then {@link #getLocalAccountType} will also return null and
2988          * when it is non-null {@link #getLocalAccountType} will also return a non-null value.
2989          */
2990         @Nullable
getLocalAccountName(@onNull Context context)2991         public static String getLocalAccountName(@NonNull Context context) {
2992             //  config_rawContactsLocalAccountName is defined in
2993             //  platform/frameworks/base/core/res/res/values/config.xml
2994             return TextUtils.nullIfEmpty(context.getString(
2995                     com.android.internal.R.string.config_rawContactsLocalAccountName));
2996         }
2997 
2998         /**
2999          * The default value used for {@link #ACCOUNT_TYPE} of raw contacts when they are inserted
3000          * without a value for this column.
3001          *
3002          * <p>This account is used to identify contacts that are only stored locally in the
3003          * contacts database instead of being associated with an {@link Account} managed by an
3004          * installed application.
3005          *
3006          * <p>When this returns null then {@link #getLocalAccountName} will also return null and
3007          * when it is non-null {@link #getLocalAccountName} will also return a non-null value.
3008          */
3009         @Nullable
getLocalAccountType(@onNull Context context)3010         public static String getLocalAccountType(@NonNull Context context) {
3011             //  config_rawContactsLocalAccountType is defined in
3012             //  platform/frameworks/base/core/res/res/values/config.xml
3013             return TextUtils.nullIfEmpty(context.getString(
3014                     com.android.internal.R.string.config_rawContactsLocalAccountType));
3015         }
3016 
3017         /**
3018          * A sub-directory of a single raw contact that contains all of its
3019          * {@link ContactsContract.Data} rows. To access this directory
3020          * append {@link Data#CONTENT_DIRECTORY} to the raw contact URI.
3021          */
3022         public static final class Data implements BaseColumns, DataColumns {
3023             /**
3024              * no public constructor since this is a utility class
3025              */
Data()3026             private Data() {
3027             }
3028 
3029             /**
3030              * The directory twig for this sub-table
3031              */
3032             public static final String CONTENT_DIRECTORY = "data";
3033         }
3034 
3035         /**
3036          * <p>
3037          * A sub-directory of a single raw contact that contains all of its
3038          * {@link ContactsContract.Data} rows. To access this directory append
3039          * {@link RawContacts.Entity#CONTENT_DIRECTORY} to the raw contact URI. See
3040          * {@link RawContactsEntity} for a stand-alone table containing the same
3041          * data.
3042          * </p>
3043          * <p>
3044          * Entity has two ID fields: {@link #_ID} for the raw contact
3045          * and {@link #DATA_ID} for the data rows.
3046          * Entity always contains at least one row, even if there are no
3047          * actual data rows. In this case the {@link #DATA_ID} field will be
3048          * null.
3049          * </p>
3050          * <p>
3051          * Using Entity should be preferred to using two separate queries:
3052          * RawContacts followed by Data. The reason is that Entity reads all
3053          * data for a raw contact in one transaction, so there is no possibility
3054          * of the data changing between the two queries.
3055          */
3056         public static final class Entity implements BaseColumns, DataColumns {
3057             /**
3058              * no public constructor since this is a utility class
3059              */
Entity()3060             private Entity() {
3061             }
3062 
3063             /**
3064              * The directory twig for this sub-table
3065              */
3066             public static final String CONTENT_DIRECTORY = "entity";
3067 
3068             /**
3069              * The ID of the data row. The value will be null if this raw contact has no
3070              * data rows.
3071              * <P>Type: INTEGER</P>
3072              */
3073             public static final String DATA_ID = "data_id";
3074         }
3075 
3076         /**
3077          * <p>
3078          * A sub-directory of a single raw contact that contains all of its
3079          * {@link ContactsContract.StreamItems} rows. To access this directory append
3080          * {@link RawContacts.StreamItems#CONTENT_DIRECTORY} to the raw contact URI. See
3081          * {@link ContactsContract.StreamItems} for a stand-alone table containing the
3082          * same data.
3083          * </p>
3084          * <p>
3085          * Access to the social stream through this sub-directory requires additional permissions
3086          * beyond the read/write contact permissions required by the provider.  Querying for
3087          * social stream data requires android.permission.READ_SOCIAL_STREAM permission, and
3088          * inserting or updating social stream items requires android.permission.WRITE_SOCIAL_STREAM
3089          * permission.
3090          * </p>
3091          *
3092          * @deprecated - Do not use. This will not be supported in the future. In the future,
3093          * cursors returned from related queries will be empty.
3094          *
3095          * @removed
3096          */
3097         @Deprecated
3098         public static final class StreamItems implements BaseColumns, StreamItemsColumns {
3099             /**
3100              * No public constructor since this is a utility class
3101              *
3102              * @deprecated - Do not use. This will not be supported in the future. In the future,
3103              * cursors returned from related queries will be empty.
3104              */
3105             @Deprecated
StreamItems()3106             private StreamItems() {
3107             }
3108 
3109             /**
3110              * The directory twig for this sub-table
3111              *
3112              * @deprecated - Do not use. This will not be supported in the future. In the future,
3113              * cursors returned from related queries will be empty.
3114              */
3115             @Deprecated
3116             public static final String CONTENT_DIRECTORY = "stream_items";
3117         }
3118 
3119         /**
3120          * <p>
3121          * A sub-directory of a single raw contact that represents its primary
3122          * display photo.  To access this directory append
3123          * {@link RawContacts.DisplayPhoto#CONTENT_DIRECTORY} to the raw contact URI.
3124          * The resulting URI represents an image file, and should be interacted with
3125          * using ContentResolver.openAssetFileDescriptor.
3126          * <p>
3127          * <p>
3128          * Note that this sub-directory also supports opening the photo as an asset file
3129          * in write mode.  Callers can create or replace the primary photo associated
3130          * with this raw contact by opening the asset file and writing the full-size
3131          * photo contents into it.  When the file is closed, the image will be parsed,
3132          * sized down if necessary for the full-size display photo and thumbnail
3133          * dimensions, and stored.
3134          * </p>
3135          * <p>
3136          * Usage example:
3137          * <pre>
3138          * public void writeDisplayPhoto(long rawContactId, byte[] photo) {
3139          *     Uri rawContactPhotoUri = Uri.withAppendedPath(
3140          *             ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
3141          *             RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
3142          *     try {
3143          *         AssetFileDescriptor fd =
3144          *             getContentResolver().openAssetFileDescriptor(rawContactPhotoUri, "rw");
3145          *         OutputStream os = fd.createOutputStream();
3146          *         os.write(photo);
3147          *         os.close();
3148          *         fd.close();
3149          *     } catch (IOException e) {
3150          *         // Handle error cases.
3151          *     }
3152          * }
3153          * </pre>
3154          * </p>
3155          */
3156         public static final class DisplayPhoto {
3157             /**
3158              * No public constructor since this is a utility class
3159              */
DisplayPhoto()3160             private DisplayPhoto() {
3161             }
3162 
3163             /**
3164              * The directory twig for this sub-table
3165              */
3166             public static final String CONTENT_DIRECTORY = "display_photo";
3167         }
3168 
3169         /**
3170          * TODO: javadoc
3171          * @param cursor
3172          * @return
3173          */
newEntityIterator(Cursor cursor)3174         public static EntityIterator newEntityIterator(Cursor cursor) {
3175             return new EntityIteratorImpl(cursor);
3176         }
3177 
3178         private static class EntityIteratorImpl extends CursorEntityIterator {
3179             private static final String[] DATA_KEYS = new String[]{
3180                     Data.DATA1,
3181                     Data.DATA2,
3182                     Data.DATA3,
3183                     Data.DATA4,
3184                     Data.DATA5,
3185                     Data.DATA6,
3186                     Data.DATA7,
3187                     Data.DATA8,
3188                     Data.DATA9,
3189                     Data.DATA10,
3190                     Data.DATA11,
3191                     Data.DATA12,
3192                     Data.DATA13,
3193                     Data.DATA14,
3194                     Data.DATA15,
3195                     Data.SYNC1,
3196                     Data.SYNC2,
3197                     Data.SYNC3,
3198                     Data.SYNC4};
3199 
EntityIteratorImpl(Cursor cursor)3200             public EntityIteratorImpl(Cursor cursor) {
3201                 super(cursor);
3202             }
3203 
3204             @Override
getEntityAndIncrementCursor(Cursor cursor)3205             public android.content.Entity getEntityAndIncrementCursor(Cursor cursor)
3206                     throws RemoteException {
3207                 final int columnRawContactId = cursor.getColumnIndexOrThrow(RawContacts._ID);
3208                 final long rawContactId = cursor.getLong(columnRawContactId);
3209 
3210                 // we expect the cursor is already at the row we need to read from
3211                 ContentValues cv = new ContentValues();
3212                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, ACCOUNT_NAME);
3213                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, ACCOUNT_TYPE);
3214                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, DATA_SET);
3215                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, _ID);
3216                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DIRTY);
3217                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, VERSION);
3218                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SOURCE_ID);
3219                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC1);
3220                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC2);
3221                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC3);
3222                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC4);
3223                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DELETED);
3224                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, CONTACT_ID);
3225                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, STARRED);
3226                 android.content.Entity contact = new android.content.Entity(cv);
3227 
3228                 // read data rows until the contact id changes
3229                 do {
3230                     if (rawContactId != cursor.getLong(columnRawContactId)) {
3231                         break;
3232                     }
3233                     // add the data to to the contact
3234                     cv = new ContentValues();
3235                     cv.put(Data._ID, cursor.getLong(cursor.getColumnIndexOrThrow(Entity.DATA_ID)));
3236                     DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv,
3237                             Data.RES_PACKAGE);
3238                     DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Data.MIMETYPE);
3239                     DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, Data.IS_PRIMARY);
3240                     DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv,
3241                             Data.IS_SUPER_PRIMARY);
3242                     DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, Data.DATA_VERSION);
3243                     DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv,
3244                             CommonDataKinds.GroupMembership.GROUP_SOURCE_ID);
3245                     DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv,
3246                             Data.DATA_VERSION);
3247                     for (String key : DATA_KEYS) {
3248                         final int columnIndex = cursor.getColumnIndexOrThrow(key);
3249                         switch (cursor.getType(columnIndex)) {
3250                             case Cursor.FIELD_TYPE_NULL:
3251                                 // don't put anything
3252                                 break;
3253                             case Cursor.FIELD_TYPE_INTEGER:
3254                             case Cursor.FIELD_TYPE_FLOAT:
3255                             case Cursor.FIELD_TYPE_STRING:
3256                                 cv.put(key, cursor.getString(columnIndex));
3257                                 break;
3258                             case Cursor.FIELD_TYPE_BLOB:
3259                                 cv.put(key, cursor.getBlob(columnIndex));
3260                                 break;
3261                             default:
3262                                 throw new IllegalStateException("Invalid or unhandled data type");
3263                         }
3264                     }
3265                     contact.addSubValue(ContactsContract.Data.CONTENT_URI, cv);
3266                 } while (cursor.moveToNext());
3267 
3268                 return contact;
3269             }
3270 
3271         }
3272     }
3273 
3274     /**
3275      * Social status update columns.
3276      *
3277      * @see StatusUpdates
3278      * @see ContactsContract.Data
3279      */
3280     protected interface StatusColumns {
3281         /**
3282          * Contact's latest presence level.
3283          * <P>Type: INTEGER (one of the values below)</P>
3284          */
3285         public static final String PRESENCE = "mode";
3286 
3287         /**
3288          * @deprecated use {@link #PRESENCE}
3289          */
3290         @Deprecated
3291         public static final String PRESENCE_STATUS = PRESENCE;
3292 
3293         /**
3294          * An allowed value of {@link #PRESENCE}.
3295          */
3296         int OFFLINE = 0;
3297 
3298         /**
3299          * An allowed value of {@link #PRESENCE}.
3300          */
3301         int INVISIBLE = 1;
3302 
3303         /**
3304          * An allowed value of {@link #PRESENCE}.
3305          */
3306         int AWAY = 2;
3307 
3308         /**
3309          * An allowed value of {@link #PRESENCE}.
3310          */
3311         int IDLE = 3;
3312 
3313         /**
3314          * An allowed value of {@link #PRESENCE}.
3315          */
3316         int DO_NOT_DISTURB = 4;
3317 
3318         /**
3319          * An allowed value of {@link #PRESENCE}.
3320          */
3321         int AVAILABLE = 5;
3322 
3323         /**
3324          * Contact latest status update.
3325          * <p>Type: TEXT</p>
3326          */
3327         public static final String STATUS = "status";
3328 
3329         /**
3330          * @deprecated use {@link #STATUS}
3331          */
3332         @Deprecated
3333         public static final String PRESENCE_CUSTOM_STATUS = STATUS;
3334 
3335         /**
3336          * The absolute time in milliseconds when the latest status was inserted/updated.
3337          * <p>Type: NUMBER</p>
3338          */
3339         public static final String STATUS_TIMESTAMP = "status_ts";
3340 
3341         /**
3342          * The package containing resources for this status: label and icon.
3343          * <p>Type: TEXT</p>
3344          */
3345         public static final String STATUS_RES_PACKAGE = "status_res_package";
3346 
3347         /**
3348          * The resource ID of the label describing the source of the status update, e.g. "Google
3349          * Talk".  This resource should be scoped by the {@link #STATUS_RES_PACKAGE}.
3350          * <p>Type: NUMBER</p>
3351          */
3352         public static final String STATUS_LABEL = "status_label";
3353 
3354         /**
3355          * The resource ID of the icon for the source of the status update.
3356          * This resource should be scoped by the {@link #STATUS_RES_PACKAGE}.
3357          * <p>Type: NUMBER</p>
3358          */
3359         public static final String STATUS_ICON = "status_icon";
3360 
3361         /**
3362          * Contact's audio/video chat capability level.
3363          * <P>Type: INTEGER (one of the values below)</P>
3364          */
3365         public static final String CHAT_CAPABILITY = "chat_capability";
3366 
3367         /**
3368          * An allowed flag of {@link #CHAT_CAPABILITY}. Indicates audio-chat capability (microphone
3369          * and speaker)
3370          */
3371         public static final int CAPABILITY_HAS_VOICE = 1;
3372 
3373         /**
3374          * An allowed flag of {@link #CHAT_CAPABILITY}. Indicates that the contact's device can
3375          * display a video feed.
3376          */
3377         public static final int CAPABILITY_HAS_VIDEO = 2;
3378 
3379         /**
3380          * An allowed flag of {@link #CHAT_CAPABILITY}. Indicates that the contact's device has a
3381          * camera that can be used for video chat (e.g. a front-facing camera on a phone).
3382          */
3383         public static final int CAPABILITY_HAS_CAMERA = 4;
3384     }
3385 
3386     /**
3387      * <p>
3388      * Constants for the stream_items table, which contains social stream updates from
3389      * the user's contact list.
3390      * </p>
3391      * <p>
3392      * Only a certain number of stream items will ever be stored under a given raw contact.
3393      * Users of this API can query {@link ContactsContract.StreamItems#CONTENT_LIMIT_URI} to
3394      * determine this limit, and should restrict the number of items inserted in any given
3395      * transaction correspondingly.  Insertion of more items beyond the limit will
3396      * automatically lead to deletion of the oldest items, by {@link StreamItems#TIMESTAMP}.
3397      * </p>
3398      * <p>
3399      * Access to the social stream through these URIs requires additional permissions beyond the
3400      * read/write contact permissions required by the provider.  Querying for social stream data
3401      * requires android.permission.READ_SOCIAL_STREAM permission, and inserting or updating social
3402      * stream items requires android.permission.WRITE_SOCIAL_STREAM permission.
3403      * </p>
3404      * <h3>Account check</h3>
3405      * <p>
3406      * The content URIs to the insert, update and delete operations are required to have the account
3407      * information matching that of the owning raw contact as query parameters, namely
3408      * {@link RawContacts#ACCOUNT_TYPE} and {@link RawContacts#ACCOUNT_NAME}.
3409      * {@link RawContacts#DATA_SET} isn't required.
3410      * </p>
3411      * <h3>Operations</h3>
3412      * <dl>
3413      * <dt><b>Insert</b></dt>
3414      * <dd>
3415      * <p>Social stream updates are always associated with a raw contact.  There are a couple
3416      * of ways to insert these entries.
3417      * <dl>
3418      * <dt>Via the {@link RawContacts.StreamItems#CONTENT_DIRECTORY} sub-path of a raw contact:</dt>
3419      * <dd>
3420      * <pre>
3421      * ContentValues values = new ContentValues();
3422      * values.put(StreamItems.TEXT, "Breakfasted at Tiffanys");
3423      * values.put(StreamItems.TIMESTAMP, timestamp);
3424      * values.put(StreamItems.COMMENTS, "3 people reshared this");
3425      * Uri.Builder builder = RawContacts.CONTENT_URI.buildUpon();
3426      * ContentUris.appendId(builder, rawContactId);
3427      * builder.appendEncodedPath(RawContacts.StreamItems.CONTENT_DIRECTORY);
3428      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
3429      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
3430      * Uri streamItemUri = getContentResolver().insert(builder.build(), values);
3431      * long streamItemId = ContentUris.parseId(streamItemUri);
3432      * </pre>
3433      * </dd>
3434      * <dt>Via {@link StreamItems#CONTENT_URI}:</dt>
3435      * <dd>
3436      *<pre>
3437      * ContentValues values = new ContentValues();
3438      * values.put(StreamItems.RAW_CONTACT_ID, rawContactId);
3439      * values.put(StreamItems.TEXT, "Breakfasted at Tiffanys");
3440      * values.put(StreamItems.TIMESTAMP, timestamp);
3441      * values.put(StreamItems.COMMENTS, "3 people reshared this");
3442      * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
3443      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
3444      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
3445      * Uri streamItemUri = getContentResolver().insert(builder.build(), values);
3446      * long streamItemId = ContentUris.parseId(streamItemUri);
3447      *</pre>
3448      * </dd>
3449      * </dl>
3450      * </dd>
3451      * </p>
3452      * <p>
3453      * Once a {@link StreamItems} entry has been inserted, photos associated with that
3454      * social update can be inserted.  For example, after one of the insertions above,
3455      * photos could be added to the stream item in one of the following ways:
3456      * <dl>
3457      * <dt>Via a URI including the stream item ID:</dt>
3458      * <dd>
3459      * <pre>
3460      * values.clear();
3461      * values.put(StreamItemPhotos.SORT_INDEX, 1);
3462      * values.put(StreamItemPhotos.PHOTO, photoData);
3463      * getContentResolver().insert(Uri.withAppendedPath(
3464      *     ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId),
3465      *     StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), values);
3466      * </pre>
3467      * </dd>
3468      * <dt>Via {@link ContactsContract.StreamItems#CONTENT_PHOTO_URI}:</dt>
3469      * <dd>
3470      * <pre>
3471      * values.clear();
3472      * values.put(StreamItemPhotos.STREAM_ITEM_ID, streamItemId);
3473      * values.put(StreamItemPhotos.SORT_INDEX, 1);
3474      * values.put(StreamItemPhotos.PHOTO, photoData);
3475      * getContentResolver().insert(StreamItems.CONTENT_PHOTO_URI, values);
3476      * </pre>
3477      * <p>Note that this latter form allows the insertion of a stream item and its
3478      * photos in a single transaction, by using {@link ContentProviderOperation} with
3479      * back references to populate the stream item ID in the {@link ContentValues}.
3480      * </dd>
3481      * </dl>
3482      * </p>
3483      * </dd>
3484      * <dt><b>Update</b></dt>
3485      * <dd>Updates can be performed by appending the stream item ID to the
3486      * {@link StreamItems#CONTENT_URI} URI.  Only social stream entries that were
3487      * created by the calling package can be updated.</dd>
3488      * <dt><b>Delete</b></dt>
3489      * <dd>Deletes can be performed by appending the stream item ID to the
3490      * {@link StreamItems#CONTENT_URI} URI.  Only social stream entries that were
3491      * created by the calling package can be deleted.</dd>
3492      * <dt><b>Query</b></dt>
3493      * <dl>
3494      * <dt>Finding all social stream updates for a given contact</dt>
3495      * <dd>By Contact ID:
3496      * <pre>
3497      * Cursor c = getContentResolver().query(Uri.withAppendedPath(
3498      *          ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
3499      *          Contacts.StreamItems.CONTENT_DIRECTORY),
3500      *          null, null, null, null);
3501      * </pre>
3502      * </dd>
3503      * <dd>By lookup key:
3504      * <pre>
3505      * Cursor c = getContentResolver().query(Contacts.CONTENT_URI.buildUpon()
3506      *          .appendPath(lookupKey)
3507      *          .appendPath(Contacts.StreamItems.CONTENT_DIRECTORY).build(),
3508      *          null, null, null, null);
3509      * </pre>
3510      * </dd>
3511      * <dt>Finding all social stream updates for a given raw contact</dt>
3512      * <dd>
3513      * <pre>
3514      * Cursor c = getContentResolver().query(Uri.withAppendedPath(
3515      *          ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
3516      *          RawContacts.StreamItems.CONTENT_DIRECTORY)),
3517      *          null, null, null, null);
3518      * </pre>
3519      * </dd>
3520      * <dt>Querying for a specific stream item by ID</dt>
3521      * <dd>
3522      * <pre>
3523      * Cursor c = getContentResolver().query(ContentUris.withAppendedId(
3524      *          StreamItems.CONTENT_URI, streamItemId),
3525      *          null, null, null, null);
3526      * </pre>
3527      * </dd>
3528      * </dl>
3529      *
3530      * @deprecated - Do not use. This will not be supported in the future. In the future,
3531      * cursors returned from related queries will be empty.
3532      *
3533      * @removed
3534      */
3535     @Deprecated
3536     public static final class StreamItems implements BaseColumns, StreamItemsColumns {
3537         /**
3538          * This utility class cannot be instantiated
3539          *
3540          * @deprecated - Do not use. This will not be supported in the future. In the future,
3541          * cursors returned from related queries will be empty.
3542          */
3543         @Deprecated
StreamItems()3544         private StreamItems() {
3545         }
3546 
3547         /**
3548          * The content:// style URI for this table, which handles social network stream
3549          * updates for the user's contacts.
3550          *
3551          * @deprecated - Do not use. This will not be supported in the future. In the future,
3552          * cursors returned from related queries will be empty.
3553          */
3554         @Deprecated
3555         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "stream_items");
3556 
3557         /**
3558          * <p>
3559          * A content:// style URI for the photos stored in a sub-table underneath
3560          * stream items.  This is only used for inserts, and updates - queries and deletes
3561          * for photos should be performed by appending
3562          * {@link StreamItems.StreamItemPhotos#CONTENT_DIRECTORY} path to URIs for a
3563          * specific stream item.
3564          * </p>
3565          * <p>
3566          * When using this URI, the stream item ID for the photo(s) must be identified
3567          * in the {@link ContentValues} passed in.
3568          * </p>
3569          *
3570          * @deprecated - Do not use. This will not be supported in the future. In the future,
3571          * cursors returned from related queries will be empty.
3572          */
3573         @Deprecated
3574         public static final Uri CONTENT_PHOTO_URI = Uri.withAppendedPath(CONTENT_URI, "photo");
3575 
3576         /**
3577          * This URI allows the caller to query for the maximum number of stream items
3578          * that will be stored under any single raw contact.
3579          *
3580          * @deprecated - Do not use. This will not be supported in the future. In the future,
3581          * cursors returned from related queries will be empty.
3582          */
3583         @Deprecated
3584         public static final Uri CONTENT_LIMIT_URI =
3585                 Uri.withAppendedPath(AUTHORITY_URI, "stream_items_limit");
3586 
3587         /**
3588          * The MIME type of a directory of stream items.
3589          *
3590          * @deprecated - Do not use. This will not be supported in the future. In the future,
3591          * cursors returned from related queries will be empty.
3592          */
3593         @Deprecated
3594         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item";
3595 
3596         /**
3597          * The MIME type of a single stream item.
3598          *
3599          * @deprecated - Do not use. This will not be supported in the future. In the future,
3600          * cursors returned from related queries will be empty.
3601          */
3602         @Deprecated
3603         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item";
3604 
3605         /**
3606          * Queries to {@link ContactsContract.StreamItems#CONTENT_LIMIT_URI} will
3607          * contain this column, with the value indicating the maximum number of
3608          * stream items that will be stored under any single raw contact.
3609          *
3610          * @deprecated - Do not use. This will not be supported in the future. In the future,
3611          * cursors returned from related queries will be empty.
3612          */
3613         @Deprecated
3614         public static final String MAX_ITEMS = "max_items";
3615 
3616         /**
3617          * <p>
3618          * A sub-directory of a single stream item entry that contains all of its
3619          * photo rows. To access this
3620          * directory append {@link StreamItems.StreamItemPhotos#CONTENT_DIRECTORY} to
3621          * an individual stream item URI.
3622          * </p>
3623          * <p>
3624          * Access to social stream photos requires additional permissions beyond the read/write
3625          * contact permissions required by the provider.  Querying for social stream photos
3626          * requires android.permission.READ_SOCIAL_STREAM permission, and inserting or updating
3627          * social stream photos requires android.permission.WRITE_SOCIAL_STREAM permission.
3628          * </p>
3629          *
3630          * @deprecated - Do not use. This will not be supported in the future. In the future,
3631          * cursors returned from related queries will be empty.
3632          *
3633          * @removed
3634          */
3635         @Deprecated
3636         public static final class StreamItemPhotos
3637                 implements BaseColumns, StreamItemPhotosColumns {
3638             /**
3639              * No public constructor since this is a utility class
3640              *
3641              * @deprecated - Do not use. This will not be supported in the future. In the future,
3642              * cursors returned from related queries will be empty.
3643              */
3644             @Deprecated
StreamItemPhotos()3645             private StreamItemPhotos() {
3646             }
3647 
3648             /**
3649              * The directory twig for this sub-table
3650              *
3651              * @deprecated - Do not use. This will not be supported in the future. In the future,
3652              * cursors returned from related queries will be empty.
3653              */
3654             @Deprecated
3655             public static final String CONTENT_DIRECTORY = "photo";
3656 
3657             /**
3658              * The MIME type of a directory of stream item photos.
3659              *
3660              * @deprecated - Do not use. This will not be supported in the future. In the future,
3661              * cursors returned from related queries will be empty.
3662              */
3663             @Deprecated
3664             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item_photo";
3665 
3666             /**
3667              * The MIME type of a single stream item photo.
3668              *
3669              * @deprecated - Do not use. This will not be supported in the future. In the future,
3670              * cursors returned from related queries will be empty.
3671              */
3672             @Deprecated
3673             public static final String CONTENT_ITEM_TYPE
3674                     = "vnd.android.cursor.item/stream_item_photo";
3675         }
3676     }
3677 
3678     /**
3679      * Columns in the StreamItems table.
3680      *
3681      * @see ContactsContract.StreamItems
3682      * @deprecated - Do not use. This will not be supported in the future. In the future,
3683      * cursors returned from related queries will be empty.
3684      *
3685      * @removed
3686      */
3687     @Deprecated
3688     protected interface StreamItemsColumns {
3689         /**
3690          * A reference to the {@link android.provider.ContactsContract.Contacts#_ID}
3691          * that this stream item belongs to.
3692          *
3693          * <p>Type: INTEGER</p>
3694          * <p>read-only</p>
3695          *
3696          * @deprecated - Do not use. This will not be supported in the future. In the future,
3697          * cursors returned from related queries will be empty.
3698          */
3699         @Deprecated
3700         public static final String CONTACT_ID = "contact_id";
3701 
3702         /**
3703          * A reference to the {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY}
3704          * that this stream item belongs to.
3705          *
3706          * <p>Type: TEXT</p>
3707          * <p>read-only</p>
3708          *
3709          * @deprecated - Do not use. This will not be supported in the future. In the future,
3710          * cursors returned from related queries will be empty.
3711          */
3712         @Deprecated
3713         public static final String CONTACT_LOOKUP_KEY = "contact_lookup";
3714 
3715         /**
3716          * A reference to the {@link RawContacts#_ID}
3717          * that this stream item belongs to.
3718          * <p>Type: INTEGER</p>
3719          *
3720          * @deprecated - Do not use. This will not be supported in the future. In the future,
3721          * cursors returned from related queries will be empty.
3722          */
3723         @Deprecated
3724         public static final String RAW_CONTACT_ID = "raw_contact_id";
3725 
3726         /**
3727          * The package name to use when creating {@link Resources} objects for
3728          * this stream item. This value is only designed for use when building
3729          * user interfaces, and should not be used to infer the owner.
3730          * <P>Type: TEXT</P>
3731          *
3732          * @deprecated - Do not use. This will not be supported in the future. In the future,
3733          * cursors returned from related queries will be empty.
3734          */
3735         @Deprecated
3736         public static final String RES_PACKAGE = "res_package";
3737 
3738         /**
3739          * The account type to which the raw_contact of this item is associated. See
3740          * {@link RawContacts#ACCOUNT_TYPE}
3741          *
3742          * <p>Type: TEXT</p>
3743          * <p>read-only</p>
3744          *
3745          * @deprecated - Do not use. This will not be supported in the future. In the future,
3746          * cursors returned from related queries will be empty.
3747          */
3748         @Deprecated
3749         public static final String ACCOUNT_TYPE = "account_type";
3750 
3751         /**
3752          * The account name to which the raw_contact of this item is associated. See
3753          * {@link RawContacts#ACCOUNT_NAME}
3754          *
3755          * <p>Type: TEXT</p>
3756          * <p>read-only</p>
3757          *
3758          * @deprecated - Do not use. This will not be supported in the future. In the future,
3759          * cursors returned from related queries will be empty.
3760          */
3761         @Deprecated
3762         public static final String ACCOUNT_NAME = "account_name";
3763 
3764         /**
3765          * The data set within the account that the raw_contact of this row belongs to. This allows
3766          * multiple sync adapters for the same account type to distinguish between
3767          * each others' data.
3768          * {@link RawContacts#DATA_SET}
3769          *
3770          * <P>Type: TEXT</P>
3771          * <p>read-only</p>
3772          *
3773          * @deprecated - Do not use. This will not be supported in the future. In the future,
3774          * cursors returned from related queries will be empty.
3775          */
3776         @Deprecated
3777         public static final String DATA_SET = "data_set";
3778 
3779         /**
3780          * The source_id of the raw_contact that this row belongs to.
3781          * {@link RawContacts#SOURCE_ID}
3782          *
3783          * <P>Type: TEXT</P>
3784          * <p>read-only</p>
3785          *
3786          * @deprecated - Do not use. This will not be supported in the future. In the future,
3787          * cursors returned from related queries will be empty.
3788          */
3789         @Deprecated
3790         public static final String RAW_CONTACT_SOURCE_ID = "raw_contact_source_id";
3791 
3792         /**
3793          * The resource name of the icon for the source of the stream item.
3794          * This resource should be scoped by the {@link #RES_PACKAGE}. As this can only reference
3795          * drawables, the "@drawable/" prefix must be omitted.
3796          * <P>Type: TEXT</P>
3797          *
3798          * @deprecated - Do not use. This will not be supported in the future. In the future,
3799          * cursors returned from related queries will be empty.
3800          */
3801         @Deprecated
3802         public static final String RES_ICON = "icon";
3803 
3804         /**
3805          * The resource name of the label describing the source of the status update, e.g. "Google
3806          * Talk". This resource should be scoped by the {@link #RES_PACKAGE}. As this can only
3807          * reference strings, the "@string/" prefix must be omitted.
3808          * <p>Type: TEXT</p>
3809          *
3810          * @deprecated - Do not use. This will not be supported in the future. In the future,
3811          * cursors returned from related queries will be empty.
3812          */
3813         @Deprecated
3814         public static final String RES_LABEL = "label";
3815 
3816         /**
3817          * <P>
3818          * The main textual contents of the item. Typically this is content
3819          * that was posted by the source of this stream item, but it can also
3820          * be a textual representation of an action (e.g. ”Checked in at Joe's”).
3821          * This text is displayed to the user and allows formatting and embedded
3822          * resource images via HTML (as parseable via
3823          * {@link android.text.Html#fromHtml}).
3824          * </P>
3825          * <P>
3826          * Long content may be truncated and/or ellipsized - the exact behavior
3827          * is unspecified, but it should not break tags.
3828          * </P>
3829          * <P>Type: TEXT</P>
3830          *
3831          * @deprecated - Do not use. This will not be supported in the future. In the future,
3832          * cursors returned from related queries will be empty.
3833          */
3834         @Deprecated
3835         public static final String TEXT = "text";
3836 
3837         /**
3838          * The absolute time (milliseconds since epoch) when this stream item was
3839          * inserted/updated.
3840          * <P>Type: NUMBER</P>
3841          *
3842          * @deprecated - Do not use. This will not be supported in the future. In the future,
3843          * cursors returned from related queries will be empty.
3844          */
3845         @Deprecated
3846         public static final String TIMESTAMP = "timestamp";
3847 
3848         /**
3849          * <P>
3850          * Summary information about the stream item, for example to indicate how
3851          * many people have reshared it, how many have liked it, how many thumbs
3852          * up and/or thumbs down it has, what the original source was, etc.
3853          * </P>
3854          * <P>
3855          * This text is displayed to the user and allows simple formatting via
3856          * HTML, in the same manner as {@link #TEXT} allows.
3857          * </P>
3858          * <P>
3859          * Long content may be truncated and/or ellipsized - the exact behavior
3860          * is unspecified, but it should not break tags.
3861          * </P>
3862          * <P>Type: TEXT</P>
3863          *
3864          * @deprecated - Do not use. This will not be supported in the future. In the future,
3865          * cursors returned from related queries will be empty.
3866          */
3867         @Deprecated
3868         public static final String COMMENTS = "comments";
3869 
3870         /**
3871          * Generic column for use by sync adapters.
3872          *
3873          * @deprecated - Do not use. This will not be supported in the future. In the future,
3874          * cursors returned from related queries will be empty.
3875          */
3876         @Deprecated
3877         public static final String SYNC1 = "stream_item_sync1";
3878         /**
3879          * Generic column for use by sync adapters.
3880          *
3881          * @deprecated - Do not use. This will not be supported in the future. In the future,
3882          * cursors returned from related queries will be empty.
3883          */
3884         @Deprecated
3885         public static final String SYNC2 = "stream_item_sync2";
3886         /**
3887          * Generic column for use by sync adapters.
3888          *
3889          * @deprecated - Do not use. This will not be supported in the future. In the future,
3890          * cursors returned from related queries will be empty.
3891          */
3892         @Deprecated
3893         public static final String SYNC3 = "stream_item_sync3";
3894         /**
3895          * Generic column for use by sync adapters.
3896          *
3897          * @deprecated - Do not use. This will not be supported in the future. In the future,
3898          * cursors returned from related queries will be empty.
3899          */
3900         @Deprecated
3901         public static final String SYNC4 = "stream_item_sync4";
3902     }
3903 
3904     /**
3905      * <p>
3906      * Constants for the stream_item_photos table, which contains photos associated with
3907      * social stream updates.
3908      * </p>
3909      * <p>
3910      * Access to social stream photos requires additional permissions beyond the read/write
3911      * contact permissions required by the provider.  Querying for social stream photos
3912      * requires android.permission.READ_SOCIAL_STREAM permission, and inserting or updating
3913      * social stream photos requires android.permission.WRITE_SOCIAL_STREAM permission.
3914      * </p>
3915      * <h3>Account check</h3>
3916      * <p>
3917      * The content URIs to the insert, update and delete operations are required to have the account
3918      * information matching that of the owning raw contact as query parameters, namely
3919      * {@link RawContacts#ACCOUNT_TYPE} and {@link RawContacts#ACCOUNT_NAME}.
3920      * {@link RawContacts#DATA_SET} isn't required.
3921      * </p>
3922      * <h3>Operations</h3>
3923      * <dl>
3924      * <dt><b>Insert</b></dt>
3925      * <dd>
3926      * <p>Social stream photo entries are associated with a social stream item.  Photos
3927      * can be inserted into a social stream item in a couple of ways:
3928      * <dl>
3929      * <dt>
3930      * Via the {@link StreamItems.StreamItemPhotos#CONTENT_DIRECTORY} sub-path of a
3931      * stream item:
3932      * </dt>
3933      * <dd>
3934      * <pre>
3935      * ContentValues values = new ContentValues();
3936      * values.put(StreamItemPhotos.SORT_INDEX, 1);
3937      * values.put(StreamItemPhotos.PHOTO, photoData);
3938      * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
3939      * ContentUris.appendId(builder, streamItemId);
3940      * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY);
3941      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
3942      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
3943      * Uri photoUri = getContentResolver().insert(builder.build(), values);
3944      * long photoId = ContentUris.parseId(photoUri);
3945      * </pre>
3946      * </dd>
3947      * <dt>Via the {@link ContactsContract.StreamItems#CONTENT_PHOTO_URI} URI:</dt>
3948      * <dd>
3949      * <pre>
3950      * ContentValues values = new ContentValues();
3951      * values.put(StreamItemPhotos.STREAM_ITEM_ID, streamItemId);
3952      * values.put(StreamItemPhotos.SORT_INDEX, 1);
3953      * values.put(StreamItemPhotos.PHOTO, photoData);
3954      * Uri.Builder builder = StreamItems.CONTENT_PHOTO_URI.buildUpon();
3955      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
3956      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
3957      * Uri photoUri = getContentResolver().insert(builder.build(), values);
3958      * long photoId = ContentUris.parseId(photoUri);
3959      * </pre>
3960      * </dd>
3961      * </dl>
3962      * </p>
3963      * </dd>
3964      * <dt><b>Update</b></dt>
3965      * <dd>
3966      * <p>Updates can only be made against a specific {@link StreamItemPhotos} entry,
3967      * identified by both the stream item ID it belongs to and the stream item photo ID.
3968      * This can be specified in two ways.
3969      * <dl>
3970      * <dt>Via the {@link StreamItems.StreamItemPhotos#CONTENT_DIRECTORY} sub-path of a
3971      * stream item:
3972      * </dt>
3973      * <dd>
3974      * <pre>
3975      * ContentValues values = new ContentValues();
3976      * values.put(StreamItemPhotos.PHOTO, newPhotoData);
3977      * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
3978      * ContentUris.appendId(builder, streamItemId);
3979      * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY);
3980      * ContentUris.appendId(builder, streamItemPhotoId);
3981      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
3982      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
3983      * getContentResolver().update(builder.build(), values, null, null);
3984      * </pre>
3985      * </dd>
3986      * <dt>Via the {@link ContactsContract.StreamItems#CONTENT_PHOTO_URI} URI:</dt>
3987      * <dd>
3988      * <pre>
3989      * ContentValues values = new ContentValues();
3990      * values.put(StreamItemPhotos.STREAM_ITEM_ID, streamItemId);
3991      * values.put(StreamItemPhotos.PHOTO, newPhotoData);
3992      * Uri.Builder builder = StreamItems.CONTENT_PHOTO_URI.buildUpon();
3993      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
3994      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
3995      * getContentResolver().update(builder.build(), values);
3996      * </pre>
3997      * </dd>
3998      * </dl>
3999      * </p>
4000      * </dd>
4001      * <dt><b>Delete</b></dt>
4002      * <dd>Deletes can be made against either a specific photo item in a stream item, or
4003      * against all or a selected subset of photo items under a stream item.
4004      * For example:
4005      * <dl>
4006      * <dt>Deleting a single photo via the
4007      * {@link StreamItems.StreamItemPhotos#CONTENT_DIRECTORY} sub-path of a stream item:
4008      * </dt>
4009      * <dd>
4010      * <pre>
4011      * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
4012      * ContentUris.appendId(builder, streamItemId);
4013      * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY);
4014      * ContentUris.appendId(builder, streamItemPhotoId);
4015      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
4016      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
4017      * getContentResolver().delete(builder.build(), null, null);
4018      * </pre>
4019      * </dd>
4020      * <dt>Deleting all photos under a stream item</dt>
4021      * <dd>
4022      * <pre>
4023      * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
4024      * ContentUris.appendId(builder, streamItemId);
4025      * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY);
4026      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
4027      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
4028      * getContentResolver().delete(builder.build(), null, null);
4029      * </pre>
4030      * </dd>
4031      * </dl>
4032      * </dd>
4033      * <dt><b>Query</b></dt>
4034      * <dl>
4035      * <dt>Querying for a specific photo in a stream item</dt>
4036      * <dd>
4037      * <pre>
4038      * Cursor c = getContentResolver().query(
4039      *     ContentUris.withAppendedId(
4040      *         Uri.withAppendedPath(
4041      *             ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId)
4042      *             StreamItems.StreamItemPhotos#CONTENT_DIRECTORY),
4043      *         streamItemPhotoId), null, null, null, null);
4044      * </pre>
4045      * </dd>
4046      * <dt>Querying for all photos in a stream item</dt>
4047      * <dd>
4048      * <pre>
4049      * Cursor c = getContentResolver().query(
4050      *     Uri.withAppendedPath(
4051      *         ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId)
4052      *         StreamItems.StreamItemPhotos#CONTENT_DIRECTORY),
4053      *     null, null, null, StreamItemPhotos.SORT_INDEX);
4054      * </pre>
4055      * </dl>
4056      * The record will contain both a {@link StreamItemPhotos#PHOTO_FILE_ID} and a
4057      * {@link StreamItemPhotos#PHOTO_URI}.  The {@link StreamItemPhotos#PHOTO_FILE_ID}
4058      * can be used in conjunction with the {@link ContactsContract.DisplayPhoto} API to
4059      * retrieve photo content, or you can open the {@link StreamItemPhotos#PHOTO_URI} as
4060      * an asset file, as follows:
4061      * <pre>
4062      * public InputStream openDisplayPhoto(String photoUri) {
4063      *     try {
4064      *         AssetFileDescriptor fd = getContentResolver().openAssetFileDescriptor(photoUri, "r");
4065      *         return fd.createInputStream();
4066      *     } catch (IOException e) {
4067      *         return null;
4068      *     }
4069      * }
4070      * <pre>
4071      * </dd>
4072      * </dl>
4073      *
4074      * @deprecated - Do not use. This will not be supported in the future. In the future,
4075      * cursors returned from related queries will be empty.
4076      *
4077      * @removed
4078      */
4079     @Deprecated
4080     public static final class StreamItemPhotos implements BaseColumns, StreamItemPhotosColumns {
4081         /**
4082          * No public constructor since this is a utility class
4083          *
4084          * @deprecated - Do not use. This will not be supported in the future. In the future,
4085          * cursors returned from related queries will be empty.
4086          */
4087         @Deprecated
StreamItemPhotos()4088         private StreamItemPhotos() {
4089         }
4090 
4091         /**
4092          * <p>
4093          * The binary representation of the photo.  Any size photo can be inserted;
4094          * the provider will resize it appropriately for storage and display.
4095          * </p>
4096          * <p>
4097          * This is only intended for use when inserting or updating a stream item photo.
4098          * To retrieve the photo that was stored, open {@link StreamItemPhotos#PHOTO_URI}
4099          * as an asset file.
4100          * </p>
4101          * <P>Type: BLOB</P>
4102          *
4103          * @deprecated - Do not use. This will not be supported in the future. In the future,
4104          * cursors returned from related queries will be empty.
4105          */
4106         @Deprecated
4107         public static final String PHOTO = "photo";
4108     }
4109 
4110     /**
4111      * Columns in the StreamItemPhotos table.
4112      *
4113      * @see ContactsContract.StreamItemPhotos
4114      * @deprecated - Do not use. This will not be supported in the future. In the future,
4115      * cursors returned from related queries will be empty.
4116      *
4117      * @removed
4118      */
4119     @Deprecated
4120     protected interface StreamItemPhotosColumns {
4121         /**
4122          * A reference to the {@link StreamItems#_ID} this photo is associated with.
4123          * <P>Type: NUMBER</P>
4124          *
4125          * @deprecated - Do not use. This will not be supported in the future. In the future,
4126          * cursors returned from related queries will be empty.
4127          */
4128         @Deprecated
4129         public static final String STREAM_ITEM_ID = "stream_item_id";
4130 
4131         /**
4132          * An integer to use for sort order for photos in the stream item.  If not
4133          * specified, the {@link StreamItemPhotos#_ID} will be used for sorting.
4134          * <P>Type: NUMBER</P>
4135          *
4136          * @deprecated - Do not use. This will not be supported in the future. In the future,
4137          * cursors returned from related queries will be empty.
4138          */
4139         @Deprecated
4140         public static final String SORT_INDEX = "sort_index";
4141 
4142         /**
4143          * Photo file ID for the photo.
4144          * See {@link ContactsContract.DisplayPhoto}.
4145          * <P>Type: NUMBER</P>
4146          *
4147          * @deprecated - Do not use. This will not be supported in the future. In the future,
4148          * cursors returned from related queries will be empty.
4149          */
4150         @Deprecated
4151         public static final String PHOTO_FILE_ID = "photo_file_id";
4152 
4153         /**
4154          * URI for retrieving the photo content, automatically populated.  Callers
4155          * may retrieve the photo content by opening this URI as an asset file.
4156          * <P>Type: TEXT</P>
4157          *
4158          * @deprecated - Do not use. This will not be supported in the future. In the future,
4159          * cursors returned from related queries will be empty.
4160          */
4161         @Deprecated
4162         public static final String PHOTO_URI = "photo_uri";
4163 
4164         /**
4165          * Generic column for use by sync adapters.
4166          *
4167          * @deprecated - Do not use. This will not be supported in the future. In the future,
4168          * cursors returned from related queries will be empty.
4169          */
4170         @Deprecated
4171         public static final String SYNC1 = "stream_item_photo_sync1";
4172         /**
4173          * Generic column for use by sync adapters.
4174          *
4175          * @deprecated - Do not use. This will not be supported in the future. In the future,
4176          * cursors returned from related queries will be empty.
4177          */
4178         @Deprecated
4179         public static final String SYNC2 = "stream_item_photo_sync2";
4180         /**
4181          * Generic column for use by sync adapters.
4182          *
4183          * @deprecated - Do not use. This will not be supported in the future. In the future,
4184          * cursors returned from related queries will be empty.
4185          */
4186         @Deprecated
4187         public static final String SYNC3 = "stream_item_photo_sync3";
4188         /**
4189          * Generic column for use by sync adapters.
4190          *
4191          * @deprecated - Do not use. This will not be supported in the future. In the future,
4192          * cursors returned from related queries will be empty.
4193          */
4194         @Deprecated
4195         public static final String SYNC4 = "stream_item_photo_sync4";
4196     }
4197 
4198     /**
4199      * <p>
4200      * Constants for the photo files table, which tracks metadata for hi-res photos
4201      * stored in the file system.
4202      * </p>
4203      *
4204      * @hide
4205      */
4206     public static final class PhotoFiles implements BaseColumns, PhotoFilesColumns {
4207         /**
4208          * No public constructor since this is a utility class
4209          */
PhotoFiles()4210         private PhotoFiles() {
4211         }
4212     }
4213 
4214     /**
4215      * Columns in the PhotoFiles table.
4216      *
4217      * @see ContactsContract.PhotoFiles
4218      *
4219      * @hide
4220      */
4221     protected interface PhotoFilesColumns {
4222 
4223         /**
4224          * The height, in pixels, of the photo this entry is associated with.
4225          * <P>Type: NUMBER</P>
4226          */
4227         public static final String HEIGHT = "height";
4228 
4229         /**
4230          * The width, in pixels, of the photo this entry is associated with.
4231          * <P>Type: NUMBER</P>
4232          */
4233         public static final String WIDTH = "width";
4234 
4235         /**
4236          * The size, in bytes, of the photo stored on disk.
4237          * <P>Type: NUMBER</P>
4238          */
4239         public static final String FILESIZE = "filesize";
4240     }
4241 
4242     /**
4243      * Columns in the Data table.
4244      *
4245      * @see ContactsContract.Data
4246      */
4247     protected interface DataColumns {
4248         /**
4249          * The package name to use when creating {@link Resources} objects for
4250          * this data row. This value is only designed for use when building user
4251          * interfaces, and should not be used to infer the owner.
4252          */
4253         public static final String RES_PACKAGE = "res_package";
4254 
4255         /**
4256          * The MIME type of the item represented by this row.
4257          */
4258         public static final String MIMETYPE = "mimetype";
4259 
4260         /**
4261          * Hash id on the data fields, used for backup and restore.
4262          *
4263          * @hide
4264          * @deprecated This column was never public since added. It will not be supported
4265          * as of Android version {@link android.os.Build.VERSION_CODES#R}.
4266          */
4267         @Deprecated
4268         public static final String HASH_ID = "hash_id";
4269 
4270         /**
4271          * A reference to the {@link RawContacts#_ID}
4272          * that this data belongs to.
4273          */
4274         public static final String RAW_CONTACT_ID = "raw_contact_id";
4275 
4276         /**
4277          * Whether this is the primary entry of its kind for the raw contact it belongs to.
4278          * <P>Type: INTEGER (if set, non-0 means true)</P>
4279          */
4280         public static final String IS_PRIMARY = "is_primary";
4281 
4282         /**
4283          * Whether this is the primary entry of its kind for the aggregate
4284          * contact it belongs to. Any data record that is "super primary" must
4285          * also be "primary".
4286          * <P>Type: INTEGER (if set, non-0 means true)</P>
4287          */
4288         public static final String IS_SUPER_PRIMARY = "is_super_primary";
4289 
4290         /**
4291          * The "read-only" flag: "0" by default, "1" if the row cannot be modified or
4292          * deleted except by a sync adapter.  See {@link ContactsContract#CALLER_IS_SYNCADAPTER}.
4293          * <P>Type: INTEGER</P>
4294          */
4295         public static final String IS_READ_ONLY = "is_read_only";
4296 
4297         /**
4298          * The version of this data record. This is a read-only value. The data column is
4299          * guaranteed to not change without the version going up. This value is monotonically
4300          * increasing.
4301          * <P>Type: INTEGER</P>
4302          */
4303         public static final String DATA_VERSION = "data_version";
4304 
4305         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4306         public static final String DATA1 = "data1";
4307         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4308         public static final String DATA2 = "data2";
4309         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4310         public static final String DATA3 = "data3";
4311         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4312         public static final String DATA4 = "data4";
4313         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4314         public static final String DATA5 = "data5";
4315         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4316         public static final String DATA6 = "data6";
4317         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4318         public static final String DATA7 = "data7";
4319         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4320         public static final String DATA8 = "data8";
4321         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4322         public static final String DATA9 = "data9";
4323         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4324         public static final String DATA10 = "data10";
4325         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4326         public static final String DATA11 = "data11";
4327         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4328         public static final String DATA12 = "data12";
4329         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4330         public static final String DATA13 = "data13";
4331         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4332         public static final String DATA14 = "data14";
4333         /**
4334          * Generic data column, the meaning is {@link #MIMETYPE} specific. By convention,
4335          * this field is used to store BLOBs (binary data).
4336          */
4337         public static final String DATA15 = "data15";
4338 
4339         /** Generic column for use by sync adapters. */
4340         public static final String SYNC1 = "data_sync1";
4341         /** Generic column for use by sync adapters. */
4342         public static final String SYNC2 = "data_sync2";
4343         /** Generic column for use by sync adapters. */
4344         public static final String SYNC3 = "data_sync3";
4345         /** Generic column for use by sync adapters. */
4346         public static final String SYNC4 = "data_sync4";
4347 
4348         /**
4349          * Carrier presence information.
4350          * <P>
4351          * Type: INTEGER (A bitmask of CARRIER_PRESENCE_* fields)
4352          * </P>
4353          *
4354          * @deprecated The contacts database will only show presence
4355          * information on devices where
4356          * {@link android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL} is true,
4357          * otherwise use {@link android.telephony.ims.RcsUceAdapter}.
4358          */
4359         @Deprecated
4360         public static final String CARRIER_PRESENCE = "carrier_presence";
4361 
4362         /**
4363          * Indicates that the entry is Video Telephony (VT) capable on the
4364          * current carrier. An allowed bitmask of {@link #CARRIER_PRESENCE}.
4365          *
4366          * @deprecated Same as {@link DataColumns#CARRIER_PRESENCE}.
4367          *
4368          */
4369         @Deprecated
4370         public static final int CARRIER_PRESENCE_VT_CAPABLE = 0x01;
4371 
4372         /**
4373          * A reference to indicate whether phone account migration process is pending.
4374          *
4375          * Before Android 13, {@link PhoneAccountHandle#getId()} returns the ICCID for Telephony
4376          * PhoneAccountHandle. Starting from Android 13, {@link PhoneAccountHandle#getId()} returns
4377          * the Subscription ID for Telephony PhoneAccountHandle. A phone account migration process
4378          * is to ensure this PhoneAccountHandle migration process cross the Android versions in
4379          * the ContactsContract database.
4380          *
4381          * <p>Type: INTEGER</p>
4382          * @hide
4383          */
4384         String IS_PHONE_ACCOUNT_MIGRATION_PENDING = "is_preferred_phone_account_migration_pending";
4385 
4386         /**
4387          * The flattened {@link android.content.ComponentName} of a  {@link
4388          * android.telecom.PhoneAccountHandle} that is the preferred {@code PhoneAccountHandle} to
4389          * call the contact with.
4390          *
4391          * <p> On a multi-SIM device this field can be used in a {@link CommonDataKinds.Phone} row
4392          * to indicate the {@link PhoneAccountHandle} to call the number with, instead of using
4393          * {@link android.telecom.TelecomManager#getDefaultOutgoingPhoneAccount(String)} or asking
4394          * every time.
4395          *
4396          * <p>{@link android.telecom.TelecomManager#placeCall(Uri, android.os.Bundle)}
4397          * should be called with {@link android.telecom.TelecomManager#EXTRA_PHONE_ACCOUNT_HANDLE}
4398          * set to the {@link PhoneAccountHandle} using the {@link ComponentName} from this field.
4399          *
4400          * @see #PREFERRED_PHONE_ACCOUNT_ID
4401          * @see PhoneAccountHandle#getComponentName()
4402          * @see ComponentName#flattenToString()
4403          */
4404         String PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME = "preferred_phone_account_component_name";
4405 
4406         /**
4407          * The ID of a {@link
4408          * android.telecom.PhoneAccountHandle} that is the preferred {@code PhoneAccountHandle} to
4409          * call the contact with. Used by {@link CommonDataKinds.Phone}.
4410          *
4411          * <p> On a multi-SIM device this field can be used in a {@link CommonDataKinds.Phone} row
4412          * to indicate the {@link PhoneAccountHandle} to call the number with, instead of using
4413          * {@link android.telecom.TelecomManager#getDefaultOutgoingPhoneAccount(String)} or asking
4414          * every time.
4415          *
4416          * <p>{@link android.telecom.TelecomManager#placeCall(Uri, android.os.Bundle)}
4417          * should be called with {@link android.telecom.TelecomManager#EXTRA_PHONE_ACCOUNT_HANDLE}
4418          * set to the {@link PhoneAccountHandle} using the id from this field.
4419          *
4420          * @see #PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME
4421          * @see PhoneAccountHandle#getId()
4422          */
4423         String PREFERRED_PHONE_ACCOUNT_ID = "preferred_phone_account_id";
4424     }
4425 
4426     /**
4427      * Columns in the Data_Usage_Stat table
4428      */
4429     protected interface DataUsageStatColumns {
4430         /**
4431          * The last time (in milliseconds) this {@link Data} was used.
4432          * @deprecated Contacts affinity information is no longer supported as of
4433          * Android version {@link android.os.Build.VERSION_CODES#Q}.
4434          * This column always contains 0.
4435          *
4436          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
4437          * this field is obsolete, regardless of Android version. For more information, see the
4438          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
4439          * page.</p>
4440          */
4441         @Deprecated
4442         public static final String LAST_TIME_USED = "last_time_used";
4443 
4444         /**
4445          * The number of times the referenced {@link Data} has been used.
4446          * @deprecated Contacts affinity information is no longer supported as of
4447          * Android version {@link android.os.Build.VERSION_CODES#Q}.
4448          * This column always contains 0.
4449          *
4450          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
4451          * this field is obsolete, regardless of Android version. For more information, see the
4452          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
4453          * page.</p>
4454          */
4455         @Deprecated
4456         public static final String TIMES_USED = "times_used";
4457 
4458         /** @hide Raw value. */
4459         public static final String RAW_LAST_TIME_USED = HIDDEN_COLUMN_PREFIX + LAST_TIME_USED;
4460 
4461         /** @hide Raw value. */
4462         public static final String RAW_TIMES_USED = HIDDEN_COLUMN_PREFIX + TIMES_USED;
4463 
4464         /**
4465          * @hide
4466          * Low res version.  Same as {@link #LAST_TIME_USED} but use it in CP2 for clarification.
4467          */
4468         public static final String LR_LAST_TIME_USED = LAST_TIME_USED;
4469 
4470         /**
4471          * @hide
4472          * Low res version.  Same as {@link #TIMES_USED} but use it in CP2 for clarification.
4473          */
4474         public static final String LR_TIMES_USED = TIMES_USED;
4475     }
4476 
4477     /**
4478      * Combines all columns returned by {@link ContactsContract.Data} table queries.
4479      *
4480      * @see ContactsContract.Data
4481      */
4482     protected interface DataColumnsWithJoins extends BaseColumns, DataColumns, StatusColumns,
4483             RawContactsColumns, ContactsColumns, ContactNameColumns, ContactOptionsColumns,
4484             ContactStatusColumns, DataUsageStatColumns {
4485     }
4486 
4487     /**
4488      * <p>
4489      * Constants for the data table, which contains data points tied to a raw
4490      * contact.  Each row of the data table is typically used to store a single
4491      * piece of contact
4492      * information (such as a phone number) and its
4493      * associated metadata (such as whether it is a work or home number).
4494      * </p>
4495      * <h3>Data kinds</h3>
4496      * <p>
4497      * Data is a generic table that can hold any kind of contact data.
4498      * The kind of data stored in a given row is specified by the row's
4499      * {@link #MIMETYPE} value, which determines the meaning of the
4500      * generic columns {@link #DATA1} through
4501      * {@link #DATA15}.
4502      * For example, if the data kind is
4503      * {@link CommonDataKinds.Phone Phone.CONTENT_ITEM_TYPE}, then the column
4504      * {@link #DATA1} stores the
4505      * phone number, but if the data kind is
4506      * {@link CommonDataKinds.Email Email.CONTENT_ITEM_TYPE}, then {@link #DATA1}
4507      * stores the email address.
4508      * Sync adapters and applications can introduce their own data kinds.
4509      * </p>
4510      * <p>
4511      * ContactsContract defines a small number of pre-defined data kinds, e.g.
4512      * {@link CommonDataKinds.Phone}, {@link CommonDataKinds.Email} etc. As a
4513      * convenience, these classes define data kind specific aliases for DATA1 etc.
4514      * For example, {@link CommonDataKinds.Phone Phone.NUMBER} is the same as
4515      * {@link ContactsContract.Data Data.DATA1}.
4516      * </p>
4517      * <p>
4518      * {@link #DATA1} is an indexed column and should be used for the data element that is
4519      * expected to be most frequently used in query selections. For example, in the
4520      * case of a row representing email addresses {@link #DATA1} should probably
4521      * be used for the email address itself, while {@link #DATA2} etc can be
4522      * used for auxiliary information like type of email address.
4523      * <p>
4524      * <p>
4525      * By convention, {@link #DATA15} is used for storing BLOBs (binary data).
4526      * </p>
4527      * <p>
4528      * The sync adapter for a given account type must correctly handle every data type
4529      * used in the corresponding raw contacts.  Otherwise it could result in lost or
4530      * corrupted data.
4531      * </p>
4532      * <p>
4533      * Similarly, you should refrain from introducing new kinds of data for an other
4534      * party's account types. For example, if you add a data row for
4535      * "favorite song" to a raw contact owned by a Google account, it will not
4536      * get synced to the server, because the Google sync adapter does not know
4537      * how to handle this data kind. Thus new data kinds are typically
4538      * introduced along with new account types, i.e. new sync adapters.
4539      * </p>
4540      * <h3>Batch operations</h3>
4541      * <p>
4542      * Data rows can be inserted/updated/deleted using the traditional
4543      * {@link ContentResolver#insert}, {@link ContentResolver#update} and
4544      * {@link ContentResolver#delete} methods, however the newer mechanism based
4545      * on a batch of {@link ContentProviderOperation} will prove to be a better
4546      * choice in almost all cases. All operations in a batch are executed in a
4547      * single transaction, which ensures that the phone-side and server-side
4548      * state of a raw contact are always consistent. Also, the batch-based
4549      * approach is far more efficient: not only are the database operations
4550      * faster when executed in a single transaction, but also sending a batch of
4551      * commands to the content provider saves a lot of time on context switching
4552      * between your process and the process in which the content provider runs.
4553      * </p>
4554      * <p>
4555      * The flip side of using batched operations is that a large batch may lock
4556      * up the database for a long time preventing other applications from
4557      * accessing data and potentially causing ANRs ("Application Not Responding"
4558      * dialogs.)
4559      * </p>
4560      * <p>
4561      * To avoid such lockups of the database, make sure to insert "yield points"
4562      * in the batch. A yield point indicates to the content provider that before
4563      * executing the next operation it can commit the changes that have already
4564      * been made, yield to other requests, open another transaction and continue
4565      * processing operations. A yield point will not automatically commit the
4566      * transaction, but only if there is another request waiting on the
4567      * database. Normally a sync adapter should insert a yield point at the
4568      * beginning of each raw contact operation sequence in the batch. See
4569      * {@link ContentProviderOperation.Builder#withYieldAllowed(boolean)}.
4570      * </p>
4571      * <h3>Operations</h3>
4572      * <dl>
4573      * <dt><b>Insert</b></dt>
4574      * <dd>
4575      * <p>
4576      * An individual data row can be inserted using the traditional
4577      * {@link ContentResolver#insert(Uri, ContentValues)} method. Multiple rows
4578      * should always be inserted as a batch.
4579      * </p>
4580      * <p>
4581      * An example of a traditional insert:
4582      * <pre>
4583      * ContentValues values = new ContentValues();
4584      * values.put(Data.RAW_CONTACT_ID, rawContactId);
4585      * values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
4586      * values.put(Phone.NUMBER, "1-800-GOOG-411");
4587      * values.put(Phone.TYPE, Phone.TYPE_CUSTOM);
4588      * values.put(Phone.LABEL, "free directory assistance");
4589      * Uri dataUri = getContentResolver().insert(Data.CONTENT_URI, values);
4590      * </pre>
4591      * <p>
4592      * The same done using ContentProviderOperations:
4593      * <pre>
4594      * ArrayList&lt;ContentProviderOperation&gt; ops =
4595      *          new ArrayList&lt;ContentProviderOperation&gt;();
4596      *
4597      * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
4598      *          .withValue(Data.RAW_CONTACT_ID, rawContactId)
4599      *          .withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
4600      *          .withValue(Phone.NUMBER, "1-800-GOOG-411")
4601      *          .withValue(Phone.TYPE, Phone.TYPE_CUSTOM)
4602      *          .withValue(Phone.LABEL, "free directory assistance")
4603      *          .build());
4604      * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
4605      * </pre>
4606      * </p>
4607      * <dt><b>Update</b></dt>
4608      * <dd>
4609      * <p>
4610      * Just as with insert, update can be done incrementally or as a batch,
4611      * the batch mode being the preferred method:
4612      * <pre>
4613      * ArrayList&lt;ContentProviderOperation&gt; ops =
4614      *          new ArrayList&lt;ContentProviderOperation&gt;();
4615      *
4616      * ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)
4617      *          .withSelection(Data._ID + "=?", new String[]{String.valueOf(dataId)})
4618      *          .withValue(Email.DATA, "somebody@android.com")
4619      *          .build());
4620      * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
4621      * </pre>
4622      * </p>
4623      * </dd>
4624      * <dt><b>Delete</b></dt>
4625      * <dd>
4626      * <p>
4627      * Just as with insert and update, deletion can be done either using the
4628      * {@link ContentResolver#delete} method or using a ContentProviderOperation:
4629      * <pre>
4630      * ArrayList&lt;ContentProviderOperation&gt; ops =
4631      *          new ArrayList&lt;ContentProviderOperation&gt;();
4632      *
4633      * ops.add(ContentProviderOperation.newDelete(Data.CONTENT_URI)
4634      *          .withSelection(Data._ID + "=?", new String[]{String.valueOf(dataId)})
4635      *          .build());
4636      * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
4637      * </pre>
4638      * </p>
4639      * </dd>
4640      * <dt><b>Query</b></dt>
4641      * <dd>
4642      * <p>
4643      * <dl>
4644      * <dt>Finding all Data of a given type for a given contact</dt>
4645      * <dd>
4646      * <pre>
4647      * Cursor c = getContentResolver().query(Data.CONTENT_URI,
4648      *          new String[] {Data._ID, Phone.NUMBER, Phone.TYPE, Phone.LABEL},
4649      *          Data.CONTACT_ID + &quot;=?&quot; + " AND "
4650      *                  + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'",
4651      *          new String[] {String.valueOf(contactId)}, null);
4652      * </pre>
4653      * </p>
4654      * <p>
4655      * </dd>
4656      * <dt>Finding all Data of a given type for a given raw contact</dt>
4657      * <dd>
4658      * <pre>
4659      * Cursor c = getContentResolver().query(Data.CONTENT_URI,
4660      *          new String[] {Data._ID, Phone.NUMBER, Phone.TYPE, Phone.LABEL},
4661      *          Data.RAW_CONTACT_ID + &quot;=?&quot; + " AND "
4662      *                  + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'",
4663      *          new String[] {String.valueOf(rawContactId)}, null);
4664      * </pre>
4665      * </dd>
4666      * <dt>Finding all Data for a given raw contact</dt>
4667      * <dd>
4668      * Most sync adapters will want to read all data rows for a raw contact
4669      * along with the raw contact itself.  For that you should use the
4670      * {@link RawContactsEntity}. See also {@link RawContacts}.
4671      * </dd>
4672      * </dl>
4673      * </p>
4674      * </dd>
4675      * </dl>
4676      * <h2>Columns</h2>
4677      * <p>
4678      * Many columns are available via a {@link Data#CONTENT_URI} query.  For best performance you
4679      * should explicitly specify a projection to only those columns that you need.
4680      * </p>
4681      * <table class="jd-sumtable">
4682      * <tr>
4683      * <th colspan='4'>Data</th>
4684      * </tr>
4685      * <tr>
4686      * <td style="width: 7em;">long</td>
4687      * <td style="width: 20em;">{@link #_ID}</td>
4688      * <td style="width: 5em;">read-only</td>
4689      * <td>Row ID. Sync adapter should try to preserve row IDs during updates. In other words,
4690      * it would be a bad idea to delete and reinsert a data row. A sync adapter should
4691      * always do an update instead.</td>
4692      * </tr>
4693      * <tr>
4694      * <td>String</td>
4695      * <td>{@link #MIMETYPE}</td>
4696      * <td>read/write-once</td>
4697      * <td>
4698      * <p>The MIME type of the item represented by this row. Examples of common
4699      * MIME types are:
4700      * <ul>
4701      * <li>{@link CommonDataKinds.StructuredName StructuredName.CONTENT_ITEM_TYPE}</li>
4702      * <li>{@link CommonDataKinds.Phone Phone.CONTENT_ITEM_TYPE}</li>
4703      * <li>{@link CommonDataKinds.Email Email.CONTENT_ITEM_TYPE}</li>
4704      * <li>{@link CommonDataKinds.Photo Photo.CONTENT_ITEM_TYPE}</li>
4705      * <li>{@link CommonDataKinds.Organization Organization.CONTENT_ITEM_TYPE}</li>
4706      * <li>{@link CommonDataKinds.Im Im.CONTENT_ITEM_TYPE}</li>
4707      * <li>{@link CommonDataKinds.Nickname Nickname.CONTENT_ITEM_TYPE}</li>
4708      * <li>{@link CommonDataKinds.Note Note.CONTENT_ITEM_TYPE}</li>
4709      * <li>{@link CommonDataKinds.StructuredPostal StructuredPostal.CONTENT_ITEM_TYPE}</li>
4710      * <li>{@link CommonDataKinds.GroupMembership GroupMembership.CONTENT_ITEM_TYPE}</li>
4711      * <li>{@link CommonDataKinds.Website Website.CONTENT_ITEM_TYPE}</li>
4712      * <li>{@link CommonDataKinds.Event Event.CONTENT_ITEM_TYPE}</li>
4713      * <li>{@link CommonDataKinds.Relation Relation.CONTENT_ITEM_TYPE}</li>
4714      * <li>{@link CommonDataKinds.SipAddress SipAddress.CONTENT_ITEM_TYPE}</li>
4715      * </ul>
4716      * </p>
4717      * </td>
4718      * </tr>
4719      * <tr>
4720      * <td>long</td>
4721      * <td>{@link #RAW_CONTACT_ID}</td>
4722      * <td>read/write-once</td>
4723      * <td>The id of the row in the {@link RawContacts} table that this data belongs to.</td>
4724      * </tr>
4725      * <tr>
4726      * <td>int</td>
4727      * <td>{@link #IS_PRIMARY}</td>
4728      * <td>read/write</td>
4729      * <td>Whether this is the primary entry of its kind for the raw contact it belongs to.
4730      * "1" if true, "0" if false.
4731      * </td>
4732      * </tr>
4733      * <tr>
4734      * <td>int</td>
4735      * <td>{@link #IS_SUPER_PRIMARY}</td>
4736      * <td>read/write</td>
4737      * <td>Whether this is the primary entry of its kind for the aggregate
4738      * contact it belongs to. Any data record that is "super primary" must
4739      * also be "primary".  For example, the super-primary entry may be
4740      * interpreted as the default contact value of its kind (for example,
4741      * the default phone number to use for the contact).</td>
4742      * </tr>
4743      * <tr>
4744      * <td>int</td>
4745      * <td>{@link #DATA_VERSION}</td>
4746      * <td>read-only</td>
4747      * <td>The version of this data record. Whenever the data row changes
4748      * the version goes up. This value is monotonically increasing.</td>
4749      * </tr>
4750      * <tr>
4751      * <td>Any type</td>
4752      * <td>
4753      * {@link #DATA1}<br>
4754      * {@link #DATA2}<br>
4755      * {@link #DATA3}<br>
4756      * {@link #DATA4}<br>
4757      * {@link #DATA5}<br>
4758      * {@link #DATA6}<br>
4759      * {@link #DATA7}<br>
4760      * {@link #DATA8}<br>
4761      * {@link #DATA9}<br>
4762      * {@link #DATA10}<br>
4763      * {@link #DATA11}<br>
4764      * {@link #DATA12}<br>
4765      * {@link #DATA13}<br>
4766      * {@link #DATA14}<br>
4767      * {@link #DATA15}
4768      * </td>
4769      * <td>read/write</td>
4770      * <td>
4771      * <p>
4772      * Generic data columns.  The meaning of each column is determined by the
4773      * {@link #MIMETYPE}.  By convention, {@link #DATA15} is used for storing
4774      * BLOBs (binary data).
4775      * </p>
4776      * <p>
4777      * Data columns whose meaning is not explicitly defined for a given MIMETYPE
4778      * should not be used.  There is no guarantee that any sync adapter will
4779      * preserve them.  Sync adapters themselves should not use such columns either,
4780      * but should instead use {@link #SYNC1}-{@link #SYNC4}.
4781      * </p>
4782      * </td>
4783      * </tr>
4784      * <tr>
4785      * <td>Any type</td>
4786      * <td>
4787      * {@link #SYNC1}<br>
4788      * {@link #SYNC2}<br>
4789      * {@link #SYNC3}<br>
4790      * {@link #SYNC4}
4791      * </td>
4792      * <td>read/write</td>
4793      * <td>Generic columns for use by sync adapters. For example, a Photo row
4794      * may store the image URL in SYNC1, a status (not loaded, loading, loaded, error)
4795      * in SYNC2, server-side version number in SYNC3 and error code in SYNC4.</td>
4796      * </tr>
4797      * </table>
4798      *
4799      * <p>
4800      * Some columns from the most recent associated status update are also available
4801      * through an implicit join.
4802      * </p>
4803      * <table class="jd-sumtable">
4804      * <tr>
4805      * <th colspan='4'>Join with {@link StatusUpdates}</th>
4806      * </tr>
4807      * <tr>
4808      * <td style="width: 7em;">int</td>
4809      * <td style="width: 20em;">{@link #PRESENCE}</td>
4810      * <td style="width: 5em;">read-only</td>
4811      * <td>IM presence status linked to this data row. Compare with
4812      * {@link #CONTACT_PRESENCE}, which contains the contact's presence across
4813      * all IM rows. See {@link StatusUpdates} for individual status definitions.
4814      * The provider may choose not to store this value
4815      * in persistent storage. The expectation is that presence status will be
4816      * updated on a regular basis.
4817      * </td>
4818      * </tr>
4819      * <tr>
4820      * <td>String</td>
4821      * <td>{@link #STATUS}</td>
4822      * <td>read-only</td>
4823      * <td>Latest status update linked with this data row.</td>
4824      * </tr>
4825      * <tr>
4826      * <td>long</td>
4827      * <td>{@link #STATUS_TIMESTAMP}</td>
4828      * <td>read-only</td>
4829      * <td>The absolute time in milliseconds when the latest status was
4830      * inserted/updated for this data row.</td>
4831      * </tr>
4832      * <tr>
4833      * <td>String</td>
4834      * <td>{@link #STATUS_RES_PACKAGE}</td>
4835      * <td>read-only</td>
4836      * <td>The package containing resources for this status: label and icon.</td>
4837      * </tr>
4838      * <tr>
4839      * <td>long</td>
4840      * <td>{@link #STATUS_LABEL}</td>
4841      * <td>read-only</td>
4842      * <td>The resource ID of the label describing the source of status update linked
4843      * to this data row. This resource is scoped by the {@link #STATUS_RES_PACKAGE}.</td>
4844      * </tr>
4845      * <tr>
4846      * <td>long</td>
4847      * <td>{@link #STATUS_ICON}</td>
4848      * <td>read-only</td>
4849      * <td>The resource ID of the icon for the source of the status update linked
4850      * to this data row. This resource is scoped by the {@link #STATUS_RES_PACKAGE}.</td>
4851      * </tr>
4852      * </table>
4853      *
4854      * <p>
4855      * Some columns from the associated raw contact are also available through an
4856      * implicit join.  The other columns are excluded as uninteresting in this
4857      * context.
4858      * </p>
4859      *
4860      * <table class="jd-sumtable">
4861      * <tr>
4862      * <th colspan='4'>Join with {@link ContactsContract.RawContacts}</th>
4863      * </tr>
4864      * <tr>
4865      * <td style="width: 7em;">long</td>
4866      * <td style="width: 20em;">{@link #CONTACT_ID}</td>
4867      * <td style="width: 5em;">read-only</td>
4868      * <td>The id of the row in the {@link Contacts} table that this data belongs
4869      * to.</td>
4870      * </tr>
4871      * <tr>
4872      * <td>int</td>
4873      * <td>{@link #AGGREGATION_MODE}</td>
4874      * <td>read-only</td>
4875      * <td>See {@link RawContacts}.</td>
4876      * </tr>
4877      * <tr>
4878      * <td>int</td>
4879      * <td>{@link #DELETED}</td>
4880      * <td>read-only</td>
4881      * <td>See {@link RawContacts}.</td>
4882      * </tr>
4883      * </table>
4884      *
4885      * <p>
4886      * The ID column for the associated aggregated contact table
4887      * {@link ContactsContract.Contacts} is available
4888      * via the implicit join to the {@link RawContacts} table, see above.
4889      * The remaining columns from this table are also
4890      * available, through an implicit join.  This
4891      * facilitates lookup by
4892      * the value of a single data element, such as the email address.
4893      * </p>
4894      *
4895      * <table class="jd-sumtable">
4896      * <tr>
4897      * <th colspan='4'>Join with {@link ContactsContract.Contacts}</th>
4898      * </tr>
4899      * <tr>
4900      * <td style="width: 7em;">String</td>
4901      * <td style="width: 20em;">{@link #LOOKUP_KEY}</td>
4902      * <td style="width: 5em;">read-only</td>
4903      * <td>See {@link ContactsContract.Contacts}</td>
4904      * </tr>
4905      * <tr>
4906      * <td>String</td>
4907      * <td>{@link #DISPLAY_NAME}</td>
4908      * <td>read-only</td>
4909      * <td>See {@link ContactsContract.Contacts}</td>
4910      * </tr>
4911      * <tr>
4912      * <td>long</td>
4913      * <td>{@link #PHOTO_ID}</td>
4914      * <td>read-only</td>
4915      * <td>See {@link ContactsContract.Contacts}.</td>
4916      * </tr>
4917      * <tr>
4918      * <td>int</td>
4919      * <td>{@link #IN_VISIBLE_GROUP}</td>
4920      * <td>read-only</td>
4921      * <td>See {@link ContactsContract.Contacts}.</td>
4922      * </tr>
4923      * <tr>
4924      * <td>int</td>
4925      * <td>{@link #HAS_PHONE_NUMBER}</td>
4926      * <td>read-only</td>
4927      * <td>See {@link ContactsContract.Contacts}.</td>
4928      * </tr>
4929      * <tr>
4930      * <td>int</td>
4931      * <td>{@link #STARRED}</td>
4932      * <td>read-only</td>
4933      * <td>See {@link ContactsContract.Contacts}.</td>
4934      * </tr>
4935      * <tr>
4936      * <td>String</td>
4937      * <td>{@link #CUSTOM_RINGTONE}</td>
4938      * <td>read-only</td>
4939      * <td>See {@link ContactsContract.Contacts}.</td>
4940      * </tr>
4941      * <tr>
4942      * <td>int</td>
4943      * <td>{@link #SEND_TO_VOICEMAIL}</td>
4944      * <td>read-only</td>
4945      * <td>See {@link ContactsContract.Contacts}.</td>
4946      * </tr>
4947      * <tr>
4948      * <td>int</td>
4949      * <td>{@link #CONTACT_PRESENCE}</td>
4950      * <td>read-only</td>
4951      * <td>See {@link ContactsContract.Contacts}.</td>
4952      * </tr>
4953      * <tr>
4954      * <td>String</td>
4955      * <td>{@link #CONTACT_STATUS}</td>
4956      * <td>read-only</td>
4957      * <td>See {@link ContactsContract.Contacts}.</td>
4958      * </tr>
4959      * <tr>
4960      * <td>long</td>
4961      * <td>{@link #CONTACT_STATUS_TIMESTAMP}</td>
4962      * <td>read-only</td>
4963      * <td>See {@link ContactsContract.Contacts}.</td>
4964      * </tr>
4965      * <tr>
4966      * <td>String</td>
4967      * <td>{@link #CONTACT_STATUS_RES_PACKAGE}</td>
4968      * <td>read-only</td>
4969      * <td>See {@link ContactsContract.Contacts}.</td>
4970      * </tr>
4971      * <tr>
4972      * <td>long</td>
4973      * <td>{@link #CONTACT_STATUS_LABEL}</td>
4974      * <td>read-only</td>
4975      * <td>See {@link ContactsContract.Contacts}.</td>
4976      * </tr>
4977      * <tr>
4978      * <td>long</td>
4979      * <td>{@link #CONTACT_STATUS_ICON}</td>
4980      * <td>read-only</td>
4981      * <td>See {@link ContactsContract.Contacts}.</td>
4982      * </tr>
4983      * </table>
4984      */
4985     public final static class Data implements DataColumnsWithJoins, ContactCounts {
4986         /**
4987          * This utility class cannot be instantiated
4988          */
Data()4989         private Data() {}
4990 
4991         /**
4992          * The content:// style URI for this table, which requests a directory
4993          * of data rows matching the selection criteria.
4994          */
4995         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "data");
4996 
4997         /**
4998         * The content:// style URI for this table in managed profile, which requests a directory
4999         * of data rows matching the selection criteria.
5000         *
5001         * @hide
5002         */
5003         static final Uri ENTERPRISE_CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
5004                 "data_enterprise");
5005 
5006         /**
5007          * A boolean parameter for {@link Data#CONTENT_URI}.
5008          * This specifies whether or not the returned data items should be filtered to show
5009          * data items belonging to visible contacts only.
5010          */
5011         public static final String VISIBLE_CONTACTS_ONLY = "visible_contacts_only";
5012 
5013         /**
5014          * The MIME type of the results from {@link #CONTENT_URI}.
5015          */
5016         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/data";
5017 
5018         /**
5019          * <p>
5020          * Build a {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}
5021          * style {@link Uri} for the parent {@link android.provider.ContactsContract.Contacts}
5022          * entry of the given {@link ContactsContract.Data} entry.
5023          * </p>
5024          * <p>
5025          * Returns the Uri for the contact in the first entry returned by
5026          * {@link ContentResolver#query(Uri, String[], String, String[], String)}
5027          * for the provided {@code dataUri}.  If the query returns null or empty
5028          * results, silently returns null.
5029          * </p>
5030          */
getContactLookupUri(ContentResolver resolver, Uri dataUri)5031         public static Uri getContactLookupUri(ContentResolver resolver, Uri dataUri) {
5032             final Cursor cursor = resolver.query(dataUri, new String[] {
5033                     RawContacts.CONTACT_ID, Contacts.LOOKUP_KEY
5034             }, null, null, null);
5035 
5036             Uri lookupUri = null;
5037             try {
5038                 if (cursor != null && cursor.moveToFirst()) {
5039                     final long contactId = cursor.getLong(0);
5040                     final String lookupKey = cursor.getString(1);
5041                     return Contacts.getLookupUri(contactId, lookupKey);
5042                 }
5043             } finally {
5044                 if (cursor != null) cursor.close();
5045             }
5046             return lookupUri;
5047         }
5048     }
5049 
5050     /**
5051      * <p>
5052      * Constants for the raw contacts entities table, which can be thought of as
5053      * an outer join of the raw_contacts table with the data table.  It is a strictly
5054      * read-only table.
5055      * </p>
5056      * <p>
5057      * If a raw contact has data rows, the RawContactsEntity cursor will contain
5058      * a one row for each data row. If the raw contact has no data rows, the
5059      * cursor will still contain one row with the raw contact-level information
5060      * and nulls for data columns.
5061      *
5062      * <pre>
5063      * Uri entityUri = ContentUris.withAppendedId(RawContactsEntity.CONTENT_URI, rawContactId);
5064      * Cursor c = getContentResolver().query(entityUri,
5065      *          new String[]{
5066      *              RawContactsEntity.SOURCE_ID,
5067      *              RawContactsEntity.DATA_ID,
5068      *              RawContactsEntity.MIMETYPE,
5069      *              RawContactsEntity.DATA1
5070      *          }, null, null, null);
5071      * try {
5072      *     while (c.moveToNext()) {
5073      *         String sourceId = c.getString(0);
5074      *         if (!c.isNull(1)) {
5075      *             String mimeType = c.getString(2);
5076      *             String data = c.getString(3);
5077      *             ...
5078      *         }
5079      *     }
5080      * } finally {
5081      *     c.close();
5082      * }
5083      * </pre>
5084      *
5085      * <h3>Columns</h3>
5086      * RawContactsEntity has a combination of RawContact and Data columns.
5087      *
5088      * <table class="jd-sumtable">
5089      * <tr>
5090      * <th colspan='4'>RawContacts</th>
5091      * </tr>
5092      * <tr>
5093      * <td style="width: 7em;">long</td>
5094      * <td style="width: 20em;">{@link #_ID}</td>
5095      * <td style="width: 5em;">read-only</td>
5096      * <td>Raw contact row ID. See {@link RawContacts}.</td>
5097      * </tr>
5098      * <tr>
5099      * <td>long</td>
5100      * <td>{@link #CONTACT_ID}</td>
5101      * <td>read-only</td>
5102      * <td>See {@link RawContacts}.</td>
5103      * </tr>
5104      * <tr>
5105      * <td>int</td>
5106      * <td>{@link #AGGREGATION_MODE}</td>
5107      * <td>read-only</td>
5108      * <td>See {@link RawContacts}.</td>
5109      * </tr>
5110      * <tr>
5111      * <td>int</td>
5112      * <td>{@link #DELETED}</td>
5113      * <td>read-only</td>
5114      * <td>See {@link RawContacts}.</td>
5115      * </tr>
5116      * </table>
5117      *
5118      * <table class="jd-sumtable">
5119      * <tr>
5120      * <th colspan='4'>Data</th>
5121      * </tr>
5122      * <tr>
5123      * <td style="width: 7em;">long</td>
5124      * <td style="width: 20em;">{@link #DATA_ID}</td>
5125      * <td style="width: 5em;">read-only</td>
5126      * <td>Data row ID. It will be null if the raw contact has no data rows.</td>
5127      * </tr>
5128      * <tr>
5129      * <td>String</td>
5130      * <td>{@link #MIMETYPE}</td>
5131      * <td>read-only</td>
5132      * <td>See {@link ContactsContract.Data}.</td>
5133      * </tr>
5134      * <tr>
5135      * <td>int</td>
5136      * <td>{@link #IS_PRIMARY}</td>
5137      * <td>read-only</td>
5138      * <td>See {@link ContactsContract.Data}.</td>
5139      * </tr>
5140      * <tr>
5141      * <td>int</td>
5142      * <td>{@link #IS_SUPER_PRIMARY}</td>
5143      * <td>read-only</td>
5144      * <td>See {@link ContactsContract.Data}.</td>
5145      * </tr>
5146      * <tr>
5147      * <td>int</td>
5148      * <td>{@link #DATA_VERSION}</td>
5149      * <td>read-only</td>
5150      * <td>See {@link ContactsContract.Data}.</td>
5151      * </tr>
5152      * <tr>
5153      * <td>Any type</td>
5154      * <td>
5155      * {@link #DATA1}<br>
5156      * {@link #DATA2}<br>
5157      * {@link #DATA3}<br>
5158      * {@link #DATA4}<br>
5159      * {@link #DATA5}<br>
5160      * {@link #DATA6}<br>
5161      * {@link #DATA7}<br>
5162      * {@link #DATA8}<br>
5163      * {@link #DATA9}<br>
5164      * {@link #DATA10}<br>
5165      * {@link #DATA11}<br>
5166      * {@link #DATA12}<br>
5167      * {@link #DATA13}<br>
5168      * {@link #DATA14}<br>
5169      * {@link #DATA15}
5170      * </td>
5171      * <td>read-only</td>
5172      * <td>See {@link ContactsContract.Data}.</td>
5173      * </tr>
5174      * <tr>
5175      * <td>Any type</td>
5176      * <td>
5177      * {@link #SYNC1}<br>
5178      * {@link #SYNC2}<br>
5179      * {@link #SYNC3}<br>
5180      * {@link #SYNC4}
5181      * </td>
5182      * <td>read-only</td>
5183      * <td>See {@link ContactsContract.Data}.</td>
5184      * </tr>
5185      * </table>
5186      */
5187     public final static class RawContactsEntity
5188             implements BaseColumns, DataColumns, RawContactsColumns {
5189         private static final String TAG = "ContactsContract.RawContactsEntity";
5190 
5191         /**
5192          * This utility class cannot be instantiated
5193          */
RawContactsEntity()5194         private RawContactsEntity() {}
5195 
5196         /**
5197          * The content:// style URI for this table
5198          */
5199         public static final Uri CONTENT_URI =
5200                 Uri.withAppendedPath(AUTHORITY_URI, "raw_contact_entities");
5201 
5202         /**
5203         * The content:// style URI for this table in the managed profile
5204         *
5205         * @hide
5206         */
5207         @TestApi
5208         public static final Uri CORP_CONTENT_URI =
5209                 Uri.withAppendedPath(AUTHORITY_URI, "raw_contact_entities_corp");
5210 
5211         /**
5212          * The content:// style URI for this table, specific to the user's profile.
5213          */
5214         public static final Uri PROFILE_CONTENT_URI =
5215                 Uri.withAppendedPath(Profile.CONTENT_URI, "raw_contact_entities");
5216 
5217         /**
5218          * The MIME type of {@link #CONTENT_URI} providing a directory of raw contact entities.
5219          */
5220         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact_entity";
5221 
5222         /**
5223          * If {@link #FOR_EXPORT_ONLY} is explicitly set to "1", returned Cursor toward
5224          * Data.CONTENT_URI contains only exportable data.
5225          *
5226          * This flag is useful (currently) only for vCard exporter in Contacts app, which
5227          * needs to exclude "un-exportable" data from available data to export, while
5228          * Contacts app itself has priviledge to access all data including "un-expotable"
5229          * ones and providers return all of them regardless of the callers' intention.
5230          * <P>Type: INTEGER</p>
5231          *
5232          * @hide Maybe available only in Eclair and not really ready for public use.
5233          * TODO: remove, or implement this feature completely. As of now (Eclair),
5234          * we only use this flag in queryEntities(), not query().
5235          */
5236         public static final String FOR_EXPORT_ONLY = "for_export_only";
5237 
5238         /**
5239          * The ID of the data column. The value will be null if this raw contact has no data rows.
5240          * <P>Type: INTEGER</P>
5241          */
5242         public static final String DATA_ID = "data_id";
5243 
5244         /**
5245          * Query raw contacts entity by a contact ID, which can potentially be a managed profile
5246          * contact ID.
5247          * <p>
5248          * @param contentResolver The content resolver to query
5249          * @param contactId Contact ID, which can potentially be a managed profile contact ID.
5250          * @return A map from a mimetype to a list of the entity content values.
5251          *
5252          * {@hide}
5253          */
5254         @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
5255         @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
queryRawContactEntity( @onNull ContentResolver contentResolver, long contactId)5256         public static @NonNull Map<String, List<ContentValues>> queryRawContactEntity(
5257                 @NonNull ContentResolver contentResolver, long contactId) {
5258             Uri uri = RawContactsEntity.CONTENT_URI;
5259             long realContactId = contactId;
5260 
5261             if (Contacts.isEnterpriseContactId(contactId)) {
5262                 uri = RawContactsEntity.CORP_CONTENT_URI;
5263                 realContactId = contactId - Contacts.ENTERPRISE_CONTACT_ID_BASE;
5264             }
5265             final Map<String, List<ContentValues>> contentValuesListMap =
5266                     new HashMap<String, List<ContentValues>>();
5267             // The resolver may return the entity iterator with no data. It is possible.
5268             // e.g. If all the data in the contact of the given contact id are not exportable ones,
5269             //      they are hidden from the view of this method, though contact id itself exists.
5270             EntityIterator entityIterator = null;
5271             try {
5272                 final String selection = Data.CONTACT_ID + "=?";
5273                 final String[] selectionArgs = new String[] {String.valueOf(realContactId)};
5274 
5275                 entityIterator = RawContacts.newEntityIterator(contentResolver.query(
5276                             uri, null, selection, selectionArgs, null));
5277 
5278                 if (entityIterator == null) {
5279                     Log.e(TAG, "EntityIterator is null");
5280                     return contentValuesListMap;
5281                 }
5282 
5283                 if (!entityIterator.hasNext()) {
5284                     Log.w(TAG, "Data does not exist. contactId: " + realContactId);
5285                     return contentValuesListMap;
5286                 }
5287 
5288                 while (entityIterator.hasNext()) {
5289                     Entity entity = entityIterator.next();
5290                     for (NamedContentValues namedContentValues : entity.getSubValues()) {
5291                         ContentValues contentValues = namedContentValues.values;
5292                         String key = contentValues.getAsString(Data.MIMETYPE);
5293                         if (key != null) {
5294                             List<ContentValues> contentValuesList = contentValuesListMap.get(key);
5295                             if (contentValuesList == null) {
5296                                 contentValuesList = new ArrayList<ContentValues>();
5297                                 contentValuesListMap.put(key, contentValuesList);
5298                             }
5299                             contentValuesList.add(contentValues);
5300                         }
5301                     }
5302                 }
5303             } finally {
5304                 if (entityIterator != null) {
5305                     entityIterator.close();
5306                 }
5307             }
5308             return contentValuesListMap;
5309         }
5310     }
5311 
5312     /**
5313      * @see PhoneLookup
5314      */
5315     protected interface PhoneLookupColumns {
5316         /**
5317          *  The ID of the data row.
5318          *  <P>Type: INTEGER</P>
5319          */
5320         public static final String DATA_ID = "data_id";
5321         /**
5322          * A reference to the {@link ContactsContract.Contacts#_ID} that this
5323          * data belongs to.
5324          * <P>Type: INTEGER</P>
5325          */
5326         public static final String CONTACT_ID = "contact_id";
5327         /**
5328          * The phone number as the user entered it.
5329          * <P>Type: TEXT</P>
5330          */
5331         public static final String NUMBER = "number";
5332 
5333         /**
5334          * The type of phone number, for example Home or Work.
5335          * <P>Type: INTEGER</P>
5336          */
5337         public static final String TYPE = "type";
5338 
5339         /**
5340          * The user defined label for the phone number.
5341          * <P>Type: TEXT</P>
5342          */
5343         public static final String LABEL = "label";
5344 
5345         /**
5346          * The phone number's E164 representation.
5347          * <P>Type: TEXT</P>
5348          */
5349         public static final String NORMALIZED_NUMBER = "normalized_number";
5350     }
5351 
5352     /**
5353      * A table that represents the result of looking up a phone number, for
5354      * example for caller ID. To perform a lookup you must append the number you
5355      * want to find to {@link #CONTENT_FILTER_URI}.  This query is highly
5356      * optimized.
5357      * <pre>
5358      * Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
5359      * resolver.query(uri, new String[]{PhoneLookup.DISPLAY_NAME,...
5360      * </pre>
5361      *
5362      * <h3>Columns</h3>
5363      *
5364      * <table class="jd-sumtable">
5365      * <tr>
5366      * <th colspan='4'>PhoneLookup</th>
5367      * </tr>
5368      * <tr>
5369      * <td>String</td>
5370      * <td>{@link #NUMBER}</td>
5371      * <td>read-only</td>
5372      * <td>Phone number.</td>
5373      * </tr>
5374      * <tr>
5375      * <td>String</td>
5376      * <td>{@link #TYPE}</td>
5377      * <td>read-only</td>
5378      * <td>Phone number type. See {@link CommonDataKinds.Phone}.</td>
5379      * </tr>
5380      * <tr>
5381      * <td>String</td>
5382      * <td>{@link #LABEL}</td>
5383      * <td>read-only</td>
5384      * <td>Custom label for the phone number. See {@link CommonDataKinds.Phone}.</td>
5385      * </tr>
5386      * </table>
5387      * <p>
5388      * Columns from the Contacts table are also available through a join.
5389      * </p>
5390      * <table class="jd-sumtable">
5391      * <tr>
5392      * <th colspan='4'>Join with {@link Contacts}</th>
5393      * </tr>
5394      * <tr>
5395      * <td>long</td>
5396      * <td>{@link #_ID}</td>
5397      * <td>read-only</td>
5398      * <td>Contact ID.</td>
5399      * </tr>
5400      * <tr>
5401      * <td>long</td>
5402      * <td>{@link #CONTACT_ID}</td>
5403      * <td>read-only</td>
5404      * <td>Contact ID.</td>
5405      * </tr>
5406      * <tr>
5407      * <td>long</td>
5408      * <td>{@link #DATA_ID}</td>
5409      * <td>read-only</td>
5410      * <td>Data ID.</td>
5411      * </tr>
5412      * <tr>
5413      * <td>String</td>
5414      * <td>{@link #LOOKUP_KEY}</td>
5415      * <td>read-only</td>
5416      * <td>See {@link ContactsContract.Contacts}</td>
5417      * </tr>
5418      * <tr>
5419      * <td>String</td>
5420      * <td>{@link #DISPLAY_NAME}</td>
5421      * <td>read-only</td>
5422      * <td>See {@link ContactsContract.Contacts}</td>
5423      * </tr>
5424      * <tr>
5425      * <td>long</td>
5426      * <td>{@link #PHOTO_ID}</td>
5427      * <td>read-only</td>
5428      * <td>See {@link ContactsContract.Contacts}.</td>
5429      * </tr>
5430      * <tr>
5431      * <td>int</td>
5432      * <td>{@link #IN_VISIBLE_GROUP}</td>
5433      * <td>read-only</td>
5434      * <td>See {@link ContactsContract.Contacts}.</td>
5435      * </tr>
5436      * <tr>
5437      * <td>int</td>
5438      * <td>{@link #HAS_PHONE_NUMBER}</td>
5439      * <td>read-only</td>
5440      * <td>See {@link ContactsContract.Contacts}.</td>
5441      * </tr>
5442      * <tr>
5443      * <td>int</td>
5444      * <td>{@link #STARRED}</td>
5445      * <td>read-only</td>
5446      * <td>See {@link ContactsContract.Contacts}.</td>
5447      * </tr>
5448      * <tr>
5449      * <td>String</td>
5450      * <td>{@link #CUSTOM_RINGTONE}</td>
5451      * <td>read-only</td>
5452      * <td>See {@link ContactsContract.Contacts}.</td>
5453      * </tr>
5454      * <tr>
5455      * <td>int</td>
5456      * <td>{@link #SEND_TO_VOICEMAIL}</td>
5457      * <td>read-only</td>
5458      * <td>See {@link ContactsContract.Contacts}.</td>
5459      * </tr>
5460      * </table>
5461      */
5462     public static final class PhoneLookup implements BaseColumns, PhoneLookupColumns,
5463             ContactsColumns, ContactOptionsColumns, ContactNameColumns {
5464         /**
5465          * This utility class cannot be instantiated
5466          */
PhoneLookup()5467         private PhoneLookup() {}
5468 
5469         /**
5470          * The content:// style URI for this table.
5471          *
5472          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
5473          * field doesn't sort results based on contacts frequency. For more information, see the
5474          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
5475          * page.
5476          *
5477          * Append the phone number you want to lookup
5478          * to this URI and query it to perform a lookup. For example:
5479          * <pre>
5480          * Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
5481          *         Uri.encode(phoneNumber));
5482          * </pre>
5483          */
5484         public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(AUTHORITY_URI,
5485                 "phone_lookup");
5486 
5487         /**
5488          * URI used for looking up contacts by phone number on the contact databases of both the
5489          * calling user and the managed profile that is linked to it.
5490          * <p>
5491          * It supports the same semantics as {@link #CONTENT_FILTER_URI} and returns the same
5492          * columns.<br>
5493          * If the device has no managed profile that is linked to the calling user, it behaves in
5494          * the exact same way as {@link #CONTENT_FILTER_URI}.<br>
5495          * If there is a managed profile linked to the calling user, it first queries the calling
5496          * user's contact database, and only if no matching contacts are found there it then queries
5497          * the managed profile database.
5498          * <p class="caution">
5499          * <b>Caution: </b>If you publish your app to the Google Play Store, this field doesn't sort
5500          * results based on contacts frequency. For more information, see the
5501          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
5502          * page.
5503          * <p>
5504          * If a result is from the managed profile, the following changes are made to the data:
5505          * <ul>
5506          *     <li>{@link #PHOTO_THUMBNAIL_URI} and {@link #PHOTO_URI} will be rewritten to special
5507          *     URIs. Use {@link ContentResolver#openAssetFileDescriptor} or its siblings to
5508          *     load pictures from them.
5509          *     <li>{@link #PHOTO_ID} and {@link #PHOTO_FILE_ID} will be set to null. Don't use them.
5510          *     <li>{@link #CONTACT_ID} and {@link #LOOKUP_KEY} will be replaced with artificial
5511          *     values. These values will be consistent across multiple queries, but do not use them
5512          *     in places that do not explicitly say they accept them. If they are used in the
5513          *     {@code selection} param in {@link android.content.ContentProvider#query}, the result
5514          *     is undefined.
5515          *     <li>In order to tell whether a contact is from the managed profile, use
5516          *     {@link ContactsContract.Contacts#isEnterpriseContactId(long)}.
5517          * <p>
5518          * A contact lookup URL built by
5519          * {@link ContactsContract.Contacts#getLookupUri(long, String)}
5520          * with a {@link #CONTACT_ID} and a {@link #LOOKUP_KEY} returned by this API can be passed
5521          * to {@link ContactsContract.QuickContact#showQuickContact} even if a contact is from the
5522          * managed profile.
5523          * <pre>
5524          * Uri lookupUri = Uri.withAppendedPath(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI,
5525          *         Uri.encode(phoneNumber));
5526          */
5527         public static final Uri ENTERPRISE_CONTENT_FILTER_URI = Uri.withAppendedPath(AUTHORITY_URI,
5528                 "phone_lookup_enterprise");
5529 
5530         /**
5531          * The MIME type of {@link #CONTENT_FILTER_URI} providing a directory of phone lookup rows.
5532          *
5533          * @hide
5534          */
5535         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone_lookup";
5536 
5537         /**
5538          * If this boolean parameter is set to true, then the appended query is treated as a
5539          * SIP address and the lookup will be performed against SIP addresses in the user's
5540          * contacts.
5541          */
5542         public static final String QUERY_PARAMETER_SIP_ADDRESS = "sip";
5543     }
5544 
5545     /**
5546      * Additional data mixed in with {@link StatusColumns} to link
5547      * back to specific {@link ContactsContract.Data#_ID} entries.
5548      *
5549      * @see StatusUpdates
5550      */
5551     protected interface PresenceColumns {
5552 
5553         /**
5554          * Reference to the {@link Data#_ID} entry that owns this presence.
5555          * <P>Type: INTEGER</P>
5556          */
5557         public static final String DATA_ID = "presence_data_id";
5558 
5559         /**
5560          * See {@link CommonDataKinds.Im} for a list of defined protocol constants.
5561          * <p>Type: NUMBER</p>
5562          */
5563         public static final String PROTOCOL = "protocol";
5564 
5565         /**
5566          * Name of the custom protocol.  Should be supplied along with the {@link #PROTOCOL} value
5567          * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}.  Should be null or
5568          * omitted if {@link #PROTOCOL} value is not
5569          * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}.
5570          *
5571          * <p>Type: NUMBER</p>
5572          */
5573         public static final String CUSTOM_PROTOCOL = "custom_protocol";
5574 
5575         /**
5576          * The IM handle the presence item is for. The handle is scoped to
5577          * {@link #PROTOCOL}.
5578          * <P>Type: TEXT</P>
5579          */
5580         public static final String IM_HANDLE = "im_handle";
5581 
5582         /**
5583          * The IM account for the local user that the presence data came from.
5584          * <P>Type: TEXT</P>
5585          */
5586         public static final String IM_ACCOUNT = "im_account";
5587     }
5588 
5589     /**
5590      * <p>
5591      * A status update is linked to a {@link ContactsContract.Data} row and captures
5592      * the user's latest status update via the corresponding source, e.g.
5593      * "Having lunch" via "Google Talk".
5594      * </p>
5595      * <p>
5596      * There are two ways a status update can be inserted: by explicitly linking
5597      * it to a Data row using {@link #DATA_ID} or indirectly linking it to a data row
5598      * using a combination of {@link #PROTOCOL} (or {@link #CUSTOM_PROTOCOL}) and
5599      * {@link #IM_HANDLE}.  There is no difference between insert and update, you can use
5600      * either.
5601      * </p>
5602      * <p>
5603      * Inserting or updating a status update for the user's profile requires either using
5604      * the {@link #DATA_ID} to identify the data row to attach the update to, or
5605      * {@link StatusUpdates#PROFILE_CONTENT_URI} to ensure that the change is scoped to the
5606      * profile.
5607      * </p>
5608      * <p>
5609      * You cannot use {@link ContentResolver#update} to change a status, but
5610      * {@link ContentResolver#insert} will replace the latests status if it already
5611      * exists.
5612      * </p>
5613      * <p>
5614      * Use {@link ContentResolver#bulkInsert(Uri, ContentValues[])} to insert/update statuses
5615      * for multiple contacts at once.
5616      * </p>
5617      *
5618      * <h3>Columns</h3>
5619      * <table class="jd-sumtable">
5620      * <tr>
5621      * <th colspan='4'>StatusUpdates</th>
5622      * </tr>
5623      * <tr>
5624      * <td>long</td>
5625      * <td>{@link #DATA_ID}</td>
5626      * <td>read/write</td>
5627      * <td>Reference to the {@link Data#_ID} entry that owns this presence. If this
5628      * field is <i>not</i> specified, the provider will attempt to find a data row
5629      * that matches the {@link #PROTOCOL} (or {@link #CUSTOM_PROTOCOL}) and
5630      * {@link #IM_HANDLE} columns.
5631      * </td>
5632      * </tr>
5633      * <tr>
5634      * <td>long</td>
5635      * <td>{@link #PROTOCOL}</td>
5636      * <td>read/write</td>
5637      * <td>See {@link CommonDataKinds.Im} for a list of defined protocol constants.</td>
5638      * </tr>
5639      * <tr>
5640      * <td>String</td>
5641      * <td>{@link #CUSTOM_PROTOCOL}</td>
5642      * <td>read/write</td>
5643      * <td>Name of the custom protocol.  Should be supplied along with the {@link #PROTOCOL} value
5644      * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}.  Should be null or
5645      * omitted if {@link #PROTOCOL} value is not
5646      * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}.</td>
5647      * </tr>
5648      * <tr>
5649      * <td>String</td>
5650      * <td>{@link #IM_HANDLE}</td>
5651      * <td>read/write</td>
5652      * <td> The IM handle the presence item is for. The handle is scoped to
5653      * {@link #PROTOCOL}.</td>
5654      * </tr>
5655      * <tr>
5656      * <td>String</td>
5657      * <td>{@link #IM_ACCOUNT}</td>
5658      * <td>read/write</td>
5659      * <td>The IM account for the local user that the presence data came from.</td>
5660      * </tr>
5661      * <tr>
5662      * <td>int</td>
5663      * <td>{@link #PRESENCE}</td>
5664      * <td>read/write</td>
5665      * <td>Contact IM presence status. The allowed values are:
5666      * <p>
5667      * <ul>
5668      * <li>{@link #OFFLINE}</li>
5669      * <li>{@link #INVISIBLE}</li>
5670      * <li>{@link #AWAY}</li>
5671      * <li>{@link #IDLE}</li>
5672      * <li>{@link #DO_NOT_DISTURB}</li>
5673      * <li>{@link #AVAILABLE}</li>
5674      * </ul>
5675      * </p>
5676      * <p>
5677      * Since presence status is inherently volatile, the content provider
5678      * may choose not to store this field in long-term storage.
5679      * </p>
5680      * </td>
5681      * </tr>
5682      * <tr>
5683      * <td>int</td>
5684      * <td>{@link #CHAT_CAPABILITY}</td>
5685      * <td>read/write</td>
5686      * <td>Contact IM chat compatibility value. The allowed values combinations of the following
5687      * flags. If None of these flags is set, the device can only do text messaging.
5688      * <p>
5689      * <ul>
5690      * <li>{@link #CAPABILITY_HAS_VIDEO}</li>
5691      * <li>{@link #CAPABILITY_HAS_VOICE}</li>
5692      * <li>{@link #CAPABILITY_HAS_CAMERA}</li>
5693      * </ul>
5694      * </p>
5695      * <p>
5696      * Since chat compatibility is inherently volatile as the contact's availability moves from
5697      * one device to another, the content provider may choose not to store this field in long-term
5698      * storage.
5699      * </p>
5700      * </td>
5701      * </tr>
5702      * <tr>
5703      * <td>String</td>
5704      * <td>{@link #STATUS}</td>
5705      * <td>read/write</td>
5706      * <td>Contact's latest status update, e.g. "having toast for breakfast"</td>
5707      * </tr>
5708      * <tr>
5709      * <td>long</td>
5710      * <td>{@link #STATUS_TIMESTAMP}</td>
5711      * <td>read/write</td>
5712      * <td>The absolute time in milliseconds when the status was
5713      * entered by the user. If this value is not provided, the provider will follow
5714      * this logic: if there was no prior status update, the value will be left as null.
5715      * If there was a prior status update, the provider will default this field
5716      * to the current time.</td>
5717      * </tr>
5718      * <tr>
5719      * <td>String</td>
5720      * <td>{@link #STATUS_RES_PACKAGE}</td>
5721      * <td>read/write</td>
5722      * <td> The package containing resources for this status: label and icon.</td>
5723      * </tr>
5724      * <tr>
5725      * <td>long</td>
5726      * <td>{@link #STATUS_LABEL}</td>
5727      * <td>read/write</td>
5728      * <td>The resource ID of the label describing the source of contact status,
5729      * e.g. "Google Talk". This resource is scoped by the
5730      * {@link #STATUS_RES_PACKAGE}.</td>
5731      * </tr>
5732      * <tr>
5733      * <td>long</td>
5734      * <td>{@link #STATUS_ICON}</td>
5735      * <td>read/write</td>
5736      * <td>The resource ID of the icon for the source of contact status. This
5737      * resource is scoped by the {@link #STATUS_RES_PACKAGE}.</td>
5738      * </tr>
5739      * </table>
5740      */
5741     public static class StatusUpdates implements StatusColumns, PresenceColumns {
5742 
5743         /**
5744          * This utility class cannot be instantiated
5745          */
StatusUpdates()5746         private StatusUpdates() {}
5747 
5748         /**
5749          * The content:// style URI for this table
5750          */
5751         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "status_updates");
5752 
5753         /**
5754          * The content:// style URI for this table, specific to the user's profile.
5755          */
5756         public static final Uri PROFILE_CONTENT_URI =
5757                 Uri.withAppendedPath(Profile.CONTENT_URI, "status_updates");
5758 
5759         /**
5760          * Gets the resource ID for the proper presence icon.
5761          *
5762          * @param status the status to get the icon for
5763          * @return the resource ID for the proper presence icon
5764          */
getPresenceIconResourceId(int status)5765         public static final int getPresenceIconResourceId(int status) {
5766             switch (status) {
5767                 case AVAILABLE:
5768                     return android.R.drawable.presence_online;
5769                 case IDLE:
5770                 case AWAY:
5771                     return android.R.drawable.presence_away;
5772                 case DO_NOT_DISTURB:
5773                     return android.R.drawable.presence_busy;
5774                 case INVISIBLE:
5775                     return android.R.drawable.presence_invisible;
5776                 case OFFLINE:
5777                 default:
5778                     return android.R.drawable.presence_offline;
5779             }
5780         }
5781 
5782         /**
5783          * Returns the precedence of the status code the higher number being the higher precedence.
5784          *
5785          * @param status The status code.
5786          * @return An integer representing the precedence, 0 being the lowest.
5787          */
getPresencePrecedence(int status)5788         public static final int getPresencePrecedence(int status) {
5789             // Keep this function here incase we want to enforce a different precedence than the
5790             // natural order of the status constants.
5791             return status;
5792         }
5793 
5794         /**
5795          * The MIME type of {@link #CONTENT_URI} providing a directory of
5796          * status update details.
5797          */
5798         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/status-update";
5799 
5800         /**
5801          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
5802          * status update detail.
5803          */
5804         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/status-update";
5805     }
5806 
5807     /**
5808      * @deprecated This old name was never meant to be made public. Do not use.
5809      */
5810     @Deprecated
5811     public static final class Presence extends StatusUpdates {
5812 
5813     }
5814 
5815     /**
5816      * Additional column returned by
5817      * {@link ContactsContract.Contacts#CONTENT_FILTER_URI Contacts.CONTENT_FILTER_URI} explaining
5818      * why the filter matched the contact. This column will contain extracts from the contact's
5819      * constituent {@link Data Data} items, formatted in a way that indicates the section of the
5820      * snippet that matched the filter.
5821      *
5822      * <p>
5823      * The following example searches for all contacts that match the query "presi" and requests
5824      * the snippet column as well.
5825      * <pre>
5826      * Builder builder = Contacts.CONTENT_FILTER_URI.buildUpon();
5827      * builder.appendPath("presi");
5828      * // Defer snippeting to the client side if possible, for performance reasons.
5829      * builder.appendQueryParameter(SearchSnippets.DEFERRED_SNIPPETING_KEY,"1");
5830      *
5831      * Cursor cursor = getContentResolver().query(builder.build());
5832      *
5833      * Bundle extras = cursor.getExtras();
5834      * if (extras.getBoolean(ContactsContract.DEFERRED_SNIPPETING)) {
5835      *     // Do our own snippet formatting.
5836      *     // For a contact with the email address (president@organization.com), the snippet
5837      *     // column will contain the string "president@organization.com".
5838      * } else {
5839      *     // The snippet has already been pre-formatted, we can display it as is.
5840      *     // For a contact with the email address (president@organization.com), the snippet
5841      *     // column will contain the string "[presi]dent@organization.com".
5842      * }
5843      * </pre>
5844      * </p>
5845      */
5846     public static class SearchSnippets {
5847 
5848         /**
5849          * The search snippet constructed by SQLite snippeting functionality.
5850          * <p>
5851          * The snippet may contain (parts of) several data elements belonging to the contact,
5852          * with the matching parts optionally surrounded by special characters that indicate the
5853          * start and end of matching text.
5854          *
5855          * For example, if a contact has an address "123 Main Street", using a filter "mai" would
5856          * return the formatted snippet "123 [Mai]n street".
5857          *
5858          * @see <a href="http://www.sqlite.org/fts3.html#snippet">
5859          *         http://www.sqlite.org/fts3.html#snippet</a>
5860          */
5861         public static final String SNIPPET = "snippet";
5862 
5863         /**
5864          * Comma-separated parameters for the generation of the snippet:
5865          * <ul>
5866          * <li>The "start match" text. Default is '['</li>
5867          * <li>The "end match" text. Default is ']'</li>
5868          * <li>The "ellipsis" text. Default is "..."</li>
5869          * <li>Maximum number of tokens to include in the snippet. Can be either
5870          * a positive or a negative number: A positive number indicates how many
5871          * tokens can be returned in total. A negative number indicates how many
5872          * tokens can be returned per occurrence of the search terms.</li>
5873          * </ul>
5874          *
5875          * @hide
5876          */
5877         public static final String SNIPPET_ARGS_PARAM_KEY = "snippet_args";
5878 
5879         /**
5880          * The key to ask the provider to defer the formatting of the snippet to the client if
5881          * possible, for performance reasons.
5882          * A value of 1 indicates true, 0 indicates false. False is the default.
5883          * When a cursor is returned to the client, it should check for an extra with the name
5884          * {@link ContactsContract#DEFERRED_SNIPPETING} in the cursor. If it exists, the client
5885          * should do its own formatting of the snippet. If it doesn't exist, the snippet column
5886          * in the cursor should already contain a formatted snippet.
5887          */
5888         public static final String DEFERRED_SNIPPETING_KEY = "deferred_snippeting";
5889     }
5890 
5891     /**
5892      * Container for definitions of common data types stored in the {@link ContactsContract.Data}
5893      * table.
5894      */
5895     public static final class CommonDataKinds {
5896         /**
5897          * This utility class cannot be instantiated
5898          */
CommonDataKinds()5899         private CommonDataKinds() {}
5900 
5901         /**
5902          * The {@link Data#RES_PACKAGE} value for common data that should be
5903          * shown using a default style.
5904          *
5905          * @hide RES_PACKAGE is hidden
5906          */
5907         public static final String PACKAGE_COMMON = "common";
5908 
5909         /**
5910          * The base types that all "Typed" data kinds support.
5911          */
5912         public interface BaseTypes {
5913             /**
5914              * A custom type. The custom label should be supplied by user.
5915              */
5916             public static int TYPE_CUSTOM = 0;
5917         }
5918 
5919         /**
5920          * Columns common across the specific types.
5921          */
5922         protected interface CommonColumns extends BaseTypes {
5923             /**
5924              * The data for the contact method.
5925              * <P>Type: TEXT</P>
5926              */
5927             public static final String DATA = DataColumns.DATA1;
5928 
5929             /**
5930              * The type of data, for example Home or Work.
5931              * <P>Type: INTEGER</P>
5932              */
5933             public static final String TYPE = DataColumns.DATA2;
5934 
5935             /**
5936              * The user defined label for the the contact method.
5937              * <P>Type: TEXT</P>
5938              */
5939             public static final String LABEL = DataColumns.DATA3;
5940         }
5941 
5942         /**
5943          * A data kind representing the contact's proper name. You can use all
5944          * columns defined for {@link ContactsContract.Data} as well as the following aliases.
5945          *
5946          * <h2>Column aliases</h2>
5947          * <table class="jd-sumtable">
5948          * <tr>
5949          * <th>Type</th><th>Alias</th><th colspan='2'>Data column</th>
5950          * </tr>
5951          * <tr>
5952          * <td>String</td>
5953          * <td>{@link #DISPLAY_NAME}</td>
5954          * <td>{@link #DATA1}</td>
5955          * <td></td>
5956          * </tr>
5957          * <tr>
5958          * <td>String</td>
5959          * <td>{@link #GIVEN_NAME}</td>
5960          * <td>{@link #DATA2}</td>
5961          * <td></td>
5962          * </tr>
5963          * <tr>
5964          * <td>String</td>
5965          * <td>{@link #FAMILY_NAME}</td>
5966          * <td>{@link #DATA3}</td>
5967          * <td></td>
5968          * </tr>
5969          * <tr>
5970          * <td>String</td>
5971          * <td>{@link #PREFIX}</td>
5972          * <td>{@link #DATA4}</td>
5973          * <td>Common prefixes in English names are "Mr", "Ms", "Dr" etc.</td>
5974          * </tr>
5975          * <tr>
5976          * <td>String</td>
5977          * <td>{@link #MIDDLE_NAME}</td>
5978          * <td>{@link #DATA5}</td>
5979          * <td></td>
5980          * </tr>
5981          * <tr>
5982          * <td>String</td>
5983          * <td>{@link #SUFFIX}</td>
5984          * <td>{@link #DATA6}</td>
5985          * <td>Common suffixes in English names are "Sr", "Jr", "III" etc.</td>
5986          * </tr>
5987          * <tr>
5988          * <td>String</td>
5989          * <td>{@link #PHONETIC_GIVEN_NAME}</td>
5990          * <td>{@link #DATA7}</td>
5991          * <td>Used for phonetic spelling of the name, e.g. Pinyin, Katakana, Hiragana</td>
5992          * </tr>
5993          * <tr>
5994          * <td>String</td>
5995          * <td>{@link #PHONETIC_MIDDLE_NAME}</td>
5996          * <td>{@link #DATA8}</td>
5997          * <td></td>
5998          * </tr>
5999          * <tr>
6000          * <td>String</td>
6001          * <td>{@link #PHONETIC_FAMILY_NAME}</td>
6002          * <td>{@link #DATA9}</td>
6003          * <td></td>
6004          * </tr>
6005          * </table>
6006          */
6007         public static final class StructuredName implements DataColumnsWithJoins, ContactCounts {
6008             /**
6009              * This utility class cannot be instantiated
6010              */
StructuredName()6011             private StructuredName() {}
6012 
6013             /** MIME type used when storing this in data table. */
6014             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/name";
6015 
6016             /**
6017              * The name that should be used to display the contact.
6018              * <i>Unstructured component of the name should be consistent with
6019              * its structured representation.</i>
6020              * <p>
6021              * Type: TEXT
6022              */
6023             public static final String DISPLAY_NAME = DATA1;
6024 
6025             /**
6026              * The given name for the contact.
6027              * <P>Type: TEXT</P>
6028              */
6029             public static final String GIVEN_NAME = DATA2;
6030 
6031             /**
6032              * The family name for the contact.
6033              * <P>Type: TEXT</P>
6034              */
6035             public static final String FAMILY_NAME = DATA3;
6036 
6037             /**
6038              * The contact's honorific prefix, e.g. "Sir"
6039              * <P>Type: TEXT</P>
6040              */
6041             public static final String PREFIX = DATA4;
6042 
6043             /**
6044              * The contact's middle name
6045              * <P>Type: TEXT</P>
6046              */
6047             public static final String MIDDLE_NAME = DATA5;
6048 
6049             /**
6050              * The contact's honorific suffix, e.g. "Jr"
6051              */
6052             public static final String SUFFIX = DATA6;
6053 
6054             /**
6055              * The phonetic version of the given name for the contact.
6056              * <P>Type: TEXT</P>
6057              */
6058             public static final String PHONETIC_GIVEN_NAME = DATA7;
6059 
6060             /**
6061              * The phonetic version of the additional name for the contact.
6062              * <P>Type: TEXT</P>
6063              */
6064             public static final String PHONETIC_MIDDLE_NAME = DATA8;
6065 
6066             /**
6067              * The phonetic version of the family name for the contact.
6068              * <P>Type: TEXT</P>
6069              */
6070             public static final String PHONETIC_FAMILY_NAME = DATA9;
6071 
6072             /**
6073              * The style used for combining given/middle/family name into a full name.
6074              * See {@link ContactsContract.FullNameStyle}.
6075              */
6076             public static final String FULL_NAME_STYLE = DATA10;
6077 
6078             /**
6079              * The alphabet used for capturing the phonetic name.
6080              * See ContactsContract.PhoneticNameStyle.
6081              */
6082             public static final String PHONETIC_NAME_STYLE = DATA11;
6083         }
6084 
6085         /**
6086          * <p>A data kind representing the contact's nickname. For example, for
6087          * Bob Parr ("Mr. Incredible"):
6088          * <pre>
6089          * ArrayList&lt;ContentProviderOperation&gt; ops =
6090          *          new ArrayList&lt;ContentProviderOperation&gt;();
6091          *
6092          * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
6093          *          .withValue(Data.RAW_CONTACT_ID, rawContactId)
6094          *          .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
6095          *          .withValue(StructuredName.DISPLAY_NAME, &quot;Bob Parr&quot;)
6096          *          .build());
6097          *
6098          * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
6099          *          .withValue(Data.RAW_CONTACT_ID, rawContactId)
6100          *          .withValue(Data.MIMETYPE, Nickname.CONTENT_ITEM_TYPE)
6101          *          .withValue(Nickname.NAME, "Mr. Incredible")
6102          *          .withValue(Nickname.TYPE, Nickname.TYPE_CUSTOM)
6103          *          .withValue(Nickname.LABEL, "Superhero")
6104          *          .build());
6105          *
6106          * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
6107          * </pre>
6108          * </p>
6109          * <p>
6110          * You can use all columns defined for {@link ContactsContract.Data} as well as the
6111          * following aliases.
6112          * </p>
6113          *
6114          * <h2>Column aliases</h2>
6115          * <table class="jd-sumtable">
6116          * <tr>
6117          * <th>Type</th><th>Alias</th><th colspan='2'>Data column</th>
6118          * </tr>
6119          * <tr>
6120          * <td>String</td>
6121          * <td>{@link #NAME}</td>
6122          * <td>{@link #DATA1}</td>
6123          * <td></td>
6124          * </tr>
6125          * <tr>
6126          * <td>int</td>
6127          * <td>{@link #TYPE}</td>
6128          * <td>{@link #DATA2}</td>
6129          * <td>
6130          * Allowed values are:
6131          * <p>
6132          * <ul>
6133          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
6134          * <li>{@link #TYPE_DEFAULT}</li>
6135          * <li>{@link #TYPE_OTHER_NAME}</li>
6136          * <li>{@link #TYPE_MAIDEN_NAME}</li>
6137          * <li>{@link #TYPE_SHORT_NAME}</li>
6138          * <li>{@link #TYPE_INITIALS}</li>
6139          * </ul>
6140          * </p>
6141          * </td>
6142          * </tr>
6143          * <tr>
6144          * <td>String</td>
6145          * <td>{@link #LABEL}</td>
6146          * <td>{@link #DATA3}</td>
6147          * <td></td>
6148          * </tr>
6149          * </table>
6150          */
6151         public static final class Nickname implements DataColumnsWithJoins, CommonColumns,
6152                 ContactCounts{
6153             /**
6154              * This utility class cannot be instantiated
6155              */
Nickname()6156             private Nickname() {}
6157 
6158             /** MIME type used when storing this in data table. */
6159             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/nickname";
6160 
6161             public static final int TYPE_DEFAULT = 1;
6162             public static final int TYPE_OTHER_NAME = 2;
6163             public static final int TYPE_MAIDEN_NAME = 3;
6164             /** @deprecated Use TYPE_MAIDEN_NAME instead. */
6165             @Deprecated
6166             public static final int TYPE_MAINDEN_NAME = 3;
6167             public static final int TYPE_SHORT_NAME = 4;
6168             public static final int TYPE_INITIALS = 5;
6169 
6170             /**
6171              * The name itself
6172              */
6173             public static final String NAME = DATA;
6174         }
6175 
6176         /**
6177          * <p>
6178          * A data kind representing a telephone number.
6179          * </p>
6180          * <p>
6181          * You can use all columns defined for {@link ContactsContract.Data} as
6182          * well as the following aliases.
6183          * </p>
6184          * <h2>Column aliases</h2>
6185          * <table class="jd-sumtable">
6186          * <tr>
6187          * <th>Type</th>
6188          * <th>Alias</th><th colspan='2'>Data column</th>
6189          * </tr>
6190          * <tr>
6191          * <td>String</td>
6192          * <td>{@link #NUMBER}</td>
6193          * <td>{@link #DATA1}</td>
6194          * <td></td>
6195          * </tr>
6196          * <tr>
6197          * <td>int</td>
6198          * <td>{@link #TYPE}</td>
6199          * <td>{@link #DATA2}</td>
6200          * <td>Allowed values are:
6201          * <p>
6202          * <ul>
6203          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
6204          * <li>{@link #TYPE_HOME}</li>
6205          * <li>{@link #TYPE_MOBILE}</li>
6206          * <li>{@link #TYPE_WORK}</li>
6207          * <li>{@link #TYPE_FAX_WORK}</li>
6208          * <li>{@link #TYPE_FAX_HOME}</li>
6209          * <li>{@link #TYPE_PAGER}</li>
6210          * <li>{@link #TYPE_OTHER}</li>
6211          * <li>{@link #TYPE_CALLBACK}</li>
6212          * <li>{@link #TYPE_CAR}</li>
6213          * <li>{@link #TYPE_COMPANY_MAIN}</li>
6214          * <li>{@link #TYPE_ISDN}</li>
6215          * <li>{@link #TYPE_MAIN}</li>
6216          * <li>{@link #TYPE_OTHER_FAX}</li>
6217          * <li>{@link #TYPE_RADIO}</li>
6218          * <li>{@link #TYPE_TELEX}</li>
6219          * <li>{@link #TYPE_TTY_TDD}</li>
6220          * <li>{@link #TYPE_WORK_MOBILE}</li>
6221          * <li>{@link #TYPE_WORK_PAGER}</li>
6222          * <li>{@link #TYPE_ASSISTANT}</li>
6223          * <li>{@link #TYPE_MMS}</li>
6224          * </ul>
6225          * </p>
6226          * </td>
6227          * </tr>
6228          * <tr>
6229          * <td>String</td>
6230          * <td>{@link #LABEL}</td>
6231          * <td>{@link #DATA3}</td>
6232          * <td></td>
6233          * </tr>
6234          * </table>
6235          */
6236         public static final class Phone implements DataColumnsWithJoins, CommonColumns,
6237                 ContactCounts {
6238             /**
6239              * This utility class cannot be instantiated
6240              */
Phone()6241             private Phone() {}
6242 
6243             /** MIME type used when storing this in data table. */
6244             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone_v2";
6245 
6246             /**
6247              * The MIME type of {@link #CONTENT_URI} providing a directory of
6248              * phones.
6249              */
6250             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone_v2";
6251 
6252             /**
6253              * The content:// style URI for all data records of the
6254              * {@link #CONTENT_ITEM_TYPE} MIME type, combined with the
6255              * associated raw contact and aggregate contact data.
6256              */
6257             public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
6258                     "phones");
6259 
6260             /**
6261              * URI used for getting all data records of the {@link #CONTENT_ITEM_TYPE} MIME type,
6262              * combined with the associated raw contact and aggregate contact data, from both the
6263              * calling user and the managed profile that is linked to it.
6264              * <p>
6265              * It supports the same semantics as {@link #CONTENT_URI} and returns the same
6266              * columns.<br>
6267              * If the device has no managed profile that is linked to the calling user, it behaves
6268              * in the exact same way as {@link #CONTENT_URI}.<br>
6269              * If there is a managed profile linked to the calling user, it will return merged
6270              * results from both.
6271              * <p>
6272              * If a result is from the managed profile, the following changes are made to the data:
6273              * <ul>
6274              *     <li>{@link #PHOTO_THUMBNAIL_URI} and {@link #PHOTO_URI} will be rewritten to
6275              *     special URIs. Use {@link ContentResolver#openAssetFileDescriptor} or its siblings
6276              *     to load pictures from them.
6277              *     <li>{@link #PHOTO_ID} and {@link #PHOTO_FILE_ID} will be set to null. Don't use
6278              *     them.
6279              *     <li>{@link #CONTACT_ID} and {@link #LOOKUP_KEY} will be replaced with artificial
6280              *     values. These values will be consistent across multiple queries, but do not use
6281              *     them in places that don't explicitly say they accept them. If they are used in
6282              *     the {@code selection} param in {@link android.content.ContentProvider#query}, the
6283              *     result is undefined.
6284              *     <li>In order to tell whether a contact is from the managed profile, use
6285              *     {@link ContactsContract.Contacts#isEnterpriseContactId(long)}.
6286              */
6287             public static final @NonNull Uri ENTERPRISE_CONTENT_URI =
6288                     Uri.withAppendedPath(Data.ENTERPRISE_CONTENT_URI, "phones");
6289 
6290             /**
6291              * <p>The content:// style URL for phone lookup using a filter. The filter returns
6292              * records of MIME type {@link #CONTENT_ITEM_TYPE}. The filter is applied
6293              * to display names as well as phone numbers. The filter argument should be passed
6294              * as an additional path segment after this URI.
6295              *
6296              * <p class="caution"><b>Caution: </b>This field doesn't sort results based on contacts
6297              * frequency. For more information, see the
6298              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
6299              * page.
6300              */
6301             public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(CONTENT_URI,
6302                     "filter");
6303 
6304             /**
6305              * <p>It supports the similar semantics as {@link #CONTENT_FILTER_URI} and returns the
6306              * same columns. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
6307              * parameters, otherwise it will throw IllegalArgumentException.
6308              *
6309              * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
6310              * this field doesn't sort results based on contacts frequency. For more information,
6311              * see the
6312              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
6313              * page.
6314              */
6315             public static final Uri ENTERPRISE_CONTENT_FILTER_URI = Uri.withAppendedPath(
6316                     CONTENT_URI, "filter_enterprise");
6317 
6318             /**
6319              * A boolean query parameter that can be used with {@link #CONTENT_FILTER_URI}.
6320              * If "1" or "true", display names are searched.  If "0" or "false", display names
6321              * are not searched.  Default is "1".
6322              */
6323             public static final String SEARCH_DISPLAY_NAME_KEY = "search_display_name";
6324 
6325             /**
6326              * A boolean query parameter that can be used with {@link #CONTENT_FILTER_URI}.
6327              * If "1" or "true", phone numbers are searched.  If "0" or "false", phone numbers
6328              * are not searched.  Default is "1".
6329              */
6330             public static final String SEARCH_PHONE_NUMBER_KEY = "search_phone_number";
6331 
6332             public static final int TYPE_HOME = 1;
6333             public static final int TYPE_MOBILE = 2;
6334             public static final int TYPE_WORK = 3;
6335             public static final int TYPE_FAX_WORK = 4;
6336             public static final int TYPE_FAX_HOME = 5;
6337             public static final int TYPE_PAGER = 6;
6338             public static final int TYPE_OTHER = 7;
6339             public static final int TYPE_CALLBACK = 8;
6340             public static final int TYPE_CAR = 9;
6341             public static final int TYPE_COMPANY_MAIN = 10;
6342             public static final int TYPE_ISDN = 11;
6343             public static final int TYPE_MAIN = 12;
6344             public static final int TYPE_OTHER_FAX = 13;
6345             public static final int TYPE_RADIO = 14;
6346             public static final int TYPE_TELEX = 15;
6347             public static final int TYPE_TTY_TDD = 16;
6348             public static final int TYPE_WORK_MOBILE = 17;
6349             public static final int TYPE_WORK_PAGER = 18;
6350             public static final int TYPE_ASSISTANT = 19;
6351             public static final int TYPE_MMS = 20;
6352 
6353             /**
6354              * The phone number as the user entered it.
6355              * <P>Type: TEXT</P>
6356              */
6357             public static final String NUMBER = DATA;
6358 
6359             /**
6360              * The phone number's E164 representation. This value can be omitted in which
6361              * case the provider will try to automatically infer it.  (It'll be left null if the
6362              * provider fails to infer.)
6363              * If present, {@link #NUMBER} has to be set as well (it will be ignored otherwise).
6364              * <P>Type: TEXT</P>
6365              */
6366             public static final String NORMALIZED_NUMBER = DATA4;
6367 
6368             /**
6369              * @deprecated use {@link #getTypeLabel(Resources, int, CharSequence)} instead.
6370              * @hide
6371              */
6372             @Deprecated
getDisplayLabel(Context context, int type, CharSequence label, CharSequence[] labelArray)6373             public static final CharSequence getDisplayLabel(Context context, int type,
6374                     CharSequence label, CharSequence[] labelArray) {
6375                 return getTypeLabel(context.getResources(), type, label);
6376             }
6377 
6378             /**
6379              * @deprecated use {@link #getTypeLabel(Resources, int, CharSequence)} instead.
6380              * @hide
6381              */
6382             @Deprecated
6383             @UnsupportedAppUsage
getDisplayLabel(Context context, int type, CharSequence label)6384             public static final CharSequence getDisplayLabel(Context context, int type,
6385                     CharSequence label) {
6386                 return getTypeLabel(context.getResources(), type, label);
6387             }
6388 
6389             /**
6390              * Return the string resource that best describes the given
6391              * {@link #TYPE}. Will always return a valid resource.
6392              */
getTypeLabelResource(int type)6393             public static final int getTypeLabelResource(int type) {
6394                 switch (type) {
6395                     case TYPE_HOME: return com.android.internal.R.string.phoneTypeHome;
6396                     case TYPE_MOBILE: return com.android.internal.R.string.phoneTypeMobile;
6397                     case TYPE_WORK: return com.android.internal.R.string.phoneTypeWork;
6398                     case TYPE_FAX_WORK: return com.android.internal.R.string.phoneTypeFaxWork;
6399                     case TYPE_FAX_HOME: return com.android.internal.R.string.phoneTypeFaxHome;
6400                     case TYPE_PAGER: return com.android.internal.R.string.phoneTypePager;
6401                     case TYPE_OTHER: return com.android.internal.R.string.phoneTypeOther;
6402                     case TYPE_CALLBACK: return com.android.internal.R.string.phoneTypeCallback;
6403                     case TYPE_CAR: return com.android.internal.R.string.phoneTypeCar;
6404                     case TYPE_COMPANY_MAIN: return com.android.internal.R.string.phoneTypeCompanyMain;
6405                     case TYPE_ISDN: return com.android.internal.R.string.phoneTypeIsdn;
6406                     case TYPE_MAIN: return com.android.internal.R.string.phoneTypeMain;
6407                     case TYPE_OTHER_FAX: return com.android.internal.R.string.phoneTypeOtherFax;
6408                     case TYPE_RADIO: return com.android.internal.R.string.phoneTypeRadio;
6409                     case TYPE_TELEX: return com.android.internal.R.string.phoneTypeTelex;
6410                     case TYPE_TTY_TDD: return com.android.internal.R.string.phoneTypeTtyTdd;
6411                     case TYPE_WORK_MOBILE: return com.android.internal.R.string.phoneTypeWorkMobile;
6412                     case TYPE_WORK_PAGER: return com.android.internal.R.string.phoneTypeWorkPager;
6413                     case TYPE_ASSISTANT: return com.android.internal.R.string.phoneTypeAssistant;
6414                     case TYPE_MMS: return com.android.internal.R.string.phoneTypeMms;
6415                     default: return com.android.internal.R.string.phoneTypeCustom;
6416                 }
6417             }
6418 
6419             /**
6420              * Return a {@link CharSequence} that best describes the given type,
6421              * possibly substituting the given {@link #LABEL} value
6422              * for {@link #TYPE_CUSTOM}.
6423              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)6424             public static final CharSequence getTypeLabel(Resources res, int type,
6425                     @Nullable CharSequence label) {
6426                 if ((type == TYPE_CUSTOM || type == TYPE_ASSISTANT) && !TextUtils.isEmpty(label)) {
6427                     return label;
6428                 } else {
6429                     final int labelRes = getTypeLabelResource(type);
6430                     return res.getText(labelRes);
6431                 }
6432             }
6433         }
6434 
6435         /**
6436          * <p>
6437          * A data kind representing an email address.
6438          * </p>
6439          * <p>
6440          * You can use all columns defined for {@link ContactsContract.Data} as
6441          * well as the following aliases.
6442          * </p>
6443          * <h2>Column aliases</h2>
6444          * <table class="jd-sumtable">
6445          * <tr>
6446          * <th>Type</th>
6447          * <th>Alias</th><th colspan='2'>Data column</th>
6448          * </tr>
6449          * <tr>
6450          * <td>String</td>
6451          * <td>{@link #ADDRESS}</td>
6452          * <td>{@link #DATA1}</td>
6453          * <td>Email address itself.</td>
6454          * </tr>
6455          * <tr>
6456          * <td>int</td>
6457          * <td>{@link #TYPE}</td>
6458          * <td>{@link #DATA2}</td>
6459          * <td>Allowed values are:
6460          * <p>
6461          * <ul>
6462          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
6463          * <li>{@link #TYPE_HOME}</li>
6464          * <li>{@link #TYPE_WORK}</li>
6465          * <li>{@link #TYPE_OTHER}</li>
6466          * <li>{@link #TYPE_MOBILE}</li>
6467          * </ul>
6468          * </p>
6469          * </td>
6470          * </tr>
6471          * <tr>
6472          * <td>String</td>
6473          * <td>{@link #LABEL}</td>
6474          * <td>{@link #DATA3}</td>
6475          * <td></td>
6476          * </tr>
6477          * </table>
6478          */
6479         public static final class Email implements DataColumnsWithJoins, CommonColumns,
6480                 ContactCounts {
6481             /*
6482              * This utility class cannot be instantiated
6483              */
Email()6484             private Email() {}
6485 
6486             /** MIME type used when storing this in data table. */
6487             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/email_v2";
6488 
6489             /**
6490              * The MIME type of {@link #CONTENT_URI} providing a directory of email addresses.
6491              */
6492             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/email_v2";
6493 
6494             /**
6495              * The content:// style URI for all data records of the
6496              * {@link #CONTENT_ITEM_TYPE} MIME type, combined with the
6497              * associated raw contact and aggregate contact data.
6498              */
6499             public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
6500                     "emails");
6501 
6502             /**
6503              * <p>
6504              * The content:// style URL for looking up data rows by email address. The
6505              * lookup argument, an email address, should be passed as an additional path segment
6506              * after this URI.
6507              * </p>
6508              * <p>Example:
6509              * <pre>
6510              * Uri uri = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(email));
6511              * Cursor c = getContentResolver().query(uri,
6512              *          new String[]{Email.CONTACT_ID, Email.DISPLAY_NAME, Email.DATA},
6513              *          null, null, null);
6514              * </pre>
6515              * </p>
6516              */
6517             public static final Uri CONTENT_LOOKUP_URI = Uri.withAppendedPath(CONTENT_URI,
6518                     "lookup");
6519 
6520             /**
6521              * URI used for looking up contacts by email on the contact databases of both the
6522              * calling user and the managed profile that is linked to it.
6523              * <p>
6524              * It supports the same semantics as {@link #CONTENT_LOOKUP_URI} and returns the same
6525              * columns.<br>
6526              * If the device has no managed profile that is linked to the calling user, it behaves
6527              * in the exact same way as {@link #CONTENT_LOOKUP_URI}.<br>
6528              * If there is a managed profile linked to the calling user, it first queries the
6529              * calling user's contact database, and only if no matching contacts are found there it
6530              * then queries the managed profile database.
6531              * <p class="caution">
6532              * If a result is from the managed profile, the following changes are made to the data:
6533              * <ul>
6534              *     <li>{@link #PHOTO_THUMBNAIL_URI} and {@link #PHOTO_URI} will be rewritten to
6535              *     specialURIs. Use {@link ContentResolver#openAssetFileDescriptor} or its siblings
6536              *     to load pictures from them.
6537              *     <li>{@link #PHOTO_ID} and {@link #PHOTO_FILE_ID} will be set to null. Don't use
6538              *     them.
6539              *     <li>{@link #CONTACT_ID} and {@link #LOOKUP_KEY} will be replaced with artificial
6540              *     values. These values will be consistent across multiple queries, but do not use
6541              *     them in places that do not explicitly say they accept them. If they are used in
6542              *     the {@code selection} param in {@link android.content.ContentProvider#query}, the
6543              *     result is undefined.
6544              *     <li>In order to tell whether a contact is from the managed profile, use
6545              *     {@link ContactsContract.Contacts#isEnterpriseContactId(long)}.
6546              * <p>
6547              * A contact lookup URL built by
6548              * {@link ContactsContract.Contacts#getLookupUri(long, String)}
6549              * with a {@link #CONTACT_ID} and a {@link #LOOKUP_KEY} returned by this API can be
6550              * passed to {@link ContactsContract.QuickContact#showQuickContact} even if a contact is
6551              * from the managed profile.
6552              * <pre>
6553              * Uri lookupUri = Uri.withAppendedPath(Email.ENTERPRISE_CONTENT_LOOKUP_URI,
6554              *         Uri.encode(email));
6555              */
6556             public static final Uri ENTERPRISE_CONTENT_LOOKUP_URI =
6557                     Uri.withAppendedPath(CONTENT_URI, "lookup_enterprise");
6558 
6559             /**
6560              * <p>The content:// style URL for email lookup using a filter. The filter returns
6561              * records of MIME type {@link #CONTENT_ITEM_TYPE}. The filter is applied
6562              * to display names as well as email addresses. The filter argument should be passed
6563              * as an additional path segment after this URI.
6564              * </p>
6565              *
6566              * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
6567              * this field doesn't sort results based on contacts frequency. For more information,
6568              * see the
6569              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
6570              * page.</p>
6571              *
6572              * <p>The query in the following example will return "Robert Parr (bob@incredibles.com)"
6573              * as well as "Bob Parr (incredible@android.com)".
6574              * <pre>
6575              * Uri uri = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode("bob"));
6576              * Cursor c = getContentResolver().query(uri,
6577              *          new String[]{Email.DISPLAY_NAME, Email.DATA},
6578              *          null, null, null);
6579              * </pre>
6580              * </p>
6581              */
6582             public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(CONTENT_URI,
6583                     "filter");
6584 
6585             /**
6586              * <p>It supports the similar semantics as {@link #CONTENT_FILTER_URI} and returns the
6587              * same columns. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
6588              * parameters, otherwise it will throw IllegalArgumentException. The passed directory
6589              * can belong either to the calling user or to a managed profile that is linked to it.
6590              * <p class="caution">
6591              * <b>Caution: </b>If you publish your app to the Google Play Store,
6592              * this field doesn't sort results based on contacts frequency. For more information,
6593              * see the
6594              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
6595              * page.
6596              */
6597             public static final Uri ENTERPRISE_CONTENT_FILTER_URI = Uri.withAppendedPath(
6598                     CONTENT_URI, "filter_enterprise");
6599 
6600             /**
6601              * The email address.
6602              * <P>Type: TEXT</P>
6603              */
6604             public static final String ADDRESS = DATA1;
6605 
6606             public static final int TYPE_HOME = 1;
6607             public static final int TYPE_WORK = 2;
6608             public static final int TYPE_OTHER = 3;
6609             public static final int TYPE_MOBILE = 4;
6610 
6611             /**
6612              * The display name for the email address
6613              * <P>Type: TEXT</P>
6614              */
6615             public static final String DISPLAY_NAME = DATA4;
6616 
6617             /**
6618              * Return the string resource that best describes the given
6619              * {@link #TYPE}. Will always return a valid resource.
6620              */
getTypeLabelResource(int type)6621             public static final int getTypeLabelResource(int type) {
6622                 switch (type) {
6623                     case TYPE_HOME: return com.android.internal.R.string.emailTypeHome;
6624                     case TYPE_WORK: return com.android.internal.R.string.emailTypeWork;
6625                     case TYPE_OTHER: return com.android.internal.R.string.emailTypeOther;
6626                     case TYPE_MOBILE: return com.android.internal.R.string.emailTypeMobile;
6627                     default: return com.android.internal.R.string.emailTypeCustom;
6628                 }
6629             }
6630 
6631             /**
6632              * Return a {@link CharSequence} that best describes the given type,
6633              * possibly substituting the given {@link #LABEL} value
6634              * for {@link #TYPE_CUSTOM}.
6635              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)6636             public static final CharSequence getTypeLabel(Resources res, int type,
6637                     @Nullable CharSequence label) {
6638                 if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
6639                     return label;
6640                 } else {
6641                     final int labelRes = getTypeLabelResource(type);
6642                     return res.getText(labelRes);
6643                 }
6644             }
6645         }
6646 
6647         /**
6648          * <p>
6649          * A data kind representing a postal addresses.
6650          * </p>
6651          * <p>
6652          * You can use all columns defined for {@link ContactsContract.Data} as
6653          * well as the following aliases.
6654          * </p>
6655          * <h2>Column aliases</h2>
6656          * <table class="jd-sumtable">
6657          * <tr>
6658          * <th>Type</th>
6659          * <th>Alias</th><th colspan='2'>Data column</th>
6660          * </tr>
6661          * <tr>
6662          * <td>String</td>
6663          * <td>{@link #FORMATTED_ADDRESS}</td>
6664          * <td>{@link #DATA1}</td>
6665          * <td></td>
6666          * </tr>
6667          * <tr>
6668          * <td>int</td>
6669          * <td>{@link #TYPE}</td>
6670          * <td>{@link #DATA2}</td>
6671          * <td>Allowed values are:
6672          * <p>
6673          * <ul>
6674          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
6675          * <li>{@link #TYPE_HOME}</li>
6676          * <li>{@link #TYPE_WORK}</li>
6677          * <li>{@link #TYPE_OTHER}</li>
6678          * </ul>
6679          * </p>
6680          * </td>
6681          * </tr>
6682          * <tr>
6683          * <td>String</td>
6684          * <td>{@link #LABEL}</td>
6685          * <td>{@link #DATA3}</td>
6686          * <td></td>
6687          * </tr>
6688          * <tr>
6689          * <td>String</td>
6690          * <td>{@link #STREET}</td>
6691          * <td>{@link #DATA4}</td>
6692          * <td></td>
6693          * </tr>
6694          * <tr>
6695          * <td>String</td>
6696          * <td>{@link #POBOX}</td>
6697          * <td>{@link #DATA5}</td>
6698          * <td>Post Office Box number</td>
6699          * </tr>
6700          * <tr>
6701          * <td>String</td>
6702          * <td>{@link #NEIGHBORHOOD}</td>
6703          * <td>{@link #DATA6}</td>
6704          * <td></td>
6705          * </tr>
6706          * <tr>
6707          * <td>String</td>
6708          * <td>{@link #CITY}</td>
6709          * <td>{@link #DATA7}</td>
6710          * <td></td>
6711          * </tr>
6712          * <tr>
6713          * <td>String</td>
6714          * <td>{@link #REGION}</td>
6715          * <td>{@link #DATA8}</td>
6716          * <td></td>
6717          * </tr>
6718          * <tr>
6719          * <td>String</td>
6720          * <td>{@link #POSTCODE}</td>
6721          * <td>{@link #DATA9}</td>
6722          * <td></td>
6723          * </tr>
6724          * <tr>
6725          * <td>String</td>
6726          * <td>{@link #COUNTRY}</td>
6727          * <td>{@link #DATA10}</td>
6728          * <td></td>
6729          * </tr>
6730          * </table>
6731          */
6732         public static final class StructuredPostal implements DataColumnsWithJoins, CommonColumns,
6733                 ContactCounts {
6734             /**
6735              * This utility class cannot be instantiated
6736              */
StructuredPostal()6737             private StructuredPostal() {
6738             }
6739 
6740             /** MIME type used when storing this in data table. */
6741             public static final String CONTENT_ITEM_TYPE =
6742                     "vnd.android.cursor.item/postal-address_v2";
6743 
6744             /**
6745              * The MIME type of {@link #CONTENT_URI} providing a directory of
6746              * postal addresses.
6747              */
6748             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/postal-address_v2";
6749 
6750             /**
6751              * The content:// style URI for all data records of the
6752              * {@link StructuredPostal#CONTENT_ITEM_TYPE} MIME type.
6753              */
6754             public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
6755                     "postals");
6756 
6757             public static final int TYPE_HOME = 1;
6758             public static final int TYPE_WORK = 2;
6759             public static final int TYPE_OTHER = 3;
6760 
6761             /**
6762              * The full, unstructured postal address. <i>This field must be
6763              * consistent with any structured data.</i>
6764              * <p>
6765              * Type: TEXT
6766              */
6767             public static final String FORMATTED_ADDRESS = DATA;
6768 
6769             /**
6770              * Can be street, avenue, road, etc. This element also includes the
6771              * house number and room/apartment/flat/floor number.
6772              * <p>
6773              * Type: TEXT
6774              */
6775             public static final String STREET = DATA4;
6776 
6777             /**
6778              * Covers actual P.O. boxes, drawers, locked bags, etc. This is
6779              * usually but not always mutually exclusive with street.
6780              * <p>
6781              * Type: TEXT
6782              */
6783             public static final String POBOX = DATA5;
6784 
6785             /**
6786              * This is used to disambiguate a street address when a city
6787              * contains more than one street with the same name, or to specify a
6788              * small place whose mail is routed through a larger postal town. In
6789              * China it could be a county or a minor city.
6790              * <p>
6791              * Type: TEXT
6792              */
6793             public static final String NEIGHBORHOOD = DATA6;
6794 
6795             /**
6796              * Can be city, village, town, borough, etc. This is the postal town
6797              * and not necessarily the place of residence or place of business.
6798              * <p>
6799              * Type: TEXT
6800              */
6801             public static final String CITY = DATA7;
6802 
6803             /**
6804              * A state, province, county (in Ireland), Land (in Germany),
6805              * departement (in France), etc.
6806              * <p>
6807              * Type: TEXT
6808              */
6809             public static final String REGION = DATA8;
6810 
6811             /**
6812              * Postal code. Usually country-wide, but sometimes specific to the
6813              * city (e.g. "2" in "Dublin 2, Ireland" addresses).
6814              * <p>
6815              * Type: TEXT
6816              */
6817             public static final String POSTCODE = DATA9;
6818 
6819             /**
6820              * The name or code of the country.
6821              * <p>
6822              * Type: TEXT
6823              */
6824             public static final String COUNTRY = DATA10;
6825 
6826             /**
6827              * Return the string resource that best describes the given
6828              * {@link #TYPE}. Will always return a valid resource.
6829              */
getTypeLabelResource(int type)6830             public static final int getTypeLabelResource(int type) {
6831                 switch (type) {
6832                     case TYPE_HOME: return com.android.internal.R.string.postalTypeHome;
6833                     case TYPE_WORK: return com.android.internal.R.string.postalTypeWork;
6834                     case TYPE_OTHER: return com.android.internal.R.string.postalTypeOther;
6835                     default: return com.android.internal.R.string.postalTypeCustom;
6836                 }
6837             }
6838 
6839             /**
6840              * Return a {@link CharSequence} that best describes the given type,
6841              * possibly substituting the given {@link #LABEL} value
6842              * for {@link #TYPE_CUSTOM}.
6843              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)6844             public static final CharSequence getTypeLabel(Resources res, int type,
6845                     @Nullable CharSequence label) {
6846                 if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
6847                     return label;
6848                 } else {
6849                     final int labelRes = getTypeLabelResource(type);
6850                     return res.getText(labelRes);
6851                 }
6852             }
6853         }
6854 
6855         /**
6856          * <p>
6857          * A data kind representing an IM address
6858          * </p>
6859          * <p>
6860          * You can use all columns defined for {@link ContactsContract.Data} as
6861          * well as the following aliases.
6862          * </p>
6863          * <h2>Column aliases</h2>
6864          * <table class="jd-sumtable">
6865          * <tr>
6866          * <th>Type</th>
6867          * <th>Alias</th><th colspan='2'>Data column</th>
6868          * </tr>
6869          * <tr>
6870          * <td>String</td>
6871          * <td>{@link #DATA}</td>
6872          * <td>{@link #DATA1}</td>
6873          * <td></td>
6874          * </tr>
6875          * <tr>
6876          * <td>int</td>
6877          * <td>{@link #TYPE}</td>
6878          * <td>{@link #DATA2}</td>
6879          * <td>Allowed values are:
6880          * <p>
6881          * <ul>
6882          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
6883          * <li>{@link #TYPE_HOME}</li>
6884          * <li>{@link #TYPE_WORK}</li>
6885          * <li>{@link #TYPE_OTHER}</li>
6886          * </ul>
6887          * </p>
6888          * </td>
6889          * </tr>
6890          * <tr>
6891          * <td>String</td>
6892          * <td>{@link #LABEL}</td>
6893          * <td>{@link #DATA3}</td>
6894          * <td></td>
6895          * </tr>
6896          * <tr>
6897          * <td>String</td>
6898          * <td>{@link #PROTOCOL}</td>
6899          * <td>{@link #DATA5}</td>
6900          * <td>
6901          * <p>
6902          * Allowed value: {@link #PROTOCOL_CUSTOM}. Also provide the actual protocol name
6903          * as {@link #CUSTOM_PROTOCOL}.
6904          * </p>
6905          * </td>
6906          * </tr>
6907          * <tr>
6908          * <td>String</td>
6909          * <td>{@link #CUSTOM_PROTOCOL}</td>
6910          * <td>{@link #DATA6}</td>
6911          * <td></td>
6912          * </tr>
6913          * </table>
6914          *
6915          * @deprecated This field may not be well supported by some contacts apps and is discouraged
6916          * to use.
6917          */
6918         @Deprecated
6919         public static final class Im implements DataColumnsWithJoins, CommonColumns, ContactCounts {
6920             /**
6921              * This utility class cannot be instantiated
6922              */
Im()6923             private Im() {}
6924 
6925             /** MIME type used when storing this in data table. */
6926             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im";
6927 
6928             public static final int TYPE_HOME = 1;
6929             public static final int TYPE_WORK = 2;
6930             public static final int TYPE_OTHER = 3;
6931 
6932             /**
6933              * This column should always be set to {@link #PROTOCOL_CUSTOM} and
6934              * the {@link #CUSTOM_PROTOCOL} should contain the name of the custom protocol.
6935              * The other predefined protocols are deprecated and should not be used.
6936              */
6937             public static final String PROTOCOL = DATA5;
6938 
6939             public static final String CUSTOM_PROTOCOL = DATA6;
6940 
6941             /*
6942              * The predefined IM protocol types.
6943              */
6944             public static final int PROTOCOL_CUSTOM = -1;
6945             /**
6946              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
6947              */
6948             @Deprecated
6949             public static final int PROTOCOL_AIM = 0;
6950             /**
6951              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
6952              */
6953             @Deprecated
6954             public static final int PROTOCOL_MSN = 1;
6955             /**
6956              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
6957              */
6958             @Deprecated
6959             public static final int PROTOCOL_YAHOO = 2;
6960             /**
6961              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
6962              */
6963             @Deprecated
6964             public static final int PROTOCOL_SKYPE = 3;
6965             /**
6966              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
6967              */
6968             @Deprecated
6969             public static final int PROTOCOL_QQ = 4;
6970             /**
6971              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
6972              */
6973             @Deprecated
6974             public static final int PROTOCOL_GOOGLE_TALK = 5;
6975             /**
6976              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
6977              */
6978             @Deprecated
6979             public static final int PROTOCOL_ICQ = 6;
6980             /**
6981              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
6982              */
6983             @Deprecated
6984             public static final int PROTOCOL_JABBER = 7;
6985             /**
6986              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
6987              */
6988             @Deprecated
6989             public static final int PROTOCOL_NETMEETING = 8;
6990 
6991             /**
6992              * Return the string resource that best describes the given
6993              * {@link #TYPE}. Will always return a valid resource.
6994              */
getTypeLabelResource(int type)6995             public static final int getTypeLabelResource(int type) {
6996                 switch (type) {
6997                     case TYPE_HOME: return com.android.internal.R.string.imTypeHome;
6998                     case TYPE_WORK: return com.android.internal.R.string.imTypeWork;
6999                     case TYPE_OTHER: return com.android.internal.R.string.imTypeOther;
7000                     default: return com.android.internal.R.string.imTypeCustom;
7001                 }
7002             }
7003 
7004             /**
7005              * Return a {@link CharSequence} that best describes the given type,
7006              * possibly substituting the given {@link #LABEL} value
7007              * for {@link #TYPE_CUSTOM}.
7008              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)7009             public static final CharSequence getTypeLabel(Resources res, int type,
7010                     @Nullable CharSequence label) {
7011                 if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
7012                     return label;
7013                 } else {
7014                     final int labelRes = getTypeLabelResource(type);
7015                     return res.getText(labelRes);
7016                 }
7017             }
7018 
7019             /**
7020              * Return the string resource that best describes the given
7021              * {@link #PROTOCOL}. Will always return a valid resource.
7022              */
getProtocolLabelResource(int type)7023             public static final int getProtocolLabelResource(int type) {
7024                 switch (type) {
7025                     case PROTOCOL_AIM: return com.android.internal.R.string.imProtocolAim;
7026                     case PROTOCOL_MSN: return com.android.internal.R.string.imProtocolMsn;
7027                     case PROTOCOL_YAHOO: return com.android.internal.R.string.imProtocolYahoo;
7028                     case PROTOCOL_SKYPE: return com.android.internal.R.string.imProtocolSkype;
7029                     case PROTOCOL_QQ: return com.android.internal.R.string.imProtocolQq;
7030                     case PROTOCOL_GOOGLE_TALK: return com.android.internal.R.string.imProtocolGoogleTalk;
7031                     case PROTOCOL_ICQ: return com.android.internal.R.string.imProtocolIcq;
7032                     case PROTOCOL_JABBER: return com.android.internal.R.string.imProtocolJabber;
7033                     case PROTOCOL_NETMEETING: return com.android.internal.R.string.imProtocolNetMeeting;
7034                     default: return com.android.internal.R.string.imProtocolCustom;
7035                 }
7036             }
7037 
7038             /**
7039              * Return a {@link CharSequence} that best describes the given
7040              * protocol, possibly substituting the given
7041              * {@link #CUSTOM_PROTOCOL} value for {@link #PROTOCOL_CUSTOM}.
7042              */
getProtocolLabel(Resources res, int type, CharSequence label)7043             public static final CharSequence getProtocolLabel(Resources res, int type,
7044                     CharSequence label) {
7045                 if (type == PROTOCOL_CUSTOM && !TextUtils.isEmpty(label)) {
7046                     return label;
7047                 } else {
7048                     final int labelRes = getProtocolLabelResource(type);
7049                     return res.getText(labelRes);
7050                 }
7051             }
7052         }
7053 
7054         /**
7055          * <p>
7056          * A data kind representing an organization.
7057          * </p>
7058          * <p>
7059          * You can use all columns defined for {@link ContactsContract.Data} as
7060          * well as the following aliases.
7061          * </p>
7062          * <h2>Column aliases</h2>
7063          * <table class="jd-sumtable">
7064          * <tr>
7065          * <th>Type</th>
7066          * <th>Alias</th><th colspan='2'>Data column</th>
7067          * </tr>
7068          * <tr>
7069          * <td>String</td>
7070          * <td>{@link #COMPANY}</td>
7071          * <td>{@link #DATA1}</td>
7072          * <td></td>
7073          * </tr>
7074          * <tr>
7075          * <td>int</td>
7076          * <td>{@link #TYPE}</td>
7077          * <td>{@link #DATA2}</td>
7078          * <td>Allowed values are:
7079          * <p>
7080          * <ul>
7081          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
7082          * <li>{@link #TYPE_WORK}</li>
7083          * <li>{@link #TYPE_OTHER}</li>
7084          * </ul>
7085          * </p>
7086          * </td>
7087          * </tr>
7088          * <tr>
7089          * <td>String</td>
7090          * <td>{@link #LABEL}</td>
7091          * <td>{@link #DATA3}</td>
7092          * <td></td>
7093          * </tr>
7094          * <tr>
7095          * <td>String</td>
7096          * <td>{@link #TITLE}</td>
7097          * <td>{@link #DATA4}</td>
7098          * <td></td>
7099          * </tr>
7100          * <tr>
7101          * <td>String</td>
7102          * <td>{@link #DEPARTMENT}</td>
7103          * <td>{@link #DATA5}</td>
7104          * <td></td>
7105          * </tr>
7106          * <tr>
7107          * <td>String</td>
7108          * <td>{@link #JOB_DESCRIPTION}</td>
7109          * <td>{@link #DATA6}</td>
7110          * <td></td>
7111          * </tr>
7112          * <tr>
7113          * <td>String</td>
7114          * <td>{@link #SYMBOL}</td>
7115          * <td>{@link #DATA7}</td>
7116          * <td></td>
7117          * </tr>
7118          * <tr>
7119          * <td>String</td>
7120          * <td>{@link #PHONETIC_NAME}</td>
7121          * <td>{@link #DATA8}</td>
7122          * <td></td>
7123          * </tr>
7124          * <tr>
7125          * <td>String</td>
7126          * <td>{@link #OFFICE_LOCATION}</td>
7127          * <td>{@link #DATA9}</td>
7128          * <td></td>
7129          * </tr>
7130          * <tr>
7131          * <td>String</td>
7132          * <td>PHONETIC_NAME_STYLE</td>
7133          * <td>{@link #DATA10}</td>
7134          * <td></td>
7135          * </tr>
7136          * </table>
7137          */
7138         public static final class Organization implements DataColumnsWithJoins, CommonColumns,
7139                 ContactCounts {
7140             /**
7141              * This utility class cannot be instantiated
7142              */
Organization()7143             private Organization() {}
7144 
7145             /** MIME type used when storing this in data table. */
7146             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/organization";
7147 
7148             public static final int TYPE_WORK = 1;
7149             public static final int TYPE_OTHER = 2;
7150 
7151             /**
7152              * The company as the user entered it.
7153              * <P>Type: TEXT</P>
7154              */
7155             public static final String COMPANY = DATA;
7156 
7157             /**
7158              * The position title at this company as the user entered it.
7159              * <P>Type: TEXT</P>
7160              */
7161             public static final String TITLE = DATA4;
7162 
7163             /**
7164              * The department at this company as the user entered it.
7165              * <P>Type: TEXT</P>
7166              */
7167             public static final String DEPARTMENT = DATA5;
7168 
7169             /**
7170              * The job description at this company as the user entered it.
7171              * <P>Type: TEXT</P>
7172              */
7173             public static final String JOB_DESCRIPTION = DATA6;
7174 
7175             /**
7176              * The symbol of this company as the user entered it.
7177              * <P>Type: TEXT</P>
7178              */
7179             public static final String SYMBOL = DATA7;
7180 
7181             /**
7182              * The phonetic name of this company as the user entered it.
7183              * <P>Type: TEXT</P>
7184              */
7185             public static final String PHONETIC_NAME = DATA8;
7186 
7187             /**
7188              * The office location of this organization.
7189              * <P>Type: TEXT</P>
7190              */
7191             public static final String OFFICE_LOCATION = DATA9;
7192 
7193             /**
7194              * The alphabet used for capturing the phonetic name.
7195              * See {@link ContactsContract.PhoneticNameStyle}.
7196              */
7197             public static final String PHONETIC_NAME_STYLE = DATA10;
7198 
7199             /**
7200              * Return the string resource that best describes the given
7201              * {@link #TYPE}. Will always return a valid resource.
7202              */
getTypeLabelResource(int type)7203             public static final int getTypeLabelResource(int type) {
7204                 switch (type) {
7205                     case TYPE_WORK: return com.android.internal.R.string.orgTypeWork;
7206                     case TYPE_OTHER: return com.android.internal.R.string.orgTypeOther;
7207                     default: return com.android.internal.R.string.orgTypeCustom;
7208                 }
7209             }
7210 
7211             /**
7212              * Return a {@link CharSequence} that best describes the given type,
7213              * possibly substituting the given {@link #LABEL} value
7214              * for {@link #TYPE_CUSTOM}.
7215              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)7216             public static final CharSequence getTypeLabel(Resources res, int type,
7217                     @Nullable CharSequence label) {
7218                 if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
7219                     return label;
7220                 } else {
7221                     final int labelRes = getTypeLabelResource(type);
7222                     return res.getText(labelRes);
7223                 }
7224             }
7225         }
7226 
7227         /**
7228          * <p>
7229          * A data kind representing a relation.
7230          * </p>
7231          * <p>
7232          * You can use all columns defined for {@link ContactsContract.Data} as
7233          * well as the following aliases.
7234          * </p>
7235          * <h2>Column aliases</h2>
7236          * <table class="jd-sumtable">
7237          * <tr>
7238          * <th>Type</th>
7239          * <th>Alias</th><th colspan='2'>Data column</th>
7240          * </tr>
7241          * <tr>
7242          * <td>String</td>
7243          * <td>{@link #NAME}</td>
7244          * <td>{@link #DATA1}</td>
7245          * <td></td>
7246          * </tr>
7247          * <tr>
7248          * <td>int</td>
7249          * <td>{@link #TYPE}</td>
7250          * <td>{@link #DATA2}</td>
7251          * <td>Allowed values are:
7252          * <p>
7253          * <ul>
7254          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
7255          * <li>{@link #TYPE_ASSISTANT}</li>
7256          * <li>{@link #TYPE_BROTHER}</li>
7257          * <li>{@link #TYPE_CHILD}</li>
7258          * <li>{@link #TYPE_DOMESTIC_PARTNER}</li>
7259          * <li>{@link #TYPE_FATHER}</li>
7260          * <li>{@link #TYPE_FRIEND}</li>
7261          * <li>{@link #TYPE_MANAGER}</li>
7262          * <li>{@link #TYPE_MOTHER}</li>
7263          * <li>{@link #TYPE_PARENT}</li>
7264          * <li>{@link #TYPE_PARTNER}</li>
7265          * <li>{@link #TYPE_REFERRED_BY}</li>
7266          * <li>{@link #TYPE_RELATIVE}</li>
7267          * <li>{@link #TYPE_SISTER}</li>
7268          * <li>{@link #TYPE_SPOUSE}</li>
7269          * </ul>
7270          * </p>
7271          * </td>
7272          * </tr>
7273          * <tr>
7274          * <td>String</td>
7275          * <td>{@link #LABEL}</td>
7276          * <td>{@link #DATA3}</td>
7277          * <td></td>
7278          * </tr>
7279          * </table>
7280          */
7281         public static final class Relation implements DataColumnsWithJoins, CommonColumns,
7282                 ContactCounts {
7283             /**
7284              * This utility class cannot be instantiated
7285              */
Relation()7286             private Relation() {}
7287 
7288             /** MIME type used when storing this in data table. */
7289             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/relation";
7290 
7291             public static final int TYPE_ASSISTANT = 1;
7292             public static final int TYPE_BROTHER = 2;
7293             public static final int TYPE_CHILD = 3;
7294             public static final int TYPE_DOMESTIC_PARTNER = 4;
7295             public static final int TYPE_FATHER = 5;
7296             public static final int TYPE_FRIEND = 6;
7297             public static final int TYPE_MANAGER = 7;
7298             public static final int TYPE_MOTHER = 8;
7299             public static final int TYPE_PARENT = 9;
7300             public static final int TYPE_PARTNER = 10;
7301             public static final int TYPE_REFERRED_BY = 11;
7302             public static final int TYPE_RELATIVE = 12;
7303             public static final int TYPE_SISTER = 13;
7304             public static final int TYPE_SPOUSE = 14;
7305 
7306             /**
7307              * The name of the relative as the user entered it.
7308              * <P>Type: TEXT</P>
7309              */
7310             public static final String NAME = DATA;
7311 
7312             /**
7313              * Return the string resource that best describes the given
7314              * {@link #TYPE}. Will always return a valid resource.
7315              */
getTypeLabelResource(int type)7316             public static final int getTypeLabelResource(int type) {
7317                 switch (type) {
7318                     case TYPE_ASSISTANT: return com.android.internal.R.string.relationTypeAssistant;
7319                     case TYPE_BROTHER: return com.android.internal.R.string.relationTypeBrother;
7320                     case TYPE_CHILD: return com.android.internal.R.string.relationTypeChild;
7321                     case TYPE_DOMESTIC_PARTNER:
7322                             return com.android.internal.R.string.relationTypeDomesticPartner;
7323                     case TYPE_FATHER: return com.android.internal.R.string.relationTypeFather;
7324                     case TYPE_FRIEND: return com.android.internal.R.string.relationTypeFriend;
7325                     case TYPE_MANAGER: return com.android.internal.R.string.relationTypeManager;
7326                     case TYPE_MOTHER: return com.android.internal.R.string.relationTypeMother;
7327                     case TYPE_PARENT: return com.android.internal.R.string.relationTypeParent;
7328                     case TYPE_PARTNER: return com.android.internal.R.string.relationTypePartner;
7329                     case TYPE_REFERRED_BY:
7330                             return com.android.internal.R.string.relationTypeReferredBy;
7331                     case TYPE_RELATIVE: return com.android.internal.R.string.relationTypeRelative;
7332                     case TYPE_SISTER: return com.android.internal.R.string.relationTypeSister;
7333                     case TYPE_SPOUSE: return com.android.internal.R.string.relationTypeSpouse;
7334                     default: return com.android.internal.R.string.orgTypeCustom;
7335                 }
7336             }
7337 
7338             /**
7339              * Return a {@link CharSequence} that best describes the given type,
7340              * possibly substituting the given {@link #LABEL} value
7341              * for {@link #TYPE_CUSTOM}.
7342              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)7343             public static final CharSequence getTypeLabel(Resources res, int type,
7344                     @Nullable CharSequence label) {
7345                 if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
7346                     return label;
7347                 } else {
7348                     final int labelRes = getTypeLabelResource(type);
7349                     return res.getText(labelRes);
7350                 }
7351             }
7352         }
7353 
7354         /**
7355          * <p>
7356          * A data kind representing an event.
7357          * </p>
7358          * <p>
7359          * You can use all columns defined for {@link ContactsContract.Data} as
7360          * well as the following aliases.
7361          * </p>
7362          * <h2>Column aliases</h2>
7363          * <table class="jd-sumtable">
7364          * <tr>
7365          * <th>Type</th>
7366          * <th>Alias</th><th colspan='2'>Data column</th>
7367          * </tr>
7368          * <tr>
7369          * <td>String</td>
7370          * <td>{@link #START_DATE}</td>
7371          * <td>{@link #DATA1}</td>
7372          * <td></td>
7373          * </tr>
7374          * <tr>
7375          * <td>int</td>
7376          * <td>{@link #TYPE}</td>
7377          * <td>{@link #DATA2}</td>
7378          * <td>Allowed values are:
7379          * <p>
7380          * <ul>
7381          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
7382          * <li>{@link #TYPE_ANNIVERSARY}</li>
7383          * <li>{@link #TYPE_OTHER}</li>
7384          * <li>{@link #TYPE_BIRTHDAY}</li>
7385          * </ul>
7386          * </p>
7387          * </td>
7388          * </tr>
7389          * <tr>
7390          * <td>String</td>
7391          * <td>{@link #LABEL}</td>
7392          * <td>{@link #DATA3}</td>
7393          * <td></td>
7394          * </tr>
7395          * </table>
7396          */
7397         public static final class Event implements DataColumnsWithJoins, CommonColumns,
7398                 ContactCounts {
7399             /**
7400              * This utility class cannot be instantiated
7401              */
Event()7402             private Event() {}
7403 
7404             /** MIME type used when storing this in data table. */
7405             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_event";
7406 
7407             public static final int TYPE_ANNIVERSARY = 1;
7408             public static final int TYPE_OTHER = 2;
7409             public static final int TYPE_BIRTHDAY = 3;
7410 
7411             /**
7412              * The event start date as the user entered it.
7413              * <P>Type: TEXT</P>
7414              */
7415             public static final String START_DATE = DATA;
7416 
7417             /**
7418              * Return the string resource that best describes the given
7419              * {@link #TYPE}. Will always return a valid resource.
7420              */
getTypeResource(Integer type)7421             public static int getTypeResource(Integer type) {
7422                 if (type == null) {
7423                     return com.android.internal.R.string.eventTypeOther;
7424                 }
7425                 switch (type) {
7426                     case TYPE_ANNIVERSARY:
7427                         return com.android.internal.R.string.eventTypeAnniversary;
7428                     case TYPE_BIRTHDAY: return com.android.internal.R.string.eventTypeBirthday;
7429                     case TYPE_OTHER: return com.android.internal.R.string.eventTypeOther;
7430                     default: return com.android.internal.R.string.eventTypeCustom;
7431                 }
7432             }
7433 
7434             /**
7435              * Return a {@link CharSequence} that best describes the given type,
7436              * possibly substituting the given {@link #LABEL} value
7437              * for {@link #TYPE_CUSTOM}.
7438              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)7439             public static final CharSequence getTypeLabel(Resources res, int type,
7440                     @Nullable CharSequence label) {
7441                 if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
7442                     return label;
7443                 } else {
7444                     final int labelRes = getTypeResource(type);
7445                     return res.getText(labelRes);
7446                 }
7447             }
7448         }
7449 
7450         /**
7451          * <p>
7452          * A data kind representing a photo for the contact.
7453          * </p>
7454          * <p>
7455          * Some sync adapters will choose to download photos in a separate
7456          * pass. A common pattern is to use columns {@link ContactsContract.Data#SYNC1}
7457          * through {@link ContactsContract.Data#SYNC4} to store temporary
7458          * data, e.g. the image URL or ID, state of download, server-side version
7459          * of the image.  It is allowed for the {@link #PHOTO} to be null.
7460          * </p>
7461          * <p>
7462          * You can use all columns defined for {@link ContactsContract.Data} as
7463          * well as the following aliases.
7464          * </p>
7465          * <h2>Column aliases</h2>
7466          * <table class="jd-sumtable">
7467          * <tr>
7468          * <th>Type</th>
7469          * <th>Alias</th><th colspan='2'>Data column</th>
7470          * </tr>
7471          * <tr>
7472          * <td>NUMBER</td>
7473          * <td>{@link #PHOTO_FILE_ID}</td>
7474          * <td>{@link #DATA14}</td>
7475          * <td>ID of the hi-res photo file.</td>
7476          * </tr>
7477          * <tr>
7478          * <td>BLOB</td>
7479          * <td>{@link #PHOTO}</td>
7480          * <td>{@link #DATA15}</td>
7481          * <td>By convention, binary data is stored in DATA15.  The thumbnail of the
7482          * photo is stored in this column.</td>
7483          * </tr>
7484          * </table>
7485          */
7486         public static final class Photo implements DataColumnsWithJoins, ContactCounts {
7487             /**
7488              * This utility class cannot be instantiated
7489              */
Photo()7490             private Photo() {}
7491 
7492             /** MIME type used when storing this in data table. */
7493             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo";
7494 
7495             /**
7496              * Photo file ID for the display photo of the raw contact.
7497              * See {@link ContactsContract.DisplayPhoto}.
7498              * <p>
7499              * Type: NUMBER
7500              */
7501             public static final String PHOTO_FILE_ID = DATA14;
7502 
7503             /**
7504              * Thumbnail photo of the raw contact. This is the raw bytes of an image
7505              * that could be inflated using {@link android.graphics.BitmapFactory}.
7506              * <p>
7507              * Type: BLOB
7508              */
7509             public static final String PHOTO = DATA15;
7510         }
7511 
7512         /**
7513          * <p>
7514          * Notes about the contact.
7515          * </p>
7516          * <p>
7517          * You can use all columns defined for {@link ContactsContract.Data} as
7518          * well as the following aliases.
7519          * </p>
7520          * <h2>Column aliases</h2>
7521          * <table class="jd-sumtable">
7522          * <tr>
7523          * <th>Type</th>
7524          * <th>Alias</th><th colspan='2'>Data column</th>
7525          * </tr>
7526          * <tr>
7527          * <td>String</td>
7528          * <td>{@link #NOTE}</td>
7529          * <td>{@link #DATA1}</td>
7530          * <td></td>
7531          * </tr>
7532          * </table>
7533          */
7534         public static final class Note implements DataColumnsWithJoins, ContactCounts {
7535             /**
7536              * This utility class cannot be instantiated
7537              */
Note()7538             private Note() {}
7539 
7540             /** MIME type used when storing this in data table. */
7541             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/note";
7542 
7543             /**
7544              * The note text.
7545              * <P>Type: TEXT</P>
7546              */
7547             public static final String NOTE = DATA1;
7548         }
7549 
7550         /**
7551          * <p>
7552          * Group Membership.
7553          * </p>
7554          * <p>
7555          * You can use all columns defined for {@link ContactsContract.Data} as
7556          * well as the following aliases.
7557          * </p>
7558          * <h2>Column aliases</h2>
7559          * <table class="jd-sumtable">
7560          * <tr>
7561          * <th>Type</th>
7562          * <th>Alias</th><th colspan='2'>Data column</th>
7563          * </tr>
7564          * <tr>
7565          * <td>long</td>
7566          * <td>{@link #GROUP_ROW_ID}</td>
7567          * <td>{@link #DATA1}</td>
7568          * <td></td>
7569          * </tr>
7570          * <tr>
7571          * <td>String</td>
7572          * <td>{@link #GROUP_SOURCE_ID}</td>
7573          * <td>none</td>
7574          * <td>
7575          * <p>
7576          * The sourceid of the group that this group membership refers to.
7577          * Exactly one of this or {@link #GROUP_ROW_ID} must be set when
7578          * inserting a row.
7579          * </p>
7580          * <p>
7581          * If this field is specified, the provider will first try to
7582          * look up a group with this {@link Groups Groups.SOURCE_ID}.  If such a group
7583          * is found, it will use the corresponding row id.  If the group is not
7584          * found, it will create one.
7585          * </td>
7586          * </tr>
7587          * </table>
7588          */
7589         public static final class GroupMembership implements DataColumnsWithJoins, ContactCounts {
7590             /**
7591              * This utility class cannot be instantiated
7592              */
GroupMembership()7593             private GroupMembership() {}
7594 
7595             /** MIME type used when storing this in data table. */
7596             public static final String CONTENT_ITEM_TYPE =
7597                     "vnd.android.cursor.item/group_membership";
7598 
7599             /**
7600              * The row id of the group that this group membership refers to. Exactly one of
7601              * this or {@link #GROUP_SOURCE_ID} must be set when inserting a row.
7602              * <P>Type: INTEGER</P>
7603              */
7604             public static final String GROUP_ROW_ID = DATA1;
7605 
7606             /**
7607              * The sourceid of the group that this group membership refers to.  Exactly one of
7608              * this or {@link #GROUP_ROW_ID} must be set when inserting a row.
7609              * <P>Type: TEXT</P>
7610              */
7611             public static final String GROUP_SOURCE_ID = "group_sourceid";
7612         }
7613 
7614         /**
7615          * <p>
7616          * A data kind representing a website related to the contact.
7617          * </p>
7618          * <p>
7619          * You can use all columns defined for {@link ContactsContract.Data} as
7620          * well as the following aliases.
7621          * </p>
7622          * <h2>Column aliases</h2>
7623          * <table class="jd-sumtable">
7624          * <tr>
7625          * <th>Type</th>
7626          * <th>Alias</th><th colspan='2'>Data column</th>
7627          * </tr>
7628          * <tr>
7629          * <td>String</td>
7630          * <td>{@link #URL}</td>
7631          * <td>{@link #DATA1}</td>
7632          * <td></td>
7633          * </tr>
7634          * <tr>
7635          * <td>int</td>
7636          * <td>{@link #TYPE}</td>
7637          * <td>{@link #DATA2}</td>
7638          * <td>Allowed values are:
7639          * <p>
7640          * <ul>
7641          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
7642          * <li>{@link #TYPE_HOMEPAGE}</li>
7643          * <li>{@link #TYPE_BLOG}</li>
7644          * <li>{@link #TYPE_PROFILE}</li>
7645          * <li>{@link #TYPE_HOME}</li>
7646          * <li>{@link #TYPE_WORK}</li>
7647          * <li>{@link #TYPE_FTP}</li>
7648          * <li>{@link #TYPE_OTHER}</li>
7649          * </ul>
7650          * </p>
7651          * </td>
7652          * </tr>
7653          * <tr>
7654          * <td>String</td>
7655          * <td>{@link #LABEL}</td>
7656          * <td>{@link #DATA3}</td>
7657          * <td></td>
7658          * </tr>
7659          * </table>
7660          */
7661         public static final class Website implements DataColumnsWithJoins, CommonColumns,
7662                 ContactCounts {
7663             /**
7664              * This utility class cannot be instantiated
7665              */
Website()7666             private Website() {}
7667 
7668             /** MIME type used when storing this in data table. */
7669             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/website";
7670 
7671             public static final int TYPE_HOMEPAGE = 1;
7672             public static final int TYPE_BLOG = 2;
7673             public static final int TYPE_PROFILE = 3;
7674             public static final int TYPE_HOME = 4;
7675             public static final int TYPE_WORK = 5;
7676             public static final int TYPE_FTP = 6;
7677             public static final int TYPE_OTHER = 7;
7678 
7679             /**
7680              * The website URL string.
7681              * <P>Type: TEXT</P>
7682              */
7683             public static final String URL = DATA;
7684         }
7685 
7686         /**
7687          * <p>
7688          * A data kind representing a SIP address for the contact.
7689          * </p>
7690          * <p>
7691          * You can use all columns defined for {@link ContactsContract.Data} as
7692          * well as the following aliases.
7693          * </p>
7694          * <h2>Column aliases</h2>
7695          * <table class="jd-sumtable">
7696          * <tr>
7697          * <th>Type</th>
7698          * <th>Alias</th><th colspan='2'>Data column</th>
7699          * </tr>
7700          * <tr>
7701          * <td>String</td>
7702          * <td>{@link #SIP_ADDRESS}</td>
7703          * <td>{@link #DATA1}</td>
7704          * <td></td>
7705          * </tr>
7706          * <tr>
7707          * <td>int</td>
7708          * <td>{@link #TYPE}</td>
7709          * <td>{@link #DATA2}</td>
7710          * <td>Allowed values are:
7711          * <p>
7712          * <ul>
7713          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
7714          * <li>{@link #TYPE_HOME}</li>
7715          * <li>{@link #TYPE_WORK}</li>
7716          * <li>{@link #TYPE_OTHER}</li>
7717          * </ul>
7718          * </p>
7719          * </td>
7720          * </tr>
7721          * <tr>
7722          * <td>String</td>
7723          * <td>{@link #LABEL}</td>
7724          * <td>{@link #DATA3}</td>
7725          * <td></td>
7726          * </tr>
7727          * </table>
7728          *
7729          * @deprecated This field may not be well supported by some contacts apps and is discouraged
7730          * to use.
7731          */
7732         @Deprecated
7733         public static final class SipAddress implements DataColumnsWithJoins, CommonColumns,
7734                 ContactCounts {
7735             /**
7736              * This utility class cannot be instantiated
7737              */
SipAddress()7738             private SipAddress() {}
7739 
7740             /** MIME type used when storing this in data table. */
7741             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sip_address";
7742 
7743             public static final int TYPE_HOME = 1;
7744             public static final int TYPE_WORK = 2;
7745             public static final int TYPE_OTHER = 3;
7746 
7747             /**
7748              * The SIP address.
7749              * <P>Type: TEXT</P>
7750              */
7751             public static final String SIP_ADDRESS = DATA1;
7752             // ...and TYPE and LABEL come from the CommonColumns interface.
7753 
7754             /**
7755              * Return the string resource that best describes the given
7756              * {@link #TYPE}. Will always return a valid resource.
7757              */
getTypeLabelResource(int type)7758             public static final int getTypeLabelResource(int type) {
7759                 switch (type) {
7760                     case TYPE_HOME: return com.android.internal.R.string.sipAddressTypeHome;
7761                     case TYPE_WORK: return com.android.internal.R.string.sipAddressTypeWork;
7762                     case TYPE_OTHER: return com.android.internal.R.string.sipAddressTypeOther;
7763                     default: return com.android.internal.R.string.sipAddressTypeCustom;
7764                 }
7765             }
7766 
7767             /**
7768              * Return a {@link CharSequence} that best describes the given type,
7769              * possibly substituting the given {@link #LABEL} value
7770              * for {@link #TYPE_CUSTOM}.
7771              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)7772             public static final CharSequence getTypeLabel(Resources res, int type,
7773                     @Nullable CharSequence label) {
7774                 if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
7775                     return label;
7776                 } else {
7777                     final int labelRes = getTypeLabelResource(type);
7778                     return res.getText(labelRes);
7779                 }
7780             }
7781         }
7782 
7783         /**
7784          * A data kind representing an Identity related to the contact.
7785          * <p>
7786          * This can be used as a signal by the aggregator to combine raw contacts into
7787          * contacts, e.g. if two contacts have Identity rows with
7788          * the same NAMESPACE and IDENTITY values the aggregator can know that they refer
7789          * to the same person.
7790          * </p>
7791          */
7792         public static final class Identity implements DataColumnsWithJoins, ContactCounts {
7793             /**
7794              * This utility class cannot be instantiated
7795              */
Identity()7796             private Identity() {}
7797 
7798             /** MIME type used when storing this in data table. */
7799             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/identity";
7800 
7801             /**
7802              * The identity string.
7803              * <P>Type: TEXT</P>
7804              */
7805             public static final String IDENTITY = DataColumns.DATA1;
7806 
7807             /**
7808              * The namespace of the identity string, e.g. "com.google"
7809              * <P>Type: TEXT</P>
7810              */
7811             public static final String NAMESPACE = DataColumns.DATA2;
7812         }
7813 
7814         /**
7815          * <p>
7816          * Convenient functionalities for "callable" data. Note that, this is NOT a separate data
7817          * kind.
7818          * </p>
7819          * <p>
7820          * This URI allows the ContactsProvider to return a unified result for "callable" data
7821          * that users can use for calling purposes. {@link Phone} and {@link SipAddress} are the
7822          * current examples for "callable", but may be expanded to the other types.
7823          * </p>
7824          * <p>
7825          * Each returned row may have a different MIMETYPE and thus different interpretation for
7826          * each column. For example the meaning for {@link Phone}'s type is different than
7827          * {@link SipAddress}'s.
7828          * </p>
7829          */
7830         public static final class Callable implements DataColumnsWithJoins, CommonColumns,
7831                 ContactCounts {
7832             /**
7833              * Similar to {@link Phone#CONTENT_URI}, but returns callable data instead of only
7834              * phone numbers.
7835              */
7836             public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
7837                     "callables");
7838             /**
7839              * <p>Similar to {@link Phone#CONTENT_FILTER_URI}, but allows users to filter callable
7840              * data.
7841              *
7842              * <p class="caution"><b>Caution: </b>This field no longer sorts results based on
7843              * contacts frequency. For more information, see the
7844              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
7845              * page.
7846              */
7847             public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(CONTENT_URI,
7848                     "filter");
7849 
7850             /**
7851              * <p>Similar to {@link Phone#ENTERPRISE_CONTENT_FILTER_URI}, but allows users to filter
7852              * callable data. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
7853              * parameters, otherwise it will throw IllegalArgumentException.
7854              *
7855              * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
7856              * this field doesn't sort results based on contacts frequency. For more information,
7857              * see the
7858              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
7859              * page.</p>
7860              */
7861             public static final Uri ENTERPRISE_CONTENT_FILTER_URI = Uri.withAppendedPath(
7862                     CONTENT_URI, "filter_enterprise");
7863         }
7864 
7865         /**
7866          * A special class of data items, used to refer to types of data that can be used to attempt
7867          * to start communicating with a person ({@link Phone} and {@link Email}). Note that this
7868          * is NOT a separate data kind.
7869          *
7870          * This URI allows the ContactsProvider to return a unified result for data items that users
7871          * can use to initiate communications with another contact. {@link Phone} and {@link Email}
7872          * are the current data types in this category.
7873          */
7874         public static final class Contactables implements DataColumnsWithJoins, CommonColumns,
7875                 ContactCounts {
7876             /**
7877              * The content:// style URI for these data items, which requests a directory of data
7878              * rows matching the selection criteria.
7879              */
7880             public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
7881                     "contactables");
7882 
7883             /**
7884              * <p>The content:// style URI for these data items, which allows for a query parameter
7885              * to be appended onto the end to filter for data items matching the query.
7886              *
7887              * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
7888              * this field doesn't sort results based on contacts frequency. For more information,
7889              * see the
7890              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
7891              * page.
7892              */
7893             public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(
7894                     Contactables.CONTENT_URI, "filter");
7895 
7896             /**
7897              * A boolean parameter for {@link Data#CONTENT_URI}.
7898              * This specifies whether or not the returned data items should be filtered to show
7899              * data items belonging to visible contacts only.
7900              */
7901             public static final String VISIBLE_CONTACTS_ONLY = "visible_contacts_only";
7902         }
7903     }
7904 
7905     /**
7906      * @see Groups
7907      */
7908     protected interface GroupsColumns {
7909         /**
7910          * The data set within the account that this group belongs to.  This allows
7911          * multiple sync adapters for the same account type to distinguish between
7912          * each others' group data.
7913          *
7914          * This is empty by default, and is completely optional.  It only needs to
7915          * be populated if multiple sync adapters are entering distinct group data
7916          * for the same account type and account name.
7917          * <P>Type: TEXT</P>
7918          */
7919         public static final String DATA_SET = "data_set";
7920 
7921         /**
7922          * A concatenation of the account type and data set (delimited by a forward
7923          * slash) - if the data set is empty, this will be the same as the account
7924          * type.  For applications that need to be aware of the data set, this can
7925          * be used instead of account type to distinguish sets of data.  This is
7926          * never intended to be used for specifying accounts.
7927          * @hide
7928          */
7929         public static final String ACCOUNT_TYPE_AND_DATA_SET = "account_type_and_data_set";
7930 
7931         /**
7932          * The display title of this group.
7933          * <p>
7934          * Type: TEXT
7935          */
7936         public static final String TITLE = "title";
7937 
7938         /**
7939          * The package name to use when creating {@link Resources} objects for
7940          * this group. This value is only designed for use when building user
7941          * interfaces, and should not be used to infer the owner.
7942          */
7943         public static final String RES_PACKAGE = "res_package";
7944 
7945         /**
7946          * The display title of this group to load as a resource from
7947          * {@link #RES_PACKAGE}, which may be localized.
7948          * <P>Type: TEXT</P>
7949          */
7950         public static final String TITLE_RES = "title_res";
7951 
7952         /**
7953          * Notes about the group.
7954          * <p>
7955          * Type: TEXT
7956          */
7957         public static final String NOTES = "notes";
7958 
7959         /**
7960          * The ID of this group if it is a System Group, i.e. a group that has a special meaning
7961          * to the sync adapter, null otherwise.
7962          * <P>Type: TEXT</P>
7963          */
7964         public static final String SYSTEM_ID = "system_id";
7965 
7966         /**
7967          * The total number of {@link Contacts} that have
7968          * {@link CommonDataKinds.GroupMembership} in this group. Read-only value that is only
7969          * present when querying {@link Groups#CONTENT_SUMMARY_URI}.
7970          * <p>
7971          * Type: INTEGER
7972          */
7973         public static final String SUMMARY_COUNT = "summ_count";
7974 
7975         /**
7976          * A boolean query parameter that can be used with {@link Groups#CONTENT_SUMMARY_URI}.
7977          * It will additionally return {@link #SUMMARY_GROUP_COUNT_PER_ACCOUNT}.
7978          *
7979          * @hide
7980          */
7981         public static final String PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT =
7982                 "return_group_count_per_account";
7983 
7984         /**
7985          * The total number of groups of the account that a group belongs to.
7986          * This column is available only when the parameter
7987          * {@link #PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT} is specified in
7988          * {@link Groups#CONTENT_SUMMARY_URI}.
7989          *
7990          * For example, when the account "A" has two groups "group1" and "group2", and the account
7991          * "B" has a group "group3", the rows for "group1" and "group2" return "2" and the row for
7992          * "group3" returns "1" for this column.
7993          *
7994          * Note: This counts only non-favorites, non-auto-add, and not deleted groups.
7995          *
7996          * Type: INTEGER
7997          * @hide
7998          */
7999         public static final String SUMMARY_GROUP_COUNT_PER_ACCOUNT = "group_count_per_account";
8000 
8001         /**
8002          * The total number of {@link Contacts} that have both
8003          * {@link CommonDataKinds.GroupMembership} in this group, and also have phone numbers.
8004          * Read-only value that is only present when querying
8005          * {@link Groups#CONTENT_SUMMARY_URI}.
8006          * <p>
8007          * Type: INTEGER
8008          */
8009         public static final String SUMMARY_WITH_PHONES = "summ_phones";
8010 
8011         /**
8012          * Flag indicating if the contacts belonging to this group should be
8013          * visible in any user interface.
8014          * <p>
8015          * Type: INTEGER (boolean)
8016          */
8017         public static final String GROUP_VISIBLE = "group_visible";
8018 
8019         /**
8020          * The "deleted" flag: "0" by default, "1" if the row has been marked
8021          * for deletion. When {@link android.content.ContentResolver#delete} is
8022          * called on a group, it is marked for deletion. The sync adaptor
8023          * deletes the group on the server and then calls ContactResolver.delete
8024          * once more, this time setting the the
8025          * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to
8026          * finalize the data removal.
8027          * <P>Type: INTEGER</P>
8028          */
8029         public static final String DELETED = "deleted";
8030 
8031         /**
8032          * Whether this group should be synced if the SYNC_EVERYTHING settings
8033          * is false for this group's account.
8034          * <p>
8035          * Type: INTEGER (boolean)
8036          */
8037         public static final String SHOULD_SYNC = "should_sync";
8038 
8039         /**
8040          * Any newly created contacts will automatically be added to groups that have this
8041          * flag set to true.
8042          * <p>
8043          * Type: INTEGER (boolean)
8044          */
8045         public static final String AUTO_ADD = "auto_add";
8046 
8047         /**
8048          * When a contacts is marked as a favorites it will be automatically added
8049          * to the groups that have this flag set, and when it is removed from favorites
8050          * it will be removed from these groups.
8051          * <p>
8052          * Type: INTEGER (boolean)
8053          */
8054         public static final String FAVORITES = "favorites";
8055 
8056         /**
8057          * The "read-only" flag: "0" by default, "1" if the row cannot be modified or
8058          * deleted except by a sync adapter.  See {@link ContactsContract#CALLER_IS_SYNCADAPTER}.
8059          * <P>Type: INTEGER</P>
8060          */
8061         public static final String GROUP_IS_READ_ONLY = "group_is_read_only";
8062     }
8063 
8064     /**
8065      * Constants for the groups table. Only per-account groups are supported.
8066      * <h2>Columns</h2>
8067      * <table class="jd-sumtable">
8068      * <tr>
8069      * <th colspan='4'>Groups</th>
8070      * </tr>
8071      * <tr>
8072      * <td>long</td>
8073      * <td>{@link #_ID}</td>
8074      * <td>read-only</td>
8075      * <td>Row ID. Sync adapter should try to preserve row IDs during updates.
8076      * In other words, it would be a really bad idea to delete and reinsert a
8077      * group. A sync adapter should always do an update instead.</td>
8078      * </tr>
8079      # <tr>
8080      * <td>String</td>
8081      * <td>{@link #DATA_SET}</td>
8082      * <td>read/write-once</td>
8083      * <td>
8084      * <p>
8085      * The data set within the account that this group belongs to.  This allows
8086      * multiple sync adapters for the same account type to distinguish between
8087      * each others' group data.  The combination of {@link #ACCOUNT_TYPE},
8088      * {@link #ACCOUNT_NAME}, and {@link #DATA_SET} identifies a set of data
8089      * that is associated with a single sync adapter.
8090      * </p>
8091      * <p>
8092      * This is empty by default, and is completely optional.  It only needs to
8093      * be populated if multiple sync adapters are entering distinct data for
8094      * the same account type and account name.
8095      * </p>
8096      * <p>
8097      * It should be set at the time the group is inserted and never changed
8098      * afterwards.
8099      * </p>
8100      * </td>
8101      * </tr>
8102      * <tr>
8103      * <td>String</td>
8104      * <td>{@link #TITLE}</td>
8105      * <td>read/write</td>
8106      * <td>The display title of this group.</td>
8107      * </tr>
8108      * <tr>
8109      * <td>String</td>
8110      * <td>{@link #NOTES}</td>
8111      * <td>read/write</td>
8112      * <td>Notes about the group.</td>
8113      * </tr>
8114      * <tr>
8115      * <td>String</td>
8116      * <td>{@link #SYSTEM_ID}</td>
8117      * <td>read/write</td>
8118      * <td>The ID of this group if it is a System Group, i.e. a group that has a
8119      * special meaning to the sync adapter, null otherwise.</td>
8120      * </tr>
8121      * <tr>
8122      * <td>int</td>
8123      * <td>{@link #SUMMARY_COUNT}</td>
8124      * <td>read-only</td>
8125      * <td>The total number of {@link Contacts} that have
8126      * {@link CommonDataKinds.GroupMembership} in this group. Read-only value
8127      * that is only present when querying {@link Groups#CONTENT_SUMMARY_URI}.</td>
8128      * </tr>
8129      * <tr>
8130      * <td>int</td>
8131      * <td>{@link #SUMMARY_WITH_PHONES}</td>
8132      * <td>read-only</td>
8133      * <td>The total number of {@link Contacts} that have both
8134      * {@link CommonDataKinds.GroupMembership} in this group, and also have
8135      * phone numbers. Read-only value that is only present when querying
8136      * {@link Groups#CONTENT_SUMMARY_URI}.</td>
8137      * </tr>
8138      * <tr>
8139      * <td>int</td>
8140      * <td>{@link #GROUP_VISIBLE}</td>
8141      * <td>read-only</td>
8142      * <td>Flag indicating if the contacts belonging to this group should be
8143      * visible in any user interface. Allowed values: 0 and 1.</td>
8144      * </tr>
8145      * <tr>
8146      * <td>int</td>
8147      * <td>{@link #DELETED}</td>
8148      * <td>read/write</td>
8149      * <td>The "deleted" flag: "0" by default, "1" if the row has been marked
8150      * for deletion. When {@link android.content.ContentResolver#delete} is
8151      * called on a group, it is marked for deletion. The sync adaptor deletes
8152      * the group on the server and then calls ContactResolver.delete once more,
8153      * this time setting the the {@link ContactsContract#CALLER_IS_SYNCADAPTER}
8154      * query parameter to finalize the data removal.</td>
8155      * </tr>
8156      * <tr>
8157      * <td>int</td>
8158      * <td>{@link #SHOULD_SYNC}</td>
8159      * <td>read/write</td>
8160      * <td>Whether this group should be synced if the SYNC_EVERYTHING settings
8161      * is false for this group's account.</td>
8162      * </tr>
8163      * </table>
8164      */
8165     public static final class Groups implements BaseColumns, GroupsColumns, SyncColumns {
8166         /**
8167          * This utility class cannot be instantiated
8168          */
Groups()8169         private Groups() {
8170         }
8171 
8172         /**
8173          * The content:// style URI for this table
8174          */
8175         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "groups");
8176 
8177         /**
8178          * The content:// style URI for this table joined with details data from
8179          * {@link ContactsContract.Data}.
8180          */
8181         public static final Uri CONTENT_SUMMARY_URI = Uri.withAppendedPath(AUTHORITY_URI,
8182                 "groups_summary");
8183 
8184         /**
8185          * The MIME type of a directory of groups.
8186          */
8187         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/group";
8188 
8189         /**
8190          * The MIME type of a single group.
8191          */
8192         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/group";
8193 
newEntityIterator(Cursor cursor)8194         public static EntityIterator newEntityIterator(Cursor cursor) {
8195             return new EntityIteratorImpl(cursor);
8196         }
8197 
8198         private static class EntityIteratorImpl extends CursorEntityIterator {
EntityIteratorImpl(Cursor cursor)8199             public EntityIteratorImpl(Cursor cursor) {
8200                 super(cursor);
8201             }
8202 
8203             @Override
getEntityAndIncrementCursor(Cursor cursor)8204             public Entity getEntityAndIncrementCursor(Cursor cursor) throws RemoteException {
8205                 // we expect the cursor is already at the row we need to read from
8206                 final ContentValues values = new ContentValues();
8207                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, _ID);
8208                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, ACCOUNT_NAME);
8209                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, ACCOUNT_TYPE);
8210                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, DIRTY);
8211                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, VERSION);
8212                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SOURCE_ID);
8213                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, RES_PACKAGE);
8214                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, TITLE);
8215                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, TITLE_RES);
8216                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, GROUP_VISIBLE);
8217                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYNC1);
8218                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYNC2);
8219                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYNC3);
8220                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYNC4);
8221                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYSTEM_ID);
8222                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, DELETED);
8223                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, NOTES);
8224                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SHOULD_SYNC);
8225                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, FAVORITES);
8226                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, AUTO_ADD);
8227                 cursor.moveToNext();
8228                 return new Entity(values);
8229             }
8230         }
8231     }
8232 
8233     /**
8234      * <p>
8235      * Constants for the contact aggregation exceptions table, which contains
8236      * aggregation rules overriding those used by automatic aggregation. This
8237      * type only supports query and update. Neither insert nor delete are
8238      * supported.
8239      * </p>
8240      * <h2>Columns</h2>
8241      * <table class="jd-sumtable">
8242      * <tr>
8243      * <th colspan='4'>AggregationExceptions</th>
8244      * </tr>
8245      * <tr>
8246      * <td>int</td>
8247      * <td>{@link #TYPE}</td>
8248      * <td>read/write</td>
8249      * <td>The type of exception: {@link #TYPE_KEEP_TOGETHER},
8250      * {@link #TYPE_KEEP_SEPARATE} or {@link #TYPE_AUTOMATIC}.</td>
8251      * </tr>
8252      * <tr>
8253      * <td>long</td>
8254      * <td>{@link #RAW_CONTACT_ID1}</td>
8255      * <td>read/write</td>
8256      * <td>A reference to the {@link RawContacts#_ID} of the raw contact that
8257      * the rule applies to.</td>
8258      * </tr>
8259      * <tr>
8260      * <td>long</td>
8261      * <td>{@link #RAW_CONTACT_ID2}</td>
8262      * <td>read/write</td>
8263      * <td>A reference to the other {@link RawContacts#_ID} of the raw contact
8264      * that the rule applies to.</td>
8265      * </tr>
8266      * </table>
8267      */
8268     public static final class AggregationExceptions implements BaseColumns {
8269         /**
8270          * This utility class cannot be instantiated
8271          */
AggregationExceptions()8272         private AggregationExceptions() {}
8273 
8274         /**
8275          * The content:// style URI for this table
8276          */
8277         public static final Uri CONTENT_URI =
8278                 Uri.withAppendedPath(AUTHORITY_URI, "aggregation_exceptions");
8279 
8280         /**
8281          * The MIME type of {@link #CONTENT_URI} providing a directory of data.
8282          */
8283         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/aggregation_exception";
8284 
8285         /**
8286          * The MIME type of a {@link #CONTENT_URI} subdirectory of an aggregation exception
8287          */
8288         public static final String CONTENT_ITEM_TYPE =
8289                 "vnd.android.cursor.item/aggregation_exception";
8290 
8291         /**
8292          * The type of exception: {@link #TYPE_KEEP_TOGETHER}, {@link #TYPE_KEEP_SEPARATE} or
8293          * {@link #TYPE_AUTOMATIC}.
8294          *
8295          * <P>Type: INTEGER</P>
8296          */
8297         public static final String TYPE = "type";
8298 
8299         /**
8300          * Allows the provider to automatically decide whether the specified raw contacts should
8301          * be included in the same aggregate contact or not.
8302          */
8303         public static final int TYPE_AUTOMATIC = 0;
8304 
8305         /**
8306          * Makes sure that the specified raw contacts are included in the same
8307          * aggregate contact.
8308          */
8309         public static final int TYPE_KEEP_TOGETHER = 1;
8310 
8311         /**
8312          * Makes sure that the specified raw contacts are NOT included in the same
8313          * aggregate contact.
8314          */
8315         public static final int TYPE_KEEP_SEPARATE = 2;
8316 
8317         /**
8318          * A reference to the {@link RawContacts#_ID} of the raw contact that the rule applies to.
8319          */
8320         public static final String RAW_CONTACT_ID1 = "raw_contact_id1";
8321 
8322         /**
8323          * A reference to the other {@link RawContacts#_ID} of the raw contact that the rule
8324          * applies to.
8325          */
8326         public static final String RAW_CONTACT_ID2 = "raw_contact_id2";
8327     }
8328 
8329 
8330     /**
8331      * Class containing utility methods around determine what accounts in the ContactsProvider are
8332      * related to the SIM cards in the device.
8333      * <p>
8334      * Apps interested in managing contacts from SIM cards can query the ContactsProvider using
8335      * {@link #getSimAccounts(ContentResolver)} to get all accounts that relate to SIM cards. They
8336      * can also register a receiver for the {@link #ACTION_SIM_ACCOUNTS_CHANGED} broadcast to be
8337      * notified when these accounts change.
8338      */
8339     public static final class SimContacts {
8340         /**
8341          * This utility class cannot be instantiated
8342          */
SimContacts()8343         private SimContacts() {
8344         }
8345 
8346         /**
8347          * The method to invoke in order to add a new SIM account for a newly inserted SIM card.
8348          *
8349          * @hide
8350          */
8351         public static final String ADD_SIM_ACCOUNT_METHOD = "addSimAccount";
8352 
8353         /**
8354          * The method to invoke in order to remove a SIM account once the corresponding SIM card is
8355          * ejected.
8356          *
8357          * @hide
8358          */
8359         public static final String REMOVE_SIM_ACCOUNT_METHOD = "removeSimAccount";
8360 
8361         /**
8362          * The method to invoke in order to query all SIM accounts.
8363          *
8364          * @hide
8365          */
8366         public static final String QUERY_SIM_ACCOUNTS_METHOD = "querySimAccounts";
8367 
8368         /**
8369          * Key to add in the outgoing Bundle for the SIM slot.
8370          *
8371          * @hide
8372          */
8373         public static final String KEY_SIM_SLOT_INDEX = "key_sim_slot_index";
8374 
8375         /**
8376          * Key to add in the outgoing Bundle for the SIM account's EF type.
8377          * See {@link SimAccount#mEfType} for more information.
8378          *
8379          * @hide
8380          */
8381         public static final String KEY_SIM_EF_TYPE = "key_sim_ef_type";
8382 
8383         /**
8384          * Key to add in the outgoing Bundle for the account name.
8385          *
8386          * @hide
8387          */
8388         public static final String KEY_ACCOUNT_NAME = "key_sim_account_name";
8389 
8390         /**
8391          * Key to add in the outgoing Bundle for the account type.
8392          *
8393          * @hide
8394          */
8395         public static final String KEY_ACCOUNT_TYPE = "key_sim_account_type";
8396 
8397         /**
8398          * Key in the incoming Bundle for the all the SIM accounts.
8399          *
8400          * @hide
8401          */
8402         public static final String KEY_SIM_ACCOUNTS = "key_sim_accounts";
8403 
8404         /**
8405          * Broadcast Action: SIM accounts have changed, call
8406          * {@link #getSimAccounts(ContentResolver)} to get the latest.
8407          */
8408         @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
8409         public static final String ACTION_SIM_ACCOUNTS_CHANGED =
8410                 "android.provider.action.SIM_ACCOUNTS_CHANGED";
8411 
8412         /**
8413          * Adds a new SIM account that maps to the corresponding SIM slot.
8414          *
8415          * @param accountName     accountName value for the account
8416          * @param accountType     accountType value for the account
8417          * @param contentResolver to perform the operation on.
8418          * @param simSlotIndex    the SIM slot index of this new account.
8419          * @param efType          the EF type of this new account.
8420          * @hide
8421          */
8422         @SystemApi
8423         @RequiresPermission("android.contacts.permission.MANAGE_SIM_ACCOUNTS")
addSimAccount(@onNull ContentResolver contentResolver, @NonNull String accountName, @NonNull String accountType, int simSlotIndex, int efType)8424         public static void addSimAccount(@NonNull ContentResolver contentResolver,
8425                 @NonNull String accountName,
8426                 @NonNull String accountType,
8427                 int simSlotIndex,
8428                 int efType) {
8429             if (simSlotIndex < 0) {
8430                 throw new IllegalArgumentException("Sim slot is negative");
8431             }
8432             if (!SimAccount.getValidEfTypes().contains(efType)) {
8433                 throw new IllegalArgumentException("Invalid EF type");
8434             }
8435             if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
8436                 throw new IllegalArgumentException("Account name or type is empty");
8437             }
8438 
8439             Bundle extras = new Bundle();
8440             extras.putInt(KEY_SIM_SLOT_INDEX, simSlotIndex);
8441             extras.putInt(KEY_SIM_EF_TYPE, efType);
8442             extras.putString(KEY_ACCOUNT_NAME, accountName);
8443             extras.putString(KEY_ACCOUNT_TYPE, accountType);
8444 
8445             nullSafeCall(contentResolver, ContactsContract.AUTHORITY_URI,
8446                     ContactsContract.SimContacts.ADD_SIM_ACCOUNT_METHOD,
8447                     null, extras);
8448         }
8449 
8450         /**
8451          * Removes all SIM accounts that map to the corresponding SIM slot.
8452          *
8453          * @param contentResolver to perform the operation on.
8454          * @param simSlotIndex    the SIM slot index of the accounts to remove.
8455          * @hide
8456          */
8457         @SystemApi
8458         @RequiresPermission("android.contacts.permission.MANAGE_SIM_ACCOUNTS")
removeSimAccounts(@onNull ContentResolver contentResolver, int simSlotIndex)8459         public static void removeSimAccounts(@NonNull ContentResolver contentResolver,
8460                 int simSlotIndex) {
8461             if (simSlotIndex < 0) {
8462                 throw new IllegalArgumentException("Sim slot is negative");
8463             }
8464 
8465             Bundle extras = new Bundle();
8466             extras.putInt(KEY_SIM_SLOT_INDEX, simSlotIndex);
8467 
8468             nullSafeCall(contentResolver, ContactsContract.AUTHORITY_URI,
8469                     ContactsContract.SimContacts.REMOVE_SIM_ACCOUNT_METHOD,
8470                     null, extras);
8471         }
8472 
8473         /**
8474          * Returns all known SIM accounts. May be empty but never null.
8475          *
8476          * @param contentResolver content resolver to query.
8477          */
getSimAccounts( @onNull ContentResolver contentResolver)8478         public static @NonNull List<SimAccount> getSimAccounts(
8479                 @NonNull ContentResolver contentResolver) {
8480             Bundle response = nullSafeCall(contentResolver, ContactsContract.AUTHORITY_URI,
8481                     ContactsContract.SimContacts.QUERY_SIM_ACCOUNTS_METHOD,
8482                     null, null);
8483             List<SimAccount> result = response.getParcelableArrayList(KEY_SIM_ACCOUNTS, android.provider.ContactsContract.SimAccount.class);
8484 
8485             if (result == null) {
8486                 result = new ArrayList<>();
8487             }
8488 
8489             return result;
8490         }
8491     }
8492 
8493     /**
8494      * A parcelable class encapsulating account data for contacts that originate from a SIM card.
8495      */
8496     public static final class SimAccount implements Parcelable {
8497         /** An invalid EF type identifier. */
8498         public static final int UNKNOWN_EF_TYPE = 0;
8499         /** EF type identifier for the ADN partition. */
8500         public static final int ADN_EF_TYPE = 1;
8501         /** EF type identifier for the FDN partition. */
8502         public static final int FDN_EF_TYPE = 2;
8503         /** EF type identifier for the SDN partition. */
8504         public static final int SDN_EF_TYPE = 3;
8505 
8506         /**
8507          * The account_name of this SIM account. See {@link RawContacts#ACCOUNT_NAME}.
8508          */
8509         private final String mAccountName;
8510 
8511         /**
8512          * The account_type of this SIM account. See {@link RawContacts#ACCOUNT_TYPE}.
8513          */
8514         private final String mAccountType;
8515 
8516         /**
8517          * The slot index of the SIM card this account maps to. See {@link
8518          * android.telephony.SubscriptionInfo#getSimSlotIndex()}.
8519          */
8520         private final int mSimSlotIndex;
8521 
8522         /**
8523          * The EF type of the contacts stored in this account. One of
8524          * {@link #ADN_EF_TYPE}, {@link #SDN_EF_TYPE} or {@link #FDN_EF_TYPE}.
8525          *
8526          * EF type is the Elementary File type of the partition these contacts come from within the
8527          * SIM card.
8528          *
8529          * ADN is the "abbreviated dialing numbers" or the user managed SIM contacts.
8530          *
8531          * SDN is the "service dialing numbers" which are usually preloaded onto the SIM by the
8532          * carrier.
8533          *
8534          * FDN is the "fixed dialing numbers" which are contacts which can only be dialed from that
8535          * SIM, used in cases such as parental control.
8536          */
8537         private final int mEfType;
8538 
8539         /**
8540          * @return A set containing all known EF type values
8541          * @hide
8542          */
getValidEfTypes()8543         public static @NonNull Set<Integer> getValidEfTypes() {
8544             return Sets.newArraySet(ADN_EF_TYPE, SDN_EF_TYPE, FDN_EF_TYPE);
8545         }
8546 
8547         /**
8548          * @hide
8549          */
SimAccount(@onNull String accountName, @NonNull String accountType, int simSlotIndex, int efType)8550         public SimAccount(@NonNull String accountName, @NonNull String accountType,
8551                 int simSlotIndex,
8552                 int efType) {
8553             this.mAccountName = accountName;
8554             this.mAccountType = accountType;
8555             this.mSimSlotIndex = simSlotIndex;
8556             this.mEfType = efType;
8557         }
8558 
8559         /**
8560          * @return The account_name of this SIM account. See {@link RawContacts#ACCOUNT_NAME}.
8561          */
getAccountName()8562         public @NonNull String getAccountName() {
8563             return mAccountName;
8564         }
8565 
8566         /**
8567          * @return The account_type of this SIM account. See {@link RawContacts#ACCOUNT_TYPE}.
8568          */
getAccountType()8569         public @NonNull String getAccountType() {
8570             return mAccountType;
8571         }
8572 
8573         /**
8574          * @return The slot index of the SIM card this account maps to. See
8575          * {@link android.telephony.SubscriptionInfo#getSimSlotIndex()}.
8576          */
getSimSlotIndex()8577         public int getSimSlotIndex() {
8578             return mSimSlotIndex;
8579         }
8580 
8581         /**
8582          * @return The EF type of the contacts stored in this account.
8583          */
getEfType()8584         public int getEfType() {
8585             return mEfType;
8586         }
8587 
8588         @Override
hashCode()8589         public int hashCode() {
8590             return Objects.hash(mAccountName, mAccountType, mSimSlotIndex, mEfType);
8591         }
8592 
8593         @Override
equals(Object obj)8594         public boolean equals(Object obj) {
8595             if (obj == null) return false;
8596             if (obj == this) return true;
8597 
8598             SimAccount toCompare;
8599             try {
8600                 toCompare = (SimAccount) obj;
8601             } catch (ClassCastException ex) {
8602                 return false;
8603             }
8604 
8605             return mSimSlotIndex == toCompare.mSimSlotIndex
8606                     && mEfType == toCompare.mEfType
8607                     && Objects.equals(mAccountName, toCompare.mAccountName)
8608                     && Objects.equals(mAccountType, toCompare.mAccountType);
8609         }
8610 
8611         @Override
writeToParcel(@onNull Parcel dest, int flags)8612         public void writeToParcel(@NonNull Parcel dest, int flags) {
8613             dest.writeString(mAccountName);
8614             dest.writeString(mAccountType);
8615             dest.writeInt(mSimSlotIndex);
8616             dest.writeInt(mEfType);
8617         }
8618 
8619         @Override
describeContents()8620         public int describeContents() {
8621             return 0;
8622         }
8623 
8624         public static final @NonNull Parcelable.Creator<SimAccount> CREATOR =
8625                 new Parcelable.Creator<SimAccount>() {
8626                     @Override
8627                     public SimAccount createFromParcel(Parcel source) {
8628                         String accountName = source.readString();
8629                         String accountType = source.readString();
8630                         int simSlot = source.readInt();
8631                         int efType = source.readInt();
8632                         SimAccount simAccount = new SimAccount(accountName, accountType, simSlot,
8633                                 efType);
8634                         return simAccount;
8635                     }
8636 
8637                     @Override
8638                     public SimAccount[] newArray(int size) {
8639                         return new SimAccount[size];
8640                     }
8641                 };
8642     }
8643 
8644     /**
8645      * @see Settings
8646      */
8647     protected interface SettingsColumns {
8648         /**
8649          * The name of the account instance to which this row belongs.
8650          * <P>Type: TEXT</P>
8651          */
8652         public static final String ACCOUNT_NAME = "account_name";
8653 
8654         /**
8655          * The type of account to which this row belongs, which when paired with
8656          * {@link #ACCOUNT_NAME} identifies a specific account.
8657          * <P>Type: TEXT</P>
8658          */
8659         public static final String ACCOUNT_TYPE = "account_type";
8660 
8661         /**
8662          * The data set within the account that this row belongs to.  This allows
8663          * multiple sync adapters for the same account type to distinguish between
8664          * each others' data.
8665          *
8666          * This is empty by default, and is completely optional.  It only needs to
8667          * be populated if multiple sync adapters are entering distinct data for
8668          * the same account type and account name.
8669          * <P>Type: TEXT</P>
8670          */
8671         public static final String DATA_SET = "data_set";
8672 
8673         /**
8674          * Depending on the mode defined by the sync-adapter, this flag controls
8675          * the top-level sync behavior for this data source.
8676          * <p>
8677          * Type: INTEGER (boolean)
8678          */
8679         public static final String SHOULD_SYNC = "should_sync";
8680 
8681         /**
8682          * Flag indicating if contacts without any {@link CommonDataKinds.GroupMembership}
8683          * entries should be visible in any user interface.
8684          * <p>
8685          * Type: INTEGER (boolean)
8686          */
8687         public static final String UNGROUPED_VISIBLE = "ungrouped_visible";
8688 
8689         /**
8690          * Read-only flag indicating if this {@link #SHOULD_SYNC} or any
8691          * {@link Groups#SHOULD_SYNC} under this account have been marked as
8692          * unsynced.
8693          */
8694         public static final String ANY_UNSYNCED = "any_unsynced";
8695 
8696         /**
8697          * Read-only count of {@link Contacts} from a specific source that have
8698          * no {@link CommonDataKinds.GroupMembership} entries.
8699          * <p>
8700          * Type: INTEGER
8701          */
8702         public static final String UNGROUPED_COUNT = "summ_count";
8703 
8704         /**
8705          * Read-only count of {@link Contacts} from a specific source that have
8706          * no {@link CommonDataKinds.GroupMembership} entries, and also have phone numbers.
8707          * <p>
8708          * Type: INTEGER
8709          */
8710         public static final String UNGROUPED_WITH_PHONES = "summ_phones";
8711 
8712         /**
8713          * Flag indicating if the account is the default account for new contacts. At most one
8714          * account has this flag set at a time. It can only be set to 1 on a row with null data set.
8715          * <p>
8716          * Type: INTEGER (boolean)
8717          * @hide
8718          */
8719         String IS_DEFAULT = "x_is_default";
8720     }
8721 
8722     /**
8723      * <p>
8724      * Contacts-specific settings for various {@link Account}'s.
8725      * </p>
8726      * <p>
8727      * A settings entry for an account is created automatically when a raw contact or group
8728      * is inserted that references it. Settings entries cannot be deleted as long as raw
8729      * contacts or groups continue to reference it; in order to delete a settings entry all
8730      * raw contacts and groups referencing the account must be deleted first.
8731      * </p>
8732      * <h2>Columns</h2>
8733      * <table class="jd-sumtable">
8734      * <tr>
8735      * <th colspan='4'>Settings</th>
8736      * </tr>
8737      * <tr>
8738      * <td>String</td>
8739      * <td>{@link #ACCOUNT_NAME}</td>
8740      * <td>read/write-once</td>
8741      * <td>The name of the account instance to which this row belongs.</td>
8742      * </tr>
8743      * <tr>
8744      * <td>String</td>
8745      * <td>{@link #ACCOUNT_TYPE}</td>
8746      * <td>read/write-once</td>
8747      * <td>The type of account to which this row belongs, which when paired with
8748      * {@link #ACCOUNT_NAME} identifies a specific account.</td>
8749      * </tr>
8750      * <tr>
8751      * <td>int</td>
8752      * <td>{@link #SHOULD_SYNC}</td>
8753      * <td>read/write</td>
8754      * <td>Depending on the mode defined by the sync-adapter, this flag controls
8755      * the top-level sync behavior for this data source.</td>
8756      * </tr>
8757      * <tr>
8758      * <td>int</td>
8759      * <td>{@link #UNGROUPED_VISIBLE}</td>
8760      * <td>read/write</td>
8761      * <td>Flag indicating if contacts without any
8762      * {@link CommonDataKinds.GroupMembership} entries should be visible in any
8763      * user interface.</td>
8764      * </tr>
8765      * <tr>
8766      * <td>int</td>
8767      * <td>{@link #ANY_UNSYNCED}</td>
8768      * <td>read-only</td>
8769      * <td>Read-only flag indicating if this {@link #SHOULD_SYNC} or any
8770      * {@link Groups#SHOULD_SYNC} under this account have been marked as
8771      * unsynced.</td>
8772      * </tr>
8773      * <tr>
8774      * <td>int</td>
8775      * <td>{@link #UNGROUPED_COUNT}</td>
8776      * <td>read-only</td>
8777      * <td>Read-only count of {@link Contacts} from a specific source that have
8778      * no {@link CommonDataKinds.GroupMembership} entries.</td>
8779      * </tr>
8780      * <tr>
8781      * <td>int</td>
8782      * <td>{@link #UNGROUPED_WITH_PHONES}</td>
8783      * <td>read-only</td>
8784      * <td>Read-only count of {@link Contacts} from a specific source that have
8785      * no {@link CommonDataKinds.GroupMembership} entries, and also have phone
8786      * numbers.</td>
8787      * </tr>
8788      * </table>
8789      */
8790     public static final class Settings implements SettingsColumns {
8791         /**
8792          * This utility class cannot be instantiated
8793          */
Settings()8794         private Settings() {
8795         }
8796 
8797         /**
8798          * The content:// style URI for this table
8799          */
8800         public static final Uri CONTENT_URI =
8801                 Uri.withAppendedPath(AUTHORITY_URI, "settings");
8802 
8803         /**
8804          * The MIME-type of {@link #CONTENT_URI} providing a directory of
8805          * settings.
8806          */
8807         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/setting";
8808 
8809         /**
8810          * The MIME-type of {@link #CONTENT_URI} providing a single setting.
8811          */
8812         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/setting";
8813 
8814         /**
8815          * Action used to launch the UI to set the default account for new contacts.
8816          */
8817         @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
8818         public static final String ACTION_SET_DEFAULT_ACCOUNT =
8819                 "android.provider.action.SET_DEFAULT_ACCOUNT";
8820 
8821         /**
8822          * The method to invoke in order to set the default account for new contacts.
8823          *
8824          * @hide
8825          */
8826         public static final String SET_DEFAULT_ACCOUNT_METHOD = "setDefaultAccount";
8827 
8828         /**
8829          * The method to invoke in order to query the default account for new contacts.
8830          *
8831          * @hide
8832          */
8833         public static final String QUERY_DEFAULT_ACCOUNT_METHOD = "queryDefaultAccount";
8834 
8835         /**
8836          * Key in the incoming Bundle for the default account.
8837          *
8838          * @hide
8839          */
8840         public static final String KEY_DEFAULT_ACCOUNT = "key_default_account";
8841 
8842         /**
8843          * Get the account that is set as the default account for new contacts, which should be
8844          * initially selected when creating a new contact on contact management apps.
8845          * If the setting has not been set by any app, it will return null. Once the setting
8846          * is set to non-null Account, it can still be set to null in the future.
8847          *
8848          * @param resolver the ContentResolver to query.
8849          * @return the default account for new contacts, or null if it's not set or set to NULL
8850          * account.
8851          */
8852         @Nullable
getDefaultAccount(@onNull ContentResolver resolver)8853         public static Account getDefaultAccount(@NonNull ContentResolver resolver) {
8854             Bundle response = resolver.call(ContactsContract.AUTHORITY_URI,
8855                     QUERY_DEFAULT_ACCOUNT_METHOD, null, null);
8856             return response.getParcelable(KEY_DEFAULT_ACCOUNT, android.accounts.Account.class);
8857         }
8858 
8859         /**
8860          * Sets the account as the default account that should be initially selected
8861          * when creating a new contact on contact management apps. Apps can only set one of
8862          * the following accounts as the default account:
8863          * <ol>
8864          *   <li>null or custom local account
8865          *   <li>SIM account
8866          *   <li>AccountManager accounts
8867          * </ol>
8868          *
8869          * @param resolver the ContentResolver to query.
8870          * @param account the account to be set to default.
8871          * @hide
8872          */
8873         @SystemApi
8874         @RequiresPermission(android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS)
setDefaultAccount(@onNull ContentResolver resolver, @Nullable Account account)8875         public static void setDefaultAccount(@NonNull ContentResolver resolver,
8876                 @Nullable Account account) {
8877             Bundle extras = new Bundle();
8878             if (account != null) {
8879                 extras.putString(ACCOUNT_NAME, account.name);
8880                 extras.putString(ACCOUNT_TYPE, account.type);
8881             }
8882 
8883             resolver.call(ContactsContract.AUTHORITY_URI, SET_DEFAULT_ACCOUNT_METHOD, null, extras);
8884         }
8885     }
8886 
8887     /**
8888      * API for inquiring about the general status of the provider.
8889      */
8890     public static final class ProviderStatus {
8891 
8892         /**
8893          * Not instantiable.
8894          */
ProviderStatus()8895         private ProviderStatus() {
8896         }
8897 
8898         /**
8899          * The content:// style URI for this table.  Requests to this URI can be
8900          * performed on the UI thread because they are always unblocking.
8901          */
8902         public static final Uri CONTENT_URI =
8903                 Uri.withAppendedPath(AUTHORITY_URI, "provider_status");
8904 
8905         /**
8906          * The MIME-type of {@link #CONTENT_URI} providing a directory of
8907          * settings.
8908          */
8909         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
8910 
8911         /**
8912          * An integer representing the current status of the provider.
8913          */
8914         public static final String STATUS = "status";
8915 
8916         /**
8917          * Default status of the provider.
8918          */
8919         public static final int STATUS_NORMAL = 0;
8920 
8921         /**
8922          * The provider won't respond to queries. It is in the middle of a long running task, such
8923          * as a database upgrade or locale change.
8924          */
8925         public static final int STATUS_BUSY = 1;
8926 
8927         /**
8928          * The status that indicates that there are no accounts and no contacts
8929          * on the device.
8930          */
8931         public static final int STATUS_EMPTY = 2;
8932 
8933         /**
8934          * Timestamp (milliseconds since epoch) of when the provider's database was created.
8935          *
8936          * <P>Type: long
8937          */
8938         public static final String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
8939     }
8940 
8941     /**
8942      * <p>
8943      * API allowing applications to send usage information for each {@link Data} row to the
8944      * Contacts Provider.  Applications can also clear all usage information.
8945      * </p>
8946      * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
8947      * this field is obsolete, regardless of Android version. For more information, see the
8948      * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
8949      * page.</p>
8950      * <p>
8951      * With the feedback, Contacts Provider may return more contextually appropriate results for
8952      * Data listing, typically supplied with
8953      * {@link ContactsContract.Contacts#CONTENT_FILTER_URI},
8954      * {@link ContactsContract.CommonDataKinds.Email#CONTENT_FILTER_URI},
8955      * {@link ContactsContract.CommonDataKinds.Phone#CONTENT_FILTER_URI}, and users can benefit
8956      * from better ranked (sorted) lists in applications that show auto-complete list.
8957      * </p>
8958      * <p>
8959      * There is no guarantee for how this feedback is used, or even whether it is used at all.
8960      * The ranking algorithm will make best efforts to use the feedback data, but the exact
8961      * implementation, the storage data structures as well as the resulting sort order is device
8962      * and version specific and can change over time.
8963      * </p>
8964      * <p>
8965      * When updating usage information, users of this API need to use
8966      * {@link ContentResolver#update(Uri, ContentValues, String, String[])} with a Uri constructed
8967      * from {@link DataUsageFeedback#FEEDBACK_URI}. The Uri must contain one or more data id(s) as
8968      * its last path. They also need to append a query parameter to the Uri, to specify the type of
8969      * the communication, which enables the Contacts Provider to differentiate between kinds of
8970      * interactions using the same contact data field (for example a phone number can be used to
8971      * make phone calls or send SMS).
8972      * </p>
8973      * <p>
8974      * Selection and selectionArgs are ignored and must be set to null. To get data ids,
8975      * you may need to call {@link ContentResolver#query(Uri, String[], String, String[], String)}
8976      * toward {@link Data#CONTENT_URI}.
8977      * </p>
8978      * <p>
8979      * {@link ContentResolver#update(Uri, ContentValues, String, String[])} returns a positive
8980      * integer when successful, and returns 0 if no contact with that id was found.
8981      * </p>
8982      * <p>
8983      * Example:
8984      * <pre>
8985      * Uri uri = DataUsageFeedback.FEEDBACK_URI.buildUpon()
8986      *         .appendPath(TextUtils.join(",", dataIds))
8987      *         .appendQueryParameter(DataUsageFeedback.USAGE_TYPE,
8988      *                 DataUsageFeedback.USAGE_TYPE_CALL)
8989      *         .build();
8990      * boolean successful = resolver.update(uri, new ContentValues(), null, null) > 0;
8991      * </pre>
8992      * </p>
8993      * <p>
8994      * Applications can also clear all usage information with:
8995      * <pre>
8996      * boolean successful = resolver.delete(DataUsageFeedback.DELETE_USAGE_URI, null, null) > 0;
8997      * </pre>
8998      * </p>
8999      *
9000      * @deprecated Contacts affinity information is no longer supported as of
9001      * Android version {@link android.os.Build.VERSION_CODES#Q}.
9002      * Both update and delete calls are always ignored.
9003      */
9004     @Deprecated
9005     public static final class DataUsageFeedback {
9006 
9007         /**
9008          * The content:// style URI for sending usage feedback.
9009          * Must be used with {@link ContentResolver#update(Uri, ContentValues, String, String[])}.
9010          */
9011         public static final Uri FEEDBACK_URI =
9012                 Uri.withAppendedPath(Data.CONTENT_URI, "usagefeedback");
9013 
9014         /**
9015          * The content:// style URI for deleting all usage information.
9016          * Must be used with {@link ContentResolver#delete(Uri, String, String[])}.
9017          * The {@code where} and {@code selectionArgs} parameters are ignored.
9018          */
9019         public static final Uri DELETE_USAGE_URI =
9020                 Uri.withAppendedPath(Contacts.CONTENT_URI, "delete_usage");
9021 
9022         /**
9023          * <p>
9024          * Name for query parameter specifying the type of data usage.
9025          * </p>
9026          */
9027         public static final String USAGE_TYPE = "type";
9028 
9029         /**
9030          * <p>
9031          * Type of usage for voice interaction, which includes phone call, voice chat, and
9032          * video chat.
9033          * </p>
9034          */
9035         public static final String USAGE_TYPE_CALL = "call";
9036 
9037         /**
9038          * <p>
9039          * Type of usage for text interaction involving longer messages, which includes email.
9040          * </p>
9041          */
9042         public static final String USAGE_TYPE_LONG_TEXT = "long_text";
9043 
9044         /**
9045          * <p>
9046          * Type of usage for text interaction involving shorter messages, which includes SMS,
9047          * text chat with email addresses.
9048          * </p>
9049          */
9050         public static final String USAGE_TYPE_SHORT_TEXT = "short_text";
9051     }
9052 
9053     /**
9054      * <p>
9055      * Contact-specific information about whether or not a contact has been pinned by the user
9056      * at a particular position within the system contact application's user interface.
9057      * </p>
9058      *
9059      * <p>
9060      * This pinning information can be used by individual applications to customize how
9061      * they order particular pinned contacts. For example, a Dialer application could
9062      * use pinned information to order user-pinned contacts in a top row of favorites.
9063      * </p>
9064      *
9065      * <p>
9066      * It is possible for two or more contacts to occupy the same pinned position (due
9067      * to aggregation and sync), so this pinning information should be used on a best-effort
9068      * basis to order contacts in-application rather than an absolute guide on where a contact
9069      * should be positioned. Contacts returned by the ContactsProvider will not be ordered based
9070      * on this information, so it is up to the client application to reorder these contacts within
9071      * their own UI adhering to (or ignoring as appropriate) information stored in the pinned
9072      * column.
9073      * </p>
9074      *
9075      * <p>
9076      * By default, unpinned contacts will have a pinned position of
9077      * {@link PinnedPositions#UNPINNED}. Client-provided pinned positions can be positive
9078      * integers that are greater than 1.
9079      * </p>
9080      */
9081     public static final class PinnedPositions {
9082         /**
9083          * The method to invoke in order to undemote a formerly demoted contact. The contact id of
9084          * the contact must be provided as an argument. If the contact was not previously demoted,
9085          * nothing will be done.
9086          * @hide
9087          */
9088         @TestApi
9089         public static final String UNDEMOTE_METHOD = "undemote";
9090 
9091         /**
9092          * Undemotes a formerly demoted contact. If the contact was not previously demoted, nothing
9093          * will be done.
9094          *
9095          * @param contentResolver to perform the undemote operation on.
9096          * @param contactId the id of the contact to undemote.
9097          */
undemote(ContentResolver contentResolver, long contactId)9098         public static void undemote(ContentResolver contentResolver, long contactId) {
9099             nullSafeCall(contentResolver, ContactsContract.AUTHORITY_URI,
9100                     PinnedPositions.UNDEMOTE_METHOD,
9101                     String.valueOf(contactId), null);
9102         }
9103 
9104         /**
9105          * Pins a contact at a provided position, or unpins a contact.
9106          *
9107          * @param contentResolver to perform the pinning operation on.
9108          * @param pinnedPosition the position to pin the contact at. To unpin a contact, use
9109          *         {@link PinnedPositions#UNPINNED}.
9110          */
pin( ContentResolver contentResolver, long contactId, int pinnedPosition)9111         public static void pin(
9112                 ContentResolver contentResolver, long contactId, int pinnedPosition) {
9113             final Uri uri = Uri.withAppendedPath(Contacts.CONTENT_URI, String.valueOf(contactId));
9114             final ContentValues values = new ContentValues();
9115             values.put(Contacts.PINNED, pinnedPosition);
9116             contentResolver.update(uri, values, null, null);
9117         }
9118 
9119         /**
9120          * Default value for the pinned position of an unpinned contact.
9121          */
9122         public static final int UNPINNED = 0;
9123 
9124         /**
9125          * Value of pinned position for a contact that a user has indicated should be considered
9126          * of the lowest priority. It is up to the client application to determine how to present
9127          * such a contact - for example all the way at the bottom of a contact list, or simply
9128          * just hidden from view.
9129          */
9130         public static final int DEMOTED = -1;
9131     }
9132 
9133     /**
9134      * Helper methods to display QuickContact dialogs that display all the information belonging to
9135      * a specific {@link Contacts} entry.
9136      */
9137     public static final class QuickContact {
9138         /**
9139          * Action used to launch the system contacts application and bring up a QuickContact dialog
9140          * for the provided {@link Contacts} entry.
9141          */
9142         @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
9143         public static final String ACTION_QUICK_CONTACT =
9144                 "android.provider.action.QUICK_CONTACT";
9145 
9146         /**
9147          * Extra used to specify pivot dialog location in screen coordinates.
9148          * @deprecated Use {@link Intent#setSourceBounds(Rect)} instead.
9149          * @hide
9150          */
9151         @Deprecated
9152         public static final String EXTRA_TARGET_RECT = "android.provider.extra.TARGET_RECT";
9153 
9154         /**
9155          * Extra used to specify size of QuickContacts. Not all implementations of QuickContacts
9156          * will respect this extra's value.
9157          *
9158          * One of {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or {@link #MODE_LARGE}.
9159          */
9160         public static final String EXTRA_MODE = "android.provider.extra.MODE";
9161 
9162         /**
9163          * Extra used to specify which mimetype should be prioritized in the QuickContacts UI.
9164          * For example, passing the value {@link CommonDataKinds.Phone#CONTENT_ITEM_TYPE} can
9165          * cause phone numbers to be displayed more prominently in QuickContacts.
9166          */
9167         public static final String EXTRA_PRIORITIZED_MIMETYPE
9168                 = "android.provider.extra.PRIORITIZED_MIMETYPE";
9169 
9170         /**
9171          * Extra used to indicate a list of specific MIME-types to exclude and not display in the
9172          * QuickContacts dialog. Stored as a {@link String} array.
9173          */
9174         public static final String EXTRA_EXCLUDE_MIMES = "android.provider.extra.EXCLUDE_MIMES";
9175 
9176         /**
9177          * Small QuickContact mode, usually presented with minimal actions.
9178          */
9179         public static final int MODE_SMALL = 1;
9180 
9181         /**
9182          * Medium QuickContact mode, includes actions and light summary describing
9183          * the {@link Contacts} entry being shown. This may include social
9184          * status and presence details.
9185          */
9186         public static final int MODE_MEDIUM = 2;
9187 
9188         /**
9189          * Large QuickContact mode, includes actions and larger, card-like summary
9190          * of the {@link Contacts} entry being shown. This may include detailed
9191          * information, such as a photo.
9192          */
9193         public static final int MODE_LARGE = 3;
9194 
9195         /** @hide */
9196         public static final int MODE_DEFAULT = MODE_LARGE;
9197 
9198         /**
9199          * Constructs the QuickContacts intent with a view's rect.
9200          * @hide
9201          */
composeQuickContactsIntent(Context context, View target, Uri lookupUri, int mode, String[] excludeMimes)9202         public static Intent composeQuickContactsIntent(Context context, View target, Uri lookupUri,
9203                 int mode, String[] excludeMimes) {
9204             // Find location and bounds of target view, adjusting based on the
9205             // assumed local density.
9206             final float appScale = context.getResources().getCompatibilityInfo().applicationScale;
9207             final int[] pos = new int[2];
9208             target.getLocationOnScreen(pos);
9209 
9210             final Rect rect = new Rect();
9211             rect.left = (int) (pos[0] * appScale + 0.5f);
9212             rect.top = (int) (pos[1] * appScale + 0.5f);
9213             rect.right = (int) ((pos[0] + target.getWidth()) * appScale + 0.5f);
9214             rect.bottom = (int) ((pos[1] + target.getHeight()) * appScale + 0.5f);
9215 
9216             return composeQuickContactsIntent(context, rect, lookupUri, mode, excludeMimes);
9217         }
9218 
9219         /**
9220          * Constructs the QuickContacts intent.
9221          * @hide
9222          */
9223         @UnsupportedAppUsage
composeQuickContactsIntent(Context context, Rect target, Uri lookupUri, int mode, String[] excludeMimes)9224         public static Intent composeQuickContactsIntent(Context context, Rect target,
9225                 Uri lookupUri, int mode, String[] excludeMimes) {
9226             // When launching from an Activiy, we don't want to start a new task, but otherwise
9227             // we *must* start a new task.  (Otherwise startActivity() would crash.)
9228             Context actualContext = context;
9229             while ((actualContext instanceof ContextWrapper)
9230                     && !(actualContext instanceof Activity)) {
9231                 actualContext = ((ContextWrapper) actualContext).getBaseContext();
9232             }
9233             final int intentFlags = ((actualContext instanceof Activity)
9234                     ? 0 : Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
9235                     // Workaround for b/16898764. Declaring singleTop in manifest doesn't work.
9236                     | Intent.FLAG_ACTIVITY_SINGLE_TOP;
9237 
9238             // Launch pivot dialog through intent for now
9239             final Intent intent = new Intent(ACTION_QUICK_CONTACT).addFlags(intentFlags);
9240 
9241             // NOTE: This logic and rebuildManagedQuickContactsIntent() must be in sync.
9242             intent.setData(lookupUri);
9243             intent.setSourceBounds(target);
9244             intent.putExtra(EXTRA_MODE, mode);
9245             intent.putExtra(EXTRA_EXCLUDE_MIMES, excludeMimes);
9246             return intent;
9247         }
9248 
9249         /**
9250          * Constructs a QuickContacts intent based on an incoming intent for DevicePolicyManager
9251          * to strip off anything not necessary.
9252          *
9253          * @hide
9254          */
rebuildManagedQuickContactsIntent(String lookupKey, long contactId, boolean isContactIdIgnored, long directoryId, Intent originalIntent)9255         public static Intent rebuildManagedQuickContactsIntent(String lookupKey, long contactId,
9256                 boolean isContactIdIgnored, long directoryId, Intent originalIntent) {
9257             final Intent intent = new Intent(ACTION_QUICK_CONTACT);
9258             // Rebuild the URI from a lookup key and a contact ID.
9259             Uri uri = null;
9260             if (!TextUtils.isEmpty(lookupKey)) {
9261                 uri = isContactIdIgnored
9262                         ? Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey)
9263                         : Contacts.getLookupUri(contactId, lookupKey);
9264             }
9265             if (uri != null && directoryId != Directory.DEFAULT) {
9266                 uri = uri.buildUpon().appendQueryParameter(
9267                         ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build();
9268             }
9269             intent.setData(uri);
9270 
9271             // Copy flags and always set NEW_TASK because it won't have a parent activity.
9272             intent.setFlags(originalIntent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
9273 
9274             // Copy extras.
9275             intent.setSourceBounds(originalIntent.getSourceBounds());
9276             intent.putExtra(EXTRA_MODE, originalIntent.getIntExtra(EXTRA_MODE, MODE_DEFAULT));
9277             intent.putExtra(EXTRA_EXCLUDE_MIMES,
9278                     originalIntent.getStringArrayExtra(EXTRA_EXCLUDE_MIMES));
9279             return intent;
9280         }
9281 
9282 
9283         /**
9284          * Trigger a dialog that lists the various methods of interacting with
9285          * the requested {@link Contacts} entry. This may be based on available
9286          * {@link ContactsContract.Data} rows under that contact, and may also
9287          * include social status and presence details.
9288          *
9289          * @param context The parent {@link Context} that may be used as the
9290          *            parent for this dialog.
9291          * @param target Specific {@link View} from your layout that this dialog
9292          *            should be centered around. In particular, if the dialog
9293          *            has a "callout" arrow, it will be pointed and centered
9294          *            around this {@link View}.
9295          * @param lookupUri A {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
9296          *            {@link Uri} that describes a specific contact to feature
9297          *            in this dialog. A managed profile lookup uri is supported here,
9298          *            see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
9299          *            {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
9300          * @param mode Any of {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or
9301          *            {@link #MODE_LARGE}, indicating the desired dialog size,
9302          *            when supported.
9303          * @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
9304          *            to exclude when showing this dialog. For example, when
9305          *            already viewing the contact details card, this can be used
9306          *            to omit the details entry from the dialog.
9307          */
showQuickContact(Context context, View target, Uri lookupUri, int mode, String[] excludeMimes)9308         public static void showQuickContact(Context context, View target, Uri lookupUri, int mode,
9309                 String[] excludeMimes) {
9310             // Trigger with obtained rectangle
9311             Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode,
9312                     excludeMimes);
9313             ContactsInternal.startQuickContactWithErrorToast(context, intent);
9314         }
9315 
9316         /**
9317          * Trigger a dialog that lists the various methods of interacting with
9318          * the requested {@link Contacts} entry. This may be based on available
9319          * {@link ContactsContract.Data} rows under that contact, and may also
9320          * include social status and presence details.
9321          *
9322          * @param context The parent {@link Context} that may be used as the
9323          *            parent for this dialog.
9324          * @param target Specific {@link Rect} that this dialog should be
9325          *            centered around, in screen coordinates. In particular, if
9326          *            the dialog has a "callout" arrow, it will be pointed and
9327          *            centered around this {@link Rect}. If you are running at a
9328          *            non-native density, you need to manually adjust using
9329          *            {@link DisplayMetrics#density} before calling.
9330          * @param lookupUri A
9331          *            {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
9332          *            {@link Uri} that describes a specific contact to feature
9333          *            in this dialog. A managed profile lookup uri is supported here,
9334          *            see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
9335          *            {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
9336          * @param mode Any of {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or
9337          *            {@link #MODE_LARGE}, indicating the desired dialog size,
9338          *            when supported.
9339          * @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
9340          *            to exclude when showing this dialog. For example, when
9341          *            already viewing the contact details card, this can be used
9342          *            to omit the details entry from the dialog.
9343          */
showQuickContact(Context context, Rect target, Uri lookupUri, int mode, String[] excludeMimes)9344         public static void showQuickContact(Context context, Rect target, Uri lookupUri, int mode,
9345                 String[] excludeMimes) {
9346             Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode,
9347                     excludeMimes);
9348             ContactsInternal.startQuickContactWithErrorToast(context, intent);
9349         }
9350 
9351         /**
9352          * Trigger a dialog that lists the various methods of interacting with
9353          * the requested {@link Contacts} entry. This may be based on available
9354          * {@link ContactsContract.Data} rows under that contact, and may also
9355          * include social status and presence details.
9356          *
9357          * @param context The parent {@link Context} that may be used as the
9358          *            parent for this dialog.
9359          * @param target Specific {@link View} from your layout that this dialog
9360          *            should be centered around. In particular, if the dialog
9361          *            has a "callout" arrow, it will be pointed and centered
9362          *            around this {@link View}.
9363          * @param lookupUri A
9364          *            {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
9365          *            {@link Uri} that describes a specific contact to feature
9366          *            in this dialog. A managed profile lookup uri is supported here,
9367          *            see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
9368          *            {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
9369          * @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
9370          *            to exclude when showing this dialog. For example, when
9371          *            already viewing the contact details card, this can be used
9372          *            to omit the details entry from the dialog.
9373          * @param prioritizedMimeType This mimetype should be prioritized in the QuickContacts UI.
9374          *             For example, passing the value
9375          *             {@link CommonDataKinds.Phone#CONTENT_ITEM_TYPE} can cause phone numbers to be
9376          *             displayed more prominently in QuickContacts.
9377          */
showQuickContact(Context context, View target, Uri lookupUri, String[] excludeMimes, String prioritizedMimeType)9378         public static void showQuickContact(Context context, View target, Uri lookupUri,
9379                 String[] excludeMimes, String prioritizedMimeType) {
9380             // Use MODE_LARGE instead of accepting mode as a parameter. The different mode
9381             // values defined in ContactsContract only affect very old implementations
9382             // of QuickContacts.
9383             Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_DEFAULT,
9384                     excludeMimes);
9385             intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType);
9386             ContactsInternal.startQuickContactWithErrorToast(context, intent);
9387         }
9388 
9389         /**
9390          * Trigger a dialog that lists the various methods of interacting with
9391          * the requested {@link Contacts} entry. This may be based on available
9392          * {@link ContactsContract.Data} rows under that contact, and may also
9393          * include social status and presence details.
9394          *
9395          * @param context The parent {@link Context} that may be used as the
9396          *            parent for this dialog.
9397          * @param target Specific {@link Rect} that this dialog should be
9398          *            centered around, in screen coordinates. In particular, if
9399          *            the dialog has a "callout" arrow, it will be pointed and
9400          *            centered around this {@link Rect}. If you are running at a
9401          *            non-native density, you need to manually adjust using
9402          *            {@link DisplayMetrics#density} before calling.
9403          * @param lookupUri A
9404          *            {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
9405          *            {@link Uri} that describes a specific contact to feature
9406          *            in this dialog. A managed profile lookup uri is supported here,
9407          *            see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
9408          *            {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
9409          * @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
9410          *            to exclude when showing this dialog. For example, when
9411          *            already viewing the contact details card, this can be used
9412          *            to omit the details entry from the dialog.
9413          * @param prioritizedMimeType This mimetype should be prioritized in the QuickContacts UI.
9414          *             For example, passing the value
9415          *             {@link CommonDataKinds.Phone#CONTENT_ITEM_TYPE} can cause phone numbers to be
9416          *             displayed more prominently in QuickContacts.
9417          */
showQuickContact(Context context, Rect target, Uri lookupUri, String[] excludeMimes, String prioritizedMimeType)9418         public static void showQuickContact(Context context, Rect target, Uri lookupUri,
9419                 String[] excludeMimes, String prioritizedMimeType) {
9420             // Use MODE_LARGE instead of accepting mode as a parameter. The different mode
9421             // values defined in ContactsContract only affect very old implementations
9422             // of QuickContacts.
9423             Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_DEFAULT,
9424                     excludeMimes);
9425             intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType);
9426             ContactsInternal.startQuickContactWithErrorToast(context, intent);
9427         }
9428     }
9429 
9430     /**
9431      * Helper class for accessing full-size photos by photo file ID.
9432      * <p>
9433      * Usage example:
9434      * <dl>
9435      * <dt>Retrieving a full-size photo by photo file ID (see
9436      * {@link ContactsContract.ContactsColumns#PHOTO_FILE_ID})
9437      * </dt>
9438      * <dd>
9439      * <pre>
9440      * public InputStream openDisplayPhoto(long photoFileId) {
9441      *     Uri displayPhotoUri = ContentUris.withAppendedId(DisplayPhoto.CONTENT_URI, photoKey);
9442      *     try {
9443      *         AssetFileDescriptor fd = getContentResolver().openAssetFileDescriptor(
9444      *             displayPhotoUri, "r");
9445      *         return fd.createInputStream();
9446      *     } catch (IOException e) {
9447      *         return null;
9448      *     }
9449      * }
9450      * </pre>
9451      * </dd>
9452      * </dl>
9453      * </p>
9454      */
9455     public static final class DisplayPhoto {
9456         /**
9457          * no public constructor since this is a utility class
9458          */
DisplayPhoto()9459         private DisplayPhoto() {}
9460 
9461         /**
9462          * The content:// style URI for this class, which allows access to full-size photos,
9463          * given a key.
9464          */
9465         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "display_photo");
9466 
9467         /**
9468          * This URI allows the caller to query for the maximum dimensions of a display photo
9469          * or thumbnail.  Requests to this URI can be performed on the UI thread because
9470          * they are always unblocking.
9471          */
9472         public static final Uri CONTENT_MAX_DIMENSIONS_URI =
9473                 Uri.withAppendedPath(AUTHORITY_URI, "photo_dimensions");
9474 
9475         /**
9476          * Queries to {@link ContactsContract.DisplayPhoto#CONTENT_MAX_DIMENSIONS_URI} will
9477          * contain this column, populated with the maximum height and width (in pixels)
9478          * that will be stored for a display photo.  Larger photos will be down-sized to
9479          * fit within a square of this many pixels.
9480          */
9481         public static final String DISPLAY_MAX_DIM = "display_max_dim";
9482 
9483         /**
9484          * Queries to {@link ContactsContract.DisplayPhoto#CONTENT_MAX_DIMENSIONS_URI} will
9485          * contain this column, populated with the height and width (in pixels) for photo
9486          * thumbnails.
9487          */
9488         public static final String THUMBNAIL_MAX_DIM = "thumbnail_max_dim";
9489     }
9490 
9491     /**
9492      * Contains helper classes used to create or manage {@link android.content.Intent Intents}
9493      * that involve contacts.
9494      */
9495     public static final class Intents {
9496         /**
9497          * This is the intent that is fired when a search suggestion is clicked on.
9498          */
9499         public static final String SEARCH_SUGGESTION_CLICKED =
9500                 "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
9501 
9502         /**
9503          * This is the intent that is fired when a search suggestion for dialing a number
9504          * is clicked on.
9505          */
9506         public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED =
9507                 "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";
9508 
9509         /**
9510          * This is the intent that is fired when a search suggestion for creating a contact
9511          * is clicked on.
9512          */
9513         public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED =
9514                 "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
9515 
9516         /**
9517          * This is the intent that is fired when the contacts database is created. <p> The
9518          * READ_CONTACT permission is required to receive these broadcasts.
9519          *
9520          * <p>Because this is an implicit broadcast, apps targeting Android O will no longer
9521          * receive this broadcast via a manifest broadcast receiver.  (Broadcast receivers
9522          * registered at runtime with
9523          * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)} will still receive it.)
9524          * Instead, an app can use {@link ProviderStatus#DATABASE_CREATION_TIMESTAMP} to see if the
9525          * contacts database has been initialized when it starts.
9526          */
9527         public static final String CONTACTS_DATABASE_CREATED =
9528                 "android.provider.Contacts.DATABASE_CREATED";
9529 
9530         /**
9531          * Starts an Activity that lets the user pick a contact to attach an image to.
9532          * After picking the contact it launches the image cropper in face detection mode.
9533          */
9534         public static final String ATTACH_IMAGE =
9535                 "com.android.contacts.action.ATTACH_IMAGE";
9536 
9537         /**
9538          * This is the intent that is fired when the user clicks the "invite to the network" button
9539          * on a contact.  Only sent to an activity which is explicitly registered by a contact
9540          * provider which supports the "invite to the network" feature.
9541          * <p>
9542          * {@link Intent#getData()} contains the lookup URI for the contact.
9543          */
9544         public static final String INVITE_CONTACT =
9545                 "com.android.contacts.action.INVITE_CONTACT";
9546 
9547         /**
9548          * Takes as input a data URI with a mailto: or tel: scheme. If a single
9549          * contact exists with the given data it will be shown. If no contact
9550          * exists, a dialog will ask the user if they want to create a new
9551          * contact with the provided details filled in. If multiple contacts
9552          * share the data the user will be prompted to pick which contact they
9553          * want to view.
9554          * <p>
9555          * For <code>mailto:</code> URIs, the scheme specific portion must be a
9556          * raw email address, such as one built using
9557          * {@link Uri#fromParts(String, String, String)}.
9558          * <p>
9559          * For <code>tel:</code> URIs, the scheme specific portion is compared
9560          * to existing numbers using the standard caller ID lookup algorithm.
9561          * The number must be properly encoded, for example using
9562          * {@link Uri#fromParts(String, String, String)}.
9563          * <p>
9564          * Any extras from the {@link Insert} class will be passed along to the
9565          * create activity if there are no contacts to show.
9566          * <p>
9567          * Passing true for the {@link #EXTRA_FORCE_CREATE} extra will skip
9568          * prompting the user when the contact doesn't exist.
9569          */
9570         public static final String SHOW_OR_CREATE_CONTACT =
9571                 "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
9572 
9573         /**
9574          * Activity Action: Initiate a message to someone by voice. The message could be text,
9575          * audio, video or image(photo). This action supports messaging with a specific contact
9576          * regardless of the underlying messaging protocol used.
9577          * <p>
9578          * The action could be originated from the Voice Assistant as a voice interaction. In such
9579          * case, a receiving activity that supports {@link android.content.Intent#CATEGORY_VOICE}
9580          * could check return value of {@link android.app.Activity#isVoiceInteractionRoot} before
9581          * proceeding. By doing this check the activity verifies that the action indeed was
9582          * initiated by Voice Assistant and could send a message right away, without any further
9583          * input from the user. This allows for a smooth user experience when sending a message by
9584          * voice. Note: this activity must also support the {@link
9585          * android.content.Intent#CATEGORY_DEFAULT} so it can be found by {@link
9586          * android.service.voice.VoiceInteractionSession#startVoiceActivity}.
9587          * <p>
9588          * When the action was not initiated by Voice Assistant or when the receiving activity does
9589          * not support {@link android.content.Intent#CATEGORY_VOICE}, the activity must confirm
9590          * with the user before sending the message (because in this case it is unknown which app
9591          * sent the intent, it could be malicious).
9592          * <p>
9593          * To allow the Voice Assistant to help users with contacts disambiguation, the messaging
9594          * app may choose to integrate with the Contacts Provider. You will need to specify a new
9595          * MIME type in order to store your app’s unique contact IDs and optional human readable
9596          * labels in the Data table. The Voice Assistant needs to know this MIME type and {@link
9597          * RawContacts#ACCOUNT_TYPE} that you are using in order to provide the smooth contact
9598          * disambiguation user experience. The following convention should be met when performing
9599          * such integration:
9600          * <ul>
9601          * <li>This activity should have a string meta-data field associated with it, {@link
9602          * #METADATA_ACCOUNT_TYPE}, which defines {@link RawContacts#ACCOUNT_TYPE} for your Contacts
9603          * Provider implementation. The account type should be globally unique, for example you can
9604          * use your app package name as the account type.</li>
9605          * <li>This activity should have a string meta-data field associated with it, {@link
9606          * #METADATA_MIMETYPE}, which defines {@link DataColumns#MIMETYPE} for your Contacts
9607          * Provider implementation. For example, you can use
9608          * "vnd.android.cursor.item/vnd.{$app_package_name}.profile" as MIME type.</li>
9609          * <li>When filling Data table row for METADATA_MIMETYPE, column {@link DataColumns#DATA1}
9610          * should store the unique contact ID as understood by the app. This value will be used in
9611          * the {@link #EXTRA_RECIPIENT_CONTACT_CHAT_ID}.</li>
9612          * <li>Optionally, when filling Data table row for METADATA_MIMETYPE, column {@link
9613          * DataColumns#DATA3} could store a human readable label for the ID. For example it could be
9614          * phone number or human readable username/user_id like "a_super_cool_user_name". This label
9615          * may be shown below the Contact Name by the Voice Assistant as the user completes the
9616          * voice action. If DATA3 is empty, the ID in DATA1 may be shown instead.</li>
9617          * <li><em>Note: Do not use DATA3 to store the Contact Name. The Voice Assistant will
9618          * already get the Contact Name from the RawContact’s display_name.</em></li>
9619          * <li><em>Note: Some apps may choose to use phone number as the unique contact ID in DATA1.
9620          * If this applies to you and you’d like phone number to be shown below the Contact Name by
9621          * the Voice Assistant, then you may choose to leave DATA3 empty.</em></li>
9622          * <li><em>Note: If your app also uses DATA3 to display contact details in the Contacts App,
9623          * make sure it does not include prefix text such as "Message +<phone>" or "Free Message
9624          * +<phone>", etc. If you must show the prefix text in the Contacts App, please use a
9625          * different DATA# column, and update your contacts.xml to point to this new column. </em>
9626          * </li>
9627          * </ul>
9628          * If the app chooses not to integrate with the Contacts Provider (in particular, when
9629          * either METADATA_ACCOUNT_TYPE or METADATA_MIMETYPE field is missing), Voice Assistant
9630          * will use existing phone number entries as contact ID's for such app.
9631          * <p>
9632          * Input: {@link android.content.Intent#getType} is the MIME type of the data being sent.
9633          * The intent sender will always put the concrete mime type in the intent type, like
9634          * "text/plain" or "audio/wav" for example. If the MIME type is "text/plain", message to
9635          * sent will be provided via {@link android.content.Intent#EXTRA_TEXT} as a styled
9636          * CharSequence. Otherwise, the message content will be supplied through {@link
9637          * android.content.Intent#setClipData(ClipData)} as a content provider URI(s). In the latter
9638          * case, EXTRA_TEXT could still be supplied optionally; for example, for audio messages
9639          * ClipData will contain URI of a recording and EXTRA_TEXT could contain the text
9640          * transcription of this recording.
9641          * <p>
9642          * The message can have n recipients. The n-th recipient of the message will be provided as
9643          * n-th elements of {@link #EXTRA_RECIPIENT_CONTACT_URI}, {@link
9644          * #EXTRA_RECIPIENT_CONTACT_CHAT_ID} and {@link #EXTRA_RECIPIENT_CONTACT_NAME} (as a
9645          * consequence, EXTRA_RECIPIENT_CONTACT_URI, EXTRA_RECIPIENT_CONTACT_CHAT_ID and
9646          * EXTRA_RECIPIENT_CONTACT_NAME should all be of length n). If neither of these 3 elements
9647          * is provided (e.g. all 3 are null) for the recipient or if the information provided is
9648          * ambiguous then the activity should prompt the user for the recipient to send the message
9649          * to.
9650          * <p>
9651          * Output: nothing
9652          *
9653          * @see #EXTRA_RECIPIENT_CONTACT_URI
9654          * @see #EXTRA_RECIPIENT_CONTACT_CHAT_ID
9655          * @see #EXTRA_RECIPIENT_CONTACT_NAME
9656          * @see #METADATA_ACCOUNT_TYPE
9657          * @see #METADATA_MIMETYPE
9658          */
9659         @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
9660         public static final String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS =
9661                 "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
9662 
9663         /**
9664          * This extra specifies a content provider uri(s) for the contact(s) (if the contacts were
9665          * located in the Contacts Provider), used with {@link
9666          * #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS} to supply the recipient(s). The value of this
9667          * extra is a {@code String[]}. The number of elements in the array should be equal to
9668          * number of recipients (and consistent with {@link #EXTRA_RECIPIENT_CONTACT_CHAT_ID} and
9669          * {@link #EXTRA_RECIPIENT_CONTACT_NAME}). When the value of the element for the particular
9670          * recipient is absent, it will be set to null.
9671          * <p>
9672          * <em>Note: one contact may have multiple accounts (e.g. Chat IDs) on a specific messaging
9673          * platform, so this may be ambiguous. E.g., one contact “John Smith” could have two
9674          * accounts on the same messaging app.</em>
9675          * <p>
9676          * <em>Example value: {"content://com.android.contacts/contacts/16"}</em>
9677          */
9678         public static final String EXTRA_RECIPIENT_CONTACT_URI =
9679                 "android.provider.extra.RECIPIENT_CONTACT_URI";
9680 
9681         /**
9682          * This extra specifies a messaging app’s unique ID(s) for the contact(s), used with {@link
9683          * #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS} to supply the recipient(s). The value of this
9684          * extra is a {@code String[]}. The number of elements in the array should be equal to
9685          * number of recipients (and consistent with {@link #EXTRA_RECIPIENT_CONTACT_URI} and {@link
9686          * #EXTRA_RECIPIENT_CONTACT_NAME}). When the value of the element for the particular
9687          * recipient is absent, it will be set to null.
9688          * <p>
9689          * The value of the elements comes from the {@link DataColumns#DATA1} column in Contacts
9690          * Provider with {@link DataColumns#MIMETYPE} from {@link #METADATA_MIMETYPE} (if both
9691          * {@link #METADATA_ACCOUNT_TYPE} and {@link #METADATA_MIMETYPE} are specified by the app;
9692          * otherwise, the value will be a phone number), and should be the unambiguous contact
9693          * endpoint. This value is app-specific, it could be some proprietary ID or a phone number.
9694          */
9695         public static final String EXTRA_RECIPIENT_CONTACT_CHAT_ID =
9696                 "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
9697 
9698         /**
9699          * This extra specifies the contact name (full name from the Contacts Provider), used with
9700          * {@link #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS} to supply the recipient. The value of this
9701          * extra is a {@code String[]}. The number of elements in the array should be equal to
9702          * number of recipients (and consistent with {@link #EXTRA_RECIPIENT_CONTACT_URI} and {@link
9703          * #EXTRA_RECIPIENT_CONTACT_CHAT_ID}). When the value of the element for the particular
9704          * recipient is absent, it will be set to null.
9705          * <p>
9706          * The value of the elements comes from RawContact's display_name column.
9707          * <p>
9708          * <em>Example value: {"Jane Doe"}</em>
9709          */
9710         public static final String EXTRA_RECIPIENT_CONTACT_NAME =
9711                 "android.provider.extra.RECIPIENT_CONTACT_NAME";
9712 
9713         /**
9714          * A string associated with an {@link #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS} activity
9715          * describing {@link RawContacts#ACCOUNT_TYPE} for the corresponding Contacts Provider
9716          * implementation.
9717          */
9718         public static final String METADATA_ACCOUNT_TYPE = "android.provider.account_type";
9719 
9720         /**
9721          * A string associated with an {@link #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS} activity
9722          * describing {@link DataColumns#MIMETYPE} for the corresponding Contacts Provider
9723          * implementation.
9724          */
9725         public static final String METADATA_MIMETYPE = "android.provider.mimetype";
9726 
9727         /**
9728          * Starts an Activity that lets the user select the multiple phones from a
9729          * list of phone numbers which come from the contacts or
9730          * {@link #EXTRA_PHONE_URIS}.
9731          * <p>
9732          * The phone numbers being passed in through {@link #EXTRA_PHONE_URIS}
9733          * could belong to the contacts or not, and will be selected by default.
9734          * <p>
9735          * The user's selection will be returned from
9736          * {@link android.app.Activity#onActivityResult(int, int, android.content.Intent)}
9737          * if the resultCode is
9738          * {@link android.app.Activity#RESULT_OK}, the array of picked phone
9739          * numbers are in the Intent's
9740          * {@link #EXTRA_PHONE_URIS}; otherwise, the
9741          * {@link android.app.Activity#RESULT_CANCELED} is returned if the user
9742          * left the Activity without changing the selection.
9743          *
9744          * @hide
9745          */
9746         public static final String ACTION_GET_MULTIPLE_PHONES =
9747                 "com.android.contacts.action.GET_MULTIPLE_PHONES";
9748 
9749         /**
9750          * A broadcast action which is sent when any change has been made to the profile, such
9751          * as the profile name or the picture.  A receiver must have
9752          * the android.permission.READ_PROFILE permission.
9753          *
9754          * @hide
9755          */
9756         public static final String ACTION_PROFILE_CHANGED =
9757                 "android.provider.Contacts.PROFILE_CHANGED";
9758 
9759         /**
9760          * Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new
9761          * contact if no matching contact found. Otherwise, default behavior is
9762          * to prompt user with dialog before creating.
9763          * <p>
9764          * Type: BOOLEAN
9765          */
9766         public static final String EXTRA_FORCE_CREATE =
9767                 "com.android.contacts.action.FORCE_CREATE";
9768 
9769         /**
9770          * Used with {@link #SHOW_OR_CREATE_CONTACT} to specify an exact
9771          * description to be shown when prompting user about creating a new
9772          * contact.
9773          * <p>
9774          * Type: STRING
9775          */
9776         public static final String EXTRA_CREATE_DESCRIPTION =
9777             "com.android.contacts.action.CREATE_DESCRIPTION";
9778 
9779         /**
9780          * Used with {@link #ACTION_GET_MULTIPLE_PHONES} as the input or output value.
9781          * <p>
9782          * The phone numbers want to be picked by default should be passed in as
9783          * input value. These phone numbers could belong to the contacts or not.
9784          * <p>
9785          * The phone numbers which were picked by the user are returned as output
9786          * value.
9787          * <p>
9788          * Type: array of URIs, the tel URI is used for the phone numbers which don't
9789          * belong to any contact, the content URI is used for phone id in contacts.
9790          *
9791          * @hide
9792          */
9793         public static final String EXTRA_PHONE_URIS =
9794             "com.android.contacts.extra.PHONE_URIS";
9795 
9796         /**
9797          * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to specify a
9798          * dialog location using screen coordinates. When not specified, the
9799          * dialog will be centered.
9800          *
9801          * @hide
9802          */
9803         @Deprecated
9804         public static final String EXTRA_TARGET_RECT = "target_rect";
9805 
9806         /**
9807          * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to specify a
9808          * desired dialog style, usually a variation on size. One of
9809          * {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or {@link #MODE_LARGE}.
9810          *
9811          * @hide
9812          */
9813         @Deprecated
9814         public static final String EXTRA_MODE = "mode";
9815 
9816         /**
9817          * Value for {@link #EXTRA_MODE} to show a small-sized dialog.
9818          *
9819          * @hide
9820          */
9821         @Deprecated
9822         public static final int MODE_SMALL = 1;
9823 
9824         /**
9825          * Value for {@link #EXTRA_MODE} to show a medium-sized dialog.
9826          *
9827          * @hide
9828          */
9829         @Deprecated
9830         public static final int MODE_MEDIUM = 2;
9831 
9832         /**
9833          * Value for {@link #EXTRA_MODE} to show a large-sized dialog.
9834          *
9835          * @hide
9836          */
9837         @Deprecated
9838         public static final int MODE_LARGE = 3;
9839 
9840         /**
9841          * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to indicate
9842          * a list of specific MIME-types to exclude and not display. Stored as a
9843          * {@link String} array.
9844          *
9845          * @hide
9846          */
9847         @Deprecated
9848         public static final String EXTRA_EXCLUDE_MIMES = "exclude_mimes";
9849 
9850         /**
9851          * Convenience class that contains string constants used
9852          * to create contact {@link android.content.Intent Intents}.
9853          */
9854         public static final class Insert {
9855             /** The action code to use when adding a contact */
9856             public static final String ACTION = Intent.ACTION_INSERT;
9857 
9858             /**
9859              * If present, forces a bypass of quick insert mode.
9860              */
9861             public static final String FULL_MODE = "full_mode";
9862 
9863             /**
9864              * The extra field for the contact name.
9865              * <P>Type: String</P>
9866              */
9867             public static final String NAME = "name";
9868 
9869             // TODO add structured name values here.
9870 
9871             /**
9872              * The extra field for the contact phonetic name.
9873              * <P>Type: String</P>
9874              */
9875             public static final String PHONETIC_NAME = "phonetic_name";
9876 
9877             /**
9878              * The extra field for the contact company.
9879              * <P>Type: String</P>
9880              */
9881             public static final String COMPANY = "company";
9882 
9883             /**
9884              * The extra field for the contact job title.
9885              * <P>Type: String</P>
9886              */
9887             public static final String JOB_TITLE = "job_title";
9888 
9889             /**
9890              * The extra field for the contact notes.
9891              * <P>Type: String</P>
9892              */
9893             public static final String NOTES = "notes";
9894 
9895             /**
9896              * The extra field for the contact phone number.
9897              * <P>Type: String</P>
9898              */
9899             public static final String PHONE = "phone";
9900 
9901             /**
9902              * The extra field for the contact phone number type.
9903              * <P>Type: Either an integer value from
9904              * {@link CommonDataKinds.Phone},
9905              *  or a string specifying a custom label.</P>
9906              */
9907             public static final String PHONE_TYPE = "phone_type";
9908 
9909             /**
9910              * The extra field for the phone isprimary flag.
9911              * <P>Type: boolean</P>
9912              */
9913             public static final String PHONE_ISPRIMARY = "phone_isprimary";
9914 
9915             /**
9916              * The extra field for an optional second contact phone number.
9917              * <P>Type: String</P>
9918              */
9919             public static final String SECONDARY_PHONE = "secondary_phone";
9920 
9921             /**
9922              * The extra field for an optional second contact phone number type.
9923              * <P>Type: Either an integer value from
9924              * {@link CommonDataKinds.Phone},
9925              *  or a string specifying a custom label.</P>
9926              */
9927             public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";
9928 
9929             /**
9930              * The extra field for an optional third contact phone number.
9931              * <P>Type: String</P>
9932              */
9933             public static final String TERTIARY_PHONE = "tertiary_phone";
9934 
9935             /**
9936              * The extra field for an optional third contact phone number type.
9937              * <P>Type: Either an integer value from
9938              * {@link CommonDataKinds.Phone},
9939              *  or a string specifying a custom label.</P>
9940              */
9941             public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
9942 
9943             /**
9944              * The extra field for the contact email address.
9945              * <P>Type: String</P>
9946              */
9947             public static final String EMAIL = "email";
9948 
9949             /**
9950              * The extra field for the contact email type.
9951              * <P>Type: Either an integer value from
9952              * {@link CommonDataKinds.Email}
9953              *  or a string specifying a custom label.</P>
9954              */
9955             public static final String EMAIL_TYPE = "email_type";
9956 
9957             /**
9958              * The extra field for the email isprimary flag.
9959              * <P>Type: boolean</P>
9960              */
9961             public static final String EMAIL_ISPRIMARY = "email_isprimary";
9962 
9963             /**
9964              * The extra field for an optional second contact email address.
9965              * <P>Type: String</P>
9966              */
9967             public static final String SECONDARY_EMAIL = "secondary_email";
9968 
9969             /**
9970              * The extra field for an optional second contact email type.
9971              * <P>Type: Either an integer value from
9972              * {@link CommonDataKinds.Email}
9973              *  or a string specifying a custom label.</P>
9974              */
9975             public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";
9976 
9977             /**
9978              * The extra field for an optional third contact email address.
9979              * <P>Type: String</P>
9980              */
9981             public static final String TERTIARY_EMAIL = "tertiary_email";
9982 
9983             /**
9984              * The extra field for an optional third contact email type.
9985              * <P>Type: Either an integer value from
9986              * {@link CommonDataKinds.Email}
9987              *  or a string specifying a custom label.</P>
9988              */
9989             public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
9990 
9991             /**
9992              * The extra field for the contact postal address.
9993              * <P>Type: String</P>
9994              */
9995             public static final String POSTAL = "postal";
9996 
9997             /**
9998              * The extra field for the contact postal address type.
9999              * <P>Type: Either an integer value from
10000              * {@link CommonDataKinds.StructuredPostal}
10001              *  or a string specifying a custom label.</P>
10002              */
10003             public static final String POSTAL_TYPE = "postal_type";
10004 
10005             /**
10006              * The extra field for the postal isprimary flag.
10007              * <P>Type: boolean</P>
10008              */
10009             public static final String POSTAL_ISPRIMARY = "postal_isprimary";
10010 
10011             /**
10012              * The extra field for an IM handle.
10013              * <P>Type: String</P>
10014              */
10015             public static final String IM_HANDLE = "im_handle";
10016 
10017             /**
10018              * The extra field for the IM protocol
10019              */
10020             public static final String IM_PROTOCOL = "im_protocol";
10021 
10022             /**
10023              * The extra field for the IM isprimary flag.
10024              * <P>Type: boolean</P>
10025              */
10026             public static final String IM_ISPRIMARY = "im_isprimary";
10027 
10028             /**
10029              * The extra field that allows the client to supply multiple rows of
10030              * arbitrary data for a single contact created using the {@link Intent#ACTION_INSERT}
10031              * or edited using {@link Intent#ACTION_EDIT}. It is an ArrayList of
10032              * {@link ContentValues}, one per data row. Supplying this extra is
10033              * similar to inserting multiple rows into the {@link Data} table,
10034              * except the user gets a chance to see and edit them before saving.
10035              * Each ContentValues object must have a value for {@link Data#MIMETYPE}.
10036              * If supplied values are not visible in the editor UI, they will be
10037              * dropped.  Duplicate data will dropped.  Some fields
10038              * like {@link CommonDataKinds.Email#TYPE Email.TYPE} may be automatically
10039              * adjusted to comply with the constraints of the specific account type.
10040              * For example, an Exchange contact can only have one phone numbers of type Home,
10041              * so the contact editor may choose a different type for this phone number to
10042              * avoid dropping the valueable part of the row, which is the phone number.
10043              * <p>
10044              * Example:
10045              * <pre>
10046              *  ArrayList&lt;ContentValues&gt; data = new ArrayList&lt;ContentValues&gt;();
10047              *
10048              *  ContentValues row1 = new ContentValues();
10049              *  row1.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
10050              *  row1.put(Organization.COMPANY, "Android");
10051              *  data.add(row1);
10052              *
10053              *  ContentValues row2 = new ContentValues();
10054              *  row2.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
10055              *  row2.put(Email.TYPE, Email.TYPE_CUSTOM);
10056              *  row2.put(Email.LABEL, "Green Bot");
10057              *  row2.put(Email.ADDRESS, "android@android.com");
10058              *  data.add(row2);
10059              *
10060              *  Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
10061              *  intent.putParcelableArrayListExtra(Insert.DATA, data);
10062              *
10063              *  startActivity(intent);
10064              * </pre>
10065              */
10066             public static final String DATA = "data";
10067 
10068             /**
10069              * Used to specify the account in which to create the new contact.
10070              * <p>
10071              * If this value is not provided, the user is presented with a disambiguation
10072              * dialog to chose an account
10073              * <p>
10074              * Type: {@link Account}
10075              */
10076             public static final String EXTRA_ACCOUNT = "android.provider.extra.ACCOUNT";
10077 
10078             /**
10079              * Used to specify the data set within the account in which to create the
10080              * new contact.
10081              * <p>
10082              * This value is optional - if it is not specified, the contact will be
10083              * created in the base account, with no data set.
10084              * <p>
10085              * Type: String
10086              */
10087             public static final String EXTRA_DATA_SET = "android.provider.extra.DATA_SET";
10088         }
10089     }
10090 
10091     /**
10092      * @hide
10093      * @deprecated These columns were never public since added. They will not be supported
10094      * as of Android version {@link android.os.Build.VERSION_CODES#R}.
10095      */
10096     @Deprecated
10097     @SystemApi
10098     protected interface MetadataSyncColumns {
10099 
10100         /**
10101          * The raw contact backup id.
10102          * A reference to the {@link ContactsContract.RawContacts#BACKUP_ID} that save the
10103          * persistent unique id for each raw contact within its source system.
10104          */
10105         public static final String RAW_CONTACT_BACKUP_ID = "raw_contact_backup_id";
10106 
10107         /**
10108          * The account type to which the raw_contact of this item is associated. See
10109          * {@link RawContacts#ACCOUNT_TYPE}
10110          */
10111         public static final String ACCOUNT_TYPE = "account_type";
10112 
10113         /**
10114          * The account name to which the raw_contact of this item is associated. See
10115          * {@link RawContacts#ACCOUNT_NAME}
10116          */
10117         public static final String ACCOUNT_NAME = "account_name";
10118 
10119         /**
10120          * The data set within the account that the raw_contact of this row belongs to. This allows
10121          * multiple sync adapters for the same account type to distinguish between
10122          * each others' data.
10123          * {@link RawContacts#DATA_SET}
10124          */
10125         public static final String DATA_SET = "data_set";
10126 
10127         /**
10128          * A text column contains the Json string got from People API. The Json string contains
10129          * all the metadata related to the raw contact, i.e., all the data fields and
10130          * aggregation exceptions.
10131          *
10132          * Here is an example of the Json string got from the actual schema.
10133          * <pre>
10134          *     {
10135          *       "unique_contact_id": {
10136          *         "account_type": "CUSTOM_ACCOUNT",
10137          *         "custom_account_type": "facebook",
10138          *         "account_name": "android-test",
10139          *         "contact_id": "1111111",
10140          *         "data_set": "FOCUS"
10141          *       },
10142          *       "contact_prefs": {
10143          *         "send_to_voicemail": true,
10144          *         "starred": false,
10145          *         "pinned": 2
10146          *       },
10147          *       "aggregation_data": [
10148          *         {
10149          *           "type": "TOGETHER",
10150          *           "contact_ids": [
10151          *             {
10152          *               "account_type": "GOOGLE_ACCOUNT",
10153          *               "account_name": "android-test2",
10154          *               "contact_id": "2222222",
10155          *               "data_set": "GOOGLE_PLUS"
10156          *             },
10157          *             {
10158          *               "account_type": "GOOGLE_ACCOUNT",
10159          *               "account_name": "android-test3",
10160          *               "contact_id": "3333333",
10161          *               "data_set": "CUSTOM",
10162          *               "custom_data_set": "custom type"
10163          *             }
10164          *           ]
10165          *         }
10166          *       ],
10167          *       "field_data": [
10168          *         {
10169          *           "field_data_id": "1001",
10170          *           "field_data_prefs": {
10171          *             "is_primary": true,
10172          *             "is_super_primary": true
10173          *           },
10174          *           "usage_stats": [
10175          *             {
10176          *               "usage_type": "CALL",
10177          *               "last_time_used": 10000001,
10178          *               "usage_count": 10
10179          *             }
10180          *           ]
10181          *         }
10182          *       ]
10183          *     }
10184          * </pre>
10185          */
10186         public static final String DATA = "data";
10187 
10188         /**
10189          * The "deleted" flag: "0" by default, "1" if the row has been marked
10190          * for deletion. When {@link android.content.ContentResolver#delete} is
10191          * called on a raw contact, updating MetadataSync table to set the flag of the raw contact
10192          * as "1", then metadata sync adapter deletes the raw contact metadata on the server.
10193          * <P>Type: INTEGER</P>
10194          */
10195         public static final String DELETED = "deleted";
10196     }
10197 
10198     /**
10199      * Constants for the metadata sync table. This table is used to cache the metadata_sync data
10200      * from server before it is merged into other CP2 tables.
10201      *
10202      * @hide
10203      * @deprecated These columns were never public since added. They will not be supported
10204      * as of Android version {@link android.os.Build.VERSION_CODES#R}.
10205      */
10206     @Deprecated
10207     @SystemApi
10208     public static final class MetadataSync implements BaseColumns, MetadataSyncColumns {
10209 
10210         /** The authority for the contacts metadata */
10211         public static final String METADATA_AUTHORITY = "com.android.contacts.metadata";
10212 
10213         /** A content:// style uri to the authority for the contacts metadata */
10214         public static final Uri METADATA_AUTHORITY_URI = Uri.parse(
10215                 "content://" + METADATA_AUTHORITY);
10216 
10217         /**
10218          * This utility class cannot be instantiated
10219          */
MetadataSync()10220         private MetadataSync() {
10221         }
10222 
10223         /**
10224          * The content:// style URI for this table.
10225          */
10226         public static final Uri CONTENT_URI = Uri.withAppendedPath(METADATA_AUTHORITY_URI,
10227                 "metadata_sync");
10228 
10229         /**
10230          * The MIME type of {@link #CONTENT_URI} providing a directory of contact metadata
10231          */
10232         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata";
10233 
10234         /**
10235          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single contact metadata.
10236          */
10237         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata";
10238     }
10239 
10240     /**
10241      * @hide
10242      * @deprecated These columns are no longer supported as of Android version
10243      * {@link android.os.Build.VERSION_CODES#R}.
10244      */
10245     @Deprecated
10246     @SystemApi
10247     protected interface MetadataSyncStateColumns {
10248 
10249         /**
10250          * A reference to the name of the account to which this state belongs
10251          * <P>Type: STRING</P>
10252          */
10253         public static final String ACCOUNT_TYPE = "account_type";
10254 
10255         /**
10256          * A reference to the type of the account to which this state belongs
10257          * <P>Type: STRING</P>
10258          */
10259         public static final String ACCOUNT_NAME = "account_name";
10260 
10261         /**
10262          * A reference to the data set within the account to which this state belongs
10263          * <P>Type: STRING</P>
10264          */
10265         public static final String DATA_SET = "data_set";
10266 
10267         /**
10268          * The sync state associated with this account.
10269          * <P>Type: Blob</P>
10270          */
10271         public static final String STATE = "state";
10272     }
10273 
10274     /**
10275      * Constants for the metadata_sync_state table. This table is used to store the metadata
10276      * sync state for a set of accounts.
10277      *
10278      * @hide
10279      * @deprecated These columns are no longer supported as of Android version
10280      * {@link android.os.Build.VERSION_CODES#R}.
10281      */
10282     @Deprecated
10283     @SystemApi
10284     public static final class MetadataSyncState implements BaseColumns, MetadataSyncStateColumns {
10285 
10286         /**
10287          * This utility class cannot be instantiated
10288          */
MetadataSyncState()10289         private MetadataSyncState() {
10290         }
10291 
10292         /**
10293          * The content:// style URI for this table.
10294          */
10295         public static final Uri CONTENT_URI =
10296                 Uri.withAppendedPath(MetadataSync.METADATA_AUTHORITY_URI, "metadata_sync_state");
10297 
10298         /**
10299          * The MIME type of {@link #CONTENT_URI} providing a directory of contact metadata sync
10300          * states.
10301          */
10302         public static final String CONTENT_TYPE =
10303                 "vnd.android.cursor.dir/contact_metadata_sync_state";
10304 
10305         /**
10306          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single contact metadata sync
10307          * state.
10308          */
10309         public static final String CONTENT_ITEM_TYPE =
10310                 "vnd.android.cursor.item/contact_metadata_sync_state";
10311     }
10312 
nullSafeCall(@onNull ContentResolver resolver, @NonNull Uri uri, @NonNull String method, @Nullable String arg, @Nullable Bundle extras)10313     private static Bundle nullSafeCall(@NonNull ContentResolver resolver, @NonNull Uri uri,
10314             @NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
10315         try (ContentProviderClient client = resolver.acquireContentProviderClient(uri)) {
10316             return client.call(method, arg, extras);
10317         } catch (RemoteException e) {
10318             throw e.rethrowAsRuntimeException();
10319         }
10320     }
10321 }
10322