• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.FlaggedApi;
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.RequiresPermission;
25 import android.annotation.SdkConstant;
26 import android.annotation.SdkConstant.SdkConstantType;
27 import android.annotation.SystemApi;
28 import android.annotation.TestApi;
29 import android.app.Activity;
30 import android.compat.annotation.UnsupportedAppUsage;
31 import android.content.BroadcastReceiver;
32 import android.content.ComponentName;
33 import android.content.ContentProviderClient;
34 import android.content.ContentProviderOperation;
35 import android.content.ContentResolver;
36 import android.content.ContentUris;
37 import android.content.ContentValues;
38 import android.content.Context;
39 import android.content.ContextWrapper;
40 import android.content.CursorEntityIterator;
41 import android.content.Entity;
42 import android.content.Entity.NamedContentValues;
43 import android.content.EntityIterator;
44 import android.content.Intent;
45 import android.content.IntentFilter;
46 import android.content.res.AssetFileDescriptor;
47 import android.content.res.Resources;
48 import android.database.Cursor;
49 import android.database.CursorWrapper;
50 import android.database.DatabaseUtils;
51 import android.graphics.Rect;
52 import android.net.Uri;
53 import android.os.Build;
54 import android.os.Bundle;
55 import android.os.Parcel;
56 import android.os.Parcelable;
57 import android.os.RemoteException;
58 import android.telecom.PhoneAccountHandle;
59 import android.text.TextUtils;
60 import android.util.DisplayMetrics;
61 import android.util.Log;
62 import android.util.Pair;
63 import android.view.View;
64 
65 import com.google.android.collect.Sets;
66 
67 import java.io.ByteArrayInputStream;
68 import java.io.IOException;
69 import java.io.InputStream;
70 import java.lang.annotation.Retention;
71 import java.lang.annotation.RetentionPolicy;
72 import java.util.ArrayList;
73 import java.util.HashMap;
74 import java.util.List;
75 import java.util.Map;
76 import java.util.Objects;
77 import java.util.Set;
78 
79 /**
80  * <p>
81  * The contract between the contacts provider and applications. Contains
82  * definitions for the supported URIs and columns. These APIs supersede
83  * {@link Contacts}.
84  * </p>
85  * <h3>Overview</h3>
86  * <p>
87  * ContactsContract defines an extensible database of contact-related
88  * information. Contact information is stored in a three-tier data model:
89  * </p>
90  * <ul>
91  * <li>
92  * A row in the {@link Data} table can store any kind of personal data, such
93  * as a phone number or email addresses.  The set of data kinds that can be
94  * stored in this table is open-ended. There is a predefined set of common
95  * kinds, but any application can add its own data kinds.
96  * </li>
97  * <li>
98  * A row in the {@link RawContacts} table represents a set of data describing a
99  * person and associated with a single account (for example, one of the user's
100  * Gmail accounts).
101  * </li>
102  * <li>
103  * A row in the {@link Contacts} table represents an aggregate of one or more
104  * RawContacts presumably describing the same person.  When data in or associated with
105  * the RawContacts table is changed, the affected aggregate contacts are updated as
106  * necessary.
107  * </li>
108  * </ul>
109  * <p>
110  * Other tables include:
111  * </p>
112  * <ul>
113  * <li>
114  * {@link Groups}, which contains information about raw contact groups
115  * such as Gmail contact groups.  The
116  * current API does not support the notion of groups spanning multiple accounts.
117  * </li>
118  * <li>
119  * {@link StatusUpdates}, which contains social status updates including IM
120  * availability.
121  * </li>
122  * <li>
123  * {@link AggregationExceptions}, which is used for manual aggregation and
124  * disaggregation of raw contacts
125  * </li>
126  * <li>
127  * {@link Settings}, which contains visibility and sync settings for accounts
128  * and groups.
129  * </li>
130  * <li>
131  * {@link SyncState}, which contains free-form data maintained on behalf of sync
132  * adapters
133  * </li>
134  * <li>
135  * {@link PhoneLookup}, which is used for quick caller-ID lookup</li>
136  * </ul>
137  */
138 @SuppressWarnings("unused")
139 public final class ContactsContract {
140     /** The authority for the contacts provider */
141     public static final String AUTHORITY = "com.android.contacts";
142     /** A content:// style uri to the authority for the contacts provider */
143     public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
144 
145     /**
146      * Prefix for column names that are not visible to client apps.
147      * @hide
148      */
149     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
150     @TestApi
151     public static final String HIDDEN_COLUMN_PREFIX = "x_";
152 
153     /**
154      * An optional URI parameter for insert, update, or delete queries
155      * that allows the caller
156      * to specify that it is a sync adapter. The default value is false. If true
157      * {@link RawContacts#DIRTY} is not automatically set and the
158      * "syncToNetwork" parameter is set to false when calling
159      * {@link
160      * ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}.
161      * This prevents an unnecessary extra synchronization, see the discussion of
162      * the delete operation in {@link RawContacts}.
163      */
164     public static final String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
165 
166     /**
167      * Query parameter that should be used by the client to access a specific
168      * {@link Directory}. The parameter value should be the _ID of the corresponding
169      * directory, e.g.
170      * {@code content://com.android.contacts/data/emails/filter/acme?directory=3}
171      */
172     public static final String DIRECTORY_PARAM_KEY = "directory";
173 
174     /**
175      * A query parameter that limits the number of results returned for supported URIs. The
176      * parameter value should be an integer.
177      *
178      * <p>This parameter is not supported by all URIs.  Supported URIs include, but not limited to,
179      * {@link Contacts#CONTENT_URI},
180      * {@link RawContacts#CONTENT_URI},
181      * {@link Data#CONTENT_URI},
182      * {@link CommonDataKinds.Phone#CONTENT_URI},
183      * {@link CommonDataKinds.Callable#CONTENT_URI},
184      * {@link CommonDataKinds.Email#CONTENT_URI},
185      * {@link CommonDataKinds.Contactables#CONTENT_URI},
186      *
187      * <p>In order to limit the number of rows returned by a non-supported URI, you can implement a
188      * {@link CursorWrapper} and override the {@link CursorWrapper#getCount()} methods.
189      */
190     public static final String LIMIT_PARAM_KEY = "limit";
191 
192     /**
193      * A query parameter specifing a primary account. This parameter should be used with
194      * {@link #PRIMARY_ACCOUNT_TYPE}. The contacts provider handling a query may rely on
195      * this information to optimize its query results.
196      *
197      * For example, in an email composition screen, its implementation can specify an account when
198      * obtaining possible recipients, letting the provider know which account is selected during
199      * the composition. The provider may use the "primary account" information to optimize
200      * the search result.
201      */
202     public static final String PRIMARY_ACCOUNT_NAME = "name_for_primary_account";
203 
204     /**
205      * A query parameter specifing a primary account. This parameter should be used with
206      * {@link #PRIMARY_ACCOUNT_NAME}. See the doc in {@link #PRIMARY_ACCOUNT_NAME}.
207      */
208     public static final String PRIMARY_ACCOUNT_TYPE = "type_for_primary_account";
209 
210     /**
211      * A boolean parameter for {@link Contacts#CONTENT_STREQUENT_URI} and
212      * {@link Contacts#CONTENT_STREQUENT_FILTER_URI}, which requires the ContactsProvider to
213      * return only phone-related results.
214      */
215     public static final String STREQUENT_PHONE_ONLY = "strequent_phone_only";
216 
217     /**
218      * A key to a boolean in the "extras" bundle of the cursor.
219      * The boolean indicates that the provider did not create a snippet and that the client asking
220      * for the snippet should do it (true means the snippeting was deferred to the client).
221      *
222      * @see SearchSnippets
223      */
224     public static final String DEFERRED_SNIPPETING = "deferred_snippeting";
225 
226     /**
227      * Key to retrieve the original deferred snippeting from the cursor on the client side.
228      *
229      * @see SearchSnippets
230      * @see #DEFERRED_SNIPPETING
231      */
232     public static final String DEFERRED_SNIPPETING_QUERY = "deferred_snippeting_query";
233 
234     /**
235      * A boolean parameter for {@link CommonDataKinds.Phone#CONTENT_URI Phone.CONTENT_URI},
236      * {@link CommonDataKinds.Email#CONTENT_URI Email.CONTENT_URI}, and
237      * {@link CommonDataKinds.StructuredPostal#CONTENT_URI StructuredPostal.CONTENT_URI}.
238      * This enables a content provider to remove duplicate entries in results.
239      */
240     public static final String REMOVE_DUPLICATE_ENTRIES = "remove_duplicate_entries";
241 
242     /**
243      * <p>
244      * API for obtaining a pre-authorized version of a URI that normally requires special
245      * permission (beyond READ_CONTACTS) to read.  The caller obtaining the pre-authorized URI
246      * must already have the necessary permissions to access the URI; otherwise a
247      * {@link SecurityException} will be thrown. Unlike {@link Context#grantUriPermission},
248      * this can be used to grant permissions that aren't explicitly required for the URI inside
249      * AndroidManifest.xml. For example, permissions that are only required when reading URIs
250      * that refer to the user's profile.
251      * </p>
252      * <p>
253      * The authorized URI returned in the bundle contains an expiring token that allows the
254      * caller to execute the query without having the special permissions that would normally
255      * be required. The token expires in five minutes.
256      * </p>
257      * <p>
258      * This API does not access disk, and should be safe to invoke from the UI thread.
259      * </p>
260      * <p>
261      * Example usage:
262      * <pre>
263      * Uri profileUri = ContactsContract.Profile.CONTENT_VCARD_URI;
264      * Bundle uriBundle = new Bundle();
265      * uriBundle.putParcelable(ContactsContract.Authorization.KEY_URI_TO_AUTHORIZE, uri);
266      * Bundle authResponse = getContext().getContentResolver().call(
267      *         ContactsContract.AUTHORITY_URI,
268      *         ContactsContract.Authorization.AUTHORIZATION_METHOD,
269      *         null, // String arg, not used.
270      *         uriBundle);
271      * if (authResponse != null) {
272      *     Uri preauthorizedProfileUri = (Uri) authResponse.getParcelable(
273      *             ContactsContract.Authorization.KEY_AUTHORIZED_URI);
274      *     // This pre-authorized URI can be queried by a caller without READ_PROFILE
275      *     // permission.
276      * }
277      * </pre>
278      * </p>
279      *
280      * @hide
281      */
282     public static final class Authorization {
283         /**
284          * The method to invoke to create a pre-authorized URI out of the input argument.
285          */
286         public static final String AUTHORIZATION_METHOD = "authorize";
287 
288         /**
289          * The key to set in the outbound Bundle with the URI that should be authorized.
290          */
291         public static final String KEY_URI_TO_AUTHORIZE = "uri_to_authorize";
292 
293         /**
294          * The key to retrieve from the returned Bundle to obtain the pre-authorized URI.
295          */
296         public static final String KEY_AUTHORIZED_URI = "authorized_uri";
297     }
298 
299     /**
300      * A Directory represents a contacts corpus, e.g. Local contacts,
301      * Google Apps Global Address List or Corporate Global Address List.
302      * <p>
303      * A Directory is implemented as a content provider with its unique authority and
304      * the same API as the main Contacts Provider.  However, there is no expectation that
305      * every directory provider will implement this Contract in its entirety.  If a
306      * directory provider does not have an implementation for a specific request, it
307      * should throw an UnsupportedOperationException.
308      * </p>
309      * <p>
310      * The most important use case for Directories is search.  A Directory provider is
311      * expected to support at least {@link ContactsContract.Contacts#CONTENT_FILTER_URI
312      * Contacts.CONTENT_FILTER_URI}.  If a Directory provider wants to participate
313      * in email and phone lookup functionalities, it should also implement
314      * {@link CommonDataKinds.Email#CONTENT_FILTER_URI CommonDataKinds.Email.CONTENT_FILTER_URI}
315      * and
316      * {@link CommonDataKinds.Phone#CONTENT_FILTER_URI CommonDataKinds.Phone.CONTENT_FILTER_URI}.
317      * </p>
318      * <p>
319      * A directory provider should return NULL for every projection field it does not
320      * recognize, rather than throwing an exception.  This way it will not be broken
321      * if ContactsContract is extended with new fields in the future.
322      * </p>
323      * <p>
324      * The client interacts with a directory via Contacts Provider by supplying an
325      * optional {@code directory=} query parameter.
326      * <p>
327      * <p>
328      * When the Contacts Provider receives the request, it transforms the URI and forwards
329      * the request to the corresponding directory content provider.
330      * The URI is transformed in the following fashion:
331      * <ul>
332      * <li>The URI authority is replaced with the corresponding {@link #DIRECTORY_AUTHORITY}.</li>
333      * <li>The {@code accountName=} and {@code accountType=} parameters are added or
334      * replaced using the corresponding {@link #ACCOUNT_TYPE} and {@link #ACCOUNT_NAME} values.</li>
335      * </ul>
336      * </p>
337      * <p>
338      * Clients should send directory requests to Contacts Provider and let it
339      * forward them to the respective providers rather than constructing
340      * directory provider URIs by themselves. This level of indirection allows
341      * Contacts Provider to implement additional system-level features and
342      * optimizations. Access to Contacts Provider is protected by the
343      * READ_CONTACTS permission, but access to the directory provider is protected by
344      * BIND_DIRECTORY_SEARCH. This permission was introduced at the API level 17, for previous
345      * platform versions the provider should perform the following check to make sure the call
346      * is coming from the ContactsProvider:
347      * <pre>
348      * private boolean isCallerAllowed() {
349      *   PackageManager pm = getContext().getPackageManager();
350      *   for (String packageName: pm.getPackagesForUid(Binder.getCallingUid())) {
351      *     if (packageName.equals("com.android.providers.contacts")) {
352      *       return true;
353      *     }
354      *   }
355      *   return false;
356      * }
357      * </pre>
358      * </p>
359      * <p>
360      * The Directory table is read-only and is maintained by the Contacts Provider
361      * automatically.
362      * </p>
363      * <p>It always has at least these two rows:
364      * <ul>
365      * <li>
366      * The local directory. It has {@link Directory#_ID Directory._ID} =
367      * {@link Directory#DEFAULT Directory.DEFAULT}. This directory can be used to access locally
368      * stored contacts. The same can be achieved by omitting the {@code directory=}
369      * parameter altogether.
370      * </li>
371      * <li>
372      * The local invisible contacts. The corresponding directory ID is
373      * {@link Directory#LOCAL_INVISIBLE Directory.LOCAL_INVISIBLE}.
374      * </li>
375      * </ul>
376      * </p>
377      * <p>Custom Directories are discovered by the Contacts Provider following this procedure:
378      * <ul>
379      * <li>It finds all installed content providers with meta data identifying them
380      * as directory providers in AndroidManifest.xml:
381      * <code>
382      * &lt;meta-data android:name="android.content.ContactDirectory"
383      *               android:value="true" /&gt;
384      * </code>
385      * <p>
386      * This tag should be placed inside the corresponding content provider declaration.
387      * </p>
388      * </li>
389      * <li>
390      * Then Contacts Provider sends a {@link Directory#CONTENT_URI Directory.CONTENT_URI}
391      * query to each of the directory authorities.  A directory provider must implement
392      * this query and return a list of directories.  Each directory returned by
393      * the provider must have a unique combination for the {@link #ACCOUNT_NAME} and
394      * {@link #ACCOUNT_TYPE} columns (nulls are allowed).  Since directory IDs are assigned
395      * automatically, the _ID field will not be part of the query projection.
396      * </li>
397      * <li>Contacts Provider compiles directory lists received from all directory
398      * providers into one, assigns each individual directory a globally unique ID and
399      * stores all directory records in the Directory table.
400      * </li>
401      * </ul>
402      * </p>
403      * <p>Contacts Provider automatically interrogates newly installed or replaced packages.
404      * Thus simply installing a package containing a directory provider is sufficient
405      * to have that provider registered.  A package supplying a directory provider does
406      * not have to contain launchable activities.
407      * </p>
408      * <p>
409      * Every row in the Directory table is automatically associated with the corresponding package
410      * (apk).  If the package is later uninstalled, all corresponding directory rows
411      * are automatically removed from the Contacts Provider.
412      * </p>
413      * <p>
414      * When the list of directories handled by a directory provider changes
415      * (for instance when the user adds a new Directory account), the directory provider
416      * should call {@link #notifyDirectoryChange} to notify the Contacts Provider of the change.
417      * In response, the Contacts Provider will requery the directory provider to obtain the
418      * new list of directories.
419      * </p>
420      * <p>
421      * A directory row can be optionally associated with an existing account
422      * (see {@link android.accounts.AccountManager}). If the account is later removed,
423      * the corresponding directory rows are automatically removed from the Contacts Provider.
424      * </p>
425      */
426     public static final class Directory implements BaseColumns {
427 
428         /**
429          * Not instantiable.
430          */
Directory()431         private Directory() {
432         }
433 
434         /**
435          * The content:// style URI for this table.  Requests to this URI can be
436          * performed on the UI thread because they are always unblocking.
437          */
438         public static final Uri CONTENT_URI =
439                 Uri.withAppendedPath(AUTHORITY_URI, "directories");
440 
441         /**
442          * URI used for getting all directories from both the calling user and the managed profile
443          * that is linked to it.
444          * <p>
445          * It supports the same semantics as {@link #CONTENT_URI} and returns the same columns.<br>
446          * If the device has no managed profile that is linked to the calling user, it behaves
447          * in the exact same way as {@link #CONTENT_URI}.<br>
448          * If there is a managed profile linked to the calling user, it will return merged results
449          * from both.
450          * <p>
451          * Note: this query returns the calling user results before the managed profile results,
452          * and this order is not affected by the sorting parameter.
453          *
454          */
455         public static final Uri ENTERPRISE_CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
456                 "directories_enterprise");
457 
458         /**
459          * Access file provided by remote directory. It allows both calling user and managed profile
460          * remote directory, but not local and invisible directory.
461          * <p>
462          * It is supported only by a few specific places for referring to contact pictures in the
463          * remote directory. Contact picture URIs, e.g.
464          * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}, may contain this kind of URI.
465          *
466          * @hide
467          */
468         public static final Uri ENTERPRISE_FILE_URI = Uri.withAppendedPath(AUTHORITY_URI,
469                 "directory_file_enterprise");
470 
471 
472         /**
473          * The MIME-type of {@link #CONTENT_URI} providing a directory of
474          * contact directories.
475          */
476         public static final String CONTENT_TYPE =
477                 "vnd.android.cursor.dir/contact_directories";
478 
479         /**
480          * The MIME type of a {@link #CONTENT_URI} item.
481          */
482         public static final String CONTENT_ITEM_TYPE =
483                 "vnd.android.cursor.item/contact_directory";
484 
485         /**
486          * _ID of the default directory, which represents locally stored contacts.
487          * <b>This is only supported by {@link ContactsContract.Contacts#CONTENT_URI} and
488          * {@link ContactsContract.Contacts#CONTENT_FILTER_URI}.
489          * Other URLs do not support the concept of "visible" or "invisible" contacts.
490          */
491         public static final long DEFAULT = 0;
492 
493         /**
494          * _ID of the directory that represents locally stored invisible contacts.
495          */
496         public static final long LOCAL_INVISIBLE = 1;
497 
498         /**
499          * _ID of the managed profile default directory, which represents locally stored contacts.
500          */
501         public static final long ENTERPRISE_DEFAULT = Directory.ENTERPRISE_DIRECTORY_ID_BASE
502                 + DEFAULT;
503 
504         /**
505          * _ID of the managed profile directory that represents locally stored invisible contacts.
506          */
507         public static final long ENTERPRISE_LOCAL_INVISIBLE = Directory.ENTERPRISE_DIRECTORY_ID_BASE
508                 + LOCAL_INVISIBLE;
509 
510         /**
511          * The name of the package that owns this directory. Contacts Provider
512          * fill it in with the name of the package containing the directory provider.
513          * If the package is later uninstalled, the directories it owns are
514          * automatically removed from this table.
515          *
516          * <p>TYPE: TEXT</p>
517          */
518         public static final String PACKAGE_NAME = "packageName";
519 
520         /**
521          * The type of directory captured as a resource ID in the context of the
522          * package {@link #PACKAGE_NAME}, e.g. "Corporate Directory"
523          *
524          * <p>TYPE: INTEGER</p>
525          */
526         public static final String TYPE_RESOURCE_ID = "typeResourceId";
527 
528         /**
529          * An optional name that can be used in the UI to represent this directory,
530          * e.g. "Acme Corp"
531          * <p>TYPE: text</p>
532          */
533         public static final String DISPLAY_NAME = "displayName";
534 
535         /**
536          * <p>
537          * The authority of the Directory Provider. Contacts Provider will
538          * use this authority to forward requests to the directory provider.
539          * A directory provider can leave this column empty - Contacts Provider will fill it in.
540          * </p>
541          * <p>
542          * Clients of this API should not send requests directly to this authority.
543          * All directory requests must be routed through Contacts Provider.
544          * </p>
545          *
546          * <p>TYPE: text</p>
547          */
548         public static final String DIRECTORY_AUTHORITY = "authority";
549 
550         /**
551          * The account type which this directory is associated.
552          *
553          * <p>TYPE: text</p>
554          */
555         public static final String ACCOUNT_TYPE = "accountType";
556 
557         /**
558          * The account with which this directory is associated. If the account is later
559          * removed, the directories it owns are automatically removed from this table.
560          *
561          * <p>TYPE: text</p>
562          */
563         public static final String ACCOUNT_NAME = "accountName";
564 
565         /**
566          * Mimimal ID for managed profile directory returned from
567          * {@link Directory#ENTERPRISE_CONTENT_URI}.
568          *
569          * @hide
570          */
571         // slightly smaller than 2 ** 30
572         public static final long ENTERPRISE_DIRECTORY_ID_BASE = 1000000000;
573 
574         /**
575          * One of {@link #EXPORT_SUPPORT_NONE}, {@link #EXPORT_SUPPORT_ANY_ACCOUNT},
576          * {@link #EXPORT_SUPPORT_SAME_ACCOUNT_ONLY}. This is the expectation the
577          * directory has for data exported from it.  Clients must obey this setting.
578          */
579         public static final String EXPORT_SUPPORT = "exportSupport";
580 
581         /**
582          * An {@link #EXPORT_SUPPORT} setting that indicates that the directory
583          * does not allow any data to be copied out of it.
584          */
585         public static final int EXPORT_SUPPORT_NONE = 0;
586 
587         /**
588          * An {@link #EXPORT_SUPPORT} setting that indicates that the directory
589          * allow its data copied only to the account specified by
590          * {@link #ACCOUNT_TYPE}/{@link #ACCOUNT_NAME}.
591          */
592         public static final int EXPORT_SUPPORT_SAME_ACCOUNT_ONLY = 1;
593 
594         /**
595          * An {@link #EXPORT_SUPPORT} setting that indicates that the directory
596          * allow its data copied to any contacts account.
597          */
598         public static final int EXPORT_SUPPORT_ANY_ACCOUNT = 2;
599 
600         /**
601          * One of {@link #SHORTCUT_SUPPORT_NONE}, {@link #SHORTCUT_SUPPORT_DATA_ITEMS_ONLY},
602          * {@link #SHORTCUT_SUPPORT_FULL}. This is the expectation the directory
603          * has for shortcuts created for its elements. Clients must obey this setting.
604          */
605         public static final String SHORTCUT_SUPPORT = "shortcutSupport";
606 
607         /**
608          * An {@link #SHORTCUT_SUPPORT} setting that indicates that the directory
609          * does not allow any shortcuts created for its contacts.
610          */
611         public static final int SHORTCUT_SUPPORT_NONE = 0;
612 
613         /**
614          * An {@link #SHORTCUT_SUPPORT} setting that indicates that the directory
615          * allow creation of shortcuts for data items like email, phone or postal address,
616          * but not the entire contact.
617          */
618         public static final int SHORTCUT_SUPPORT_DATA_ITEMS_ONLY = 1;
619 
620         /**
621          * An {@link #SHORTCUT_SUPPORT} setting that indicates that the directory
622          * allow creation of shortcuts for contact as well as their constituent elements.
623          */
624         public static final int SHORTCUT_SUPPORT_FULL = 2;
625 
626         /**
627          * One of {@link #PHOTO_SUPPORT_NONE}, {@link #PHOTO_SUPPORT_THUMBNAIL_ONLY},
628          * {@link #PHOTO_SUPPORT_FULL}. This is a feature flag indicating the extent
629          * to which the directory supports contact photos.
630          */
631         public static final String PHOTO_SUPPORT = "photoSupport";
632 
633         /**
634          * An {@link #PHOTO_SUPPORT} setting that indicates that the directory
635          * does not provide any photos.
636          */
637         public static final int PHOTO_SUPPORT_NONE = 0;
638 
639         /**
640          * An {@link #PHOTO_SUPPORT} setting that indicates that the directory
641          * can only produce small size thumbnails of contact photos.
642          */
643         public static final int PHOTO_SUPPORT_THUMBNAIL_ONLY = 1;
644 
645         /**
646          * An {@link #PHOTO_SUPPORT} setting that indicates that the directory
647          * has full-size contact photos, but cannot provide scaled thumbnails.
648          */
649         public static final int PHOTO_SUPPORT_FULL_SIZE_ONLY = 2;
650 
651         /**
652          * An {@link #PHOTO_SUPPORT} setting that indicates that the directory
653          * can produce thumbnails as well as full-size contact photos.
654          */
655         public static final int PHOTO_SUPPORT_FULL = 3;
656 
657         /**
658          * Return TRUE if it is a remote stored directory.
659          */
isRemoteDirectoryId(long directoryId)660         public static boolean isRemoteDirectoryId(long directoryId) {
661             return directoryId != Directory.DEFAULT
662                     && directoryId != Directory.LOCAL_INVISIBLE
663                     && directoryId != Directory.ENTERPRISE_DEFAULT
664                     && directoryId != Directory.ENTERPRISE_LOCAL_INVISIBLE;
665         }
666 
667         /**
668          * Return TRUE if it is a remote stored directory. TODO: Remove this method once all
669          * internal apps are not using this API.
670          *
671          * @hide
672          */
isRemoteDirectory(long directoryId)673         public static boolean isRemoteDirectory(long directoryId) {
674             return isRemoteDirectoryId(directoryId);
675         }
676 
677         /**
678          * Return TRUE if a directory ID is from the contacts provider on the enterprise profile.
679          *
680          */
isEnterpriseDirectoryId(long directoryId)681         public static boolean isEnterpriseDirectoryId(long directoryId) {
682             return directoryId >= ENTERPRISE_DIRECTORY_ID_BASE;
683         }
684 
685         /**
686          * Notifies the system of a change in the list of directories handled by
687          * a particular directory provider. The Contacts provider will turn around
688          * and send a query to the directory provider for the full list of directories,
689          * which will replace the previous list.
690          */
notifyDirectoryChange(ContentResolver resolver)691         public static void notifyDirectoryChange(ContentResolver resolver) {
692             // This is done to trigger a query by Contacts Provider back to the directory provider.
693             // No data needs to be sent back, because the provider can infer the calling
694             // package from binder.
695             ContentValues contentValues = new ContentValues();
696             resolver.update(Directory.CONTENT_URI, contentValues, null, null);
697         }
698 
699         /**
700          * A query parameter that's passed to directory providers which indicates the client
701          * package name that has made the query requests.
702          */
703         public static final String CALLER_PACKAGE_PARAM_KEY = "callerPackage";
704     }
705 
706     /**
707      * @hide should be removed when users are updated to refer to SyncState
708      * @deprecated use SyncState instead
709      */
710     @Deprecated
711     public interface SyncStateColumns extends SyncStateContract.Columns {
712     }
713 
714     /**
715      * A table provided for sync adapters to use for storing private sync state data for contacts.
716      *
717      * @see SyncStateContract
718      */
719     public static final class SyncState implements SyncStateContract.Columns {
720         /**
721          * This utility class cannot be instantiated
722          */
SyncState()723         private SyncState() {}
724 
725         public static final String CONTENT_DIRECTORY =
726                 SyncStateContract.Constants.CONTENT_DIRECTORY;
727 
728         /**
729          * The content:// style URI for this table
730          */
731         public static final Uri CONTENT_URI =
732                 Uri.withAppendedPath(AUTHORITY_URI, CONTENT_DIRECTORY);
733 
734         /**
735          * @see android.provider.SyncStateContract.Helpers#get
736          */
get(ContentProviderClient provider, Account account)737         public static byte[] get(ContentProviderClient provider, Account account)
738                 throws RemoteException {
739             return SyncStateContract.Helpers.get(provider, CONTENT_URI, account);
740         }
741 
742         /**
743          * @see android.provider.SyncStateContract.Helpers#get
744          */
getWithUri(ContentProviderClient provider, Account account)745         public static Pair<Uri, byte[]> getWithUri(ContentProviderClient provider, Account account)
746                 throws RemoteException {
747             return SyncStateContract.Helpers.getWithUri(provider, CONTENT_URI, account);
748         }
749 
750         /**
751          * @see android.provider.SyncStateContract.Helpers#set
752          */
set(ContentProviderClient provider, Account account, byte[] data)753         public static void set(ContentProviderClient provider, Account account, byte[] data)
754                 throws RemoteException {
755             SyncStateContract.Helpers.set(provider, CONTENT_URI, account, data);
756         }
757 
758         /**
759          * @see android.provider.SyncStateContract.Helpers#newSetOperation
760          */
newSetOperation(Account account, byte[] data)761         public static ContentProviderOperation newSetOperation(Account account, byte[] data) {
762             return SyncStateContract.Helpers.newSetOperation(CONTENT_URI, account, data);
763         }
764     }
765 
766 
767     /**
768      * A table provided for sync adapters to use for storing private sync state data for the
769      * user's personal profile.
770      *
771      * @see SyncStateContract
772      */
773     public static final class ProfileSyncState implements SyncStateContract.Columns {
774         /**
775          * This utility class cannot be instantiated
776          */
ProfileSyncState()777         private ProfileSyncState() {}
778 
779         public static final String CONTENT_DIRECTORY =
780                 SyncStateContract.Constants.CONTENT_DIRECTORY;
781 
782         /**
783          * The content:// style URI for this table
784          */
785         public static final Uri CONTENT_URI =
786                 Uri.withAppendedPath(Profile.CONTENT_URI, CONTENT_DIRECTORY);
787 
788         /**
789          * @see android.provider.SyncStateContract.Helpers#get
790          */
get(ContentProviderClient provider, Account account)791         public static byte[] get(ContentProviderClient provider, Account account)
792                 throws RemoteException {
793             return SyncStateContract.Helpers.get(provider, CONTENT_URI, account);
794         }
795 
796         /**
797          * @see android.provider.SyncStateContract.Helpers#get
798          */
getWithUri(ContentProviderClient provider, Account account)799         public static Pair<Uri, byte[]> getWithUri(ContentProviderClient provider, Account account)
800                 throws RemoteException {
801             return SyncStateContract.Helpers.getWithUri(provider, CONTENT_URI, account);
802         }
803 
804         /**
805          * @see android.provider.SyncStateContract.Helpers#set
806          */
set(ContentProviderClient provider, Account account, byte[] data)807         public static void set(ContentProviderClient provider, Account account, byte[] data)
808                 throws RemoteException {
809             SyncStateContract.Helpers.set(provider, CONTENT_URI, account, data);
810         }
811 
812         /**
813          * @see android.provider.SyncStateContract.Helpers#newSetOperation
814          */
newSetOperation(Account account, byte[] data)815         public static ContentProviderOperation newSetOperation(Account account, byte[] data) {
816             return SyncStateContract.Helpers.newSetOperation(CONTENT_URI, account, data);
817         }
818     }
819 
820     /**
821      * Generic columns for use by sync adapters. The specific functions of
822      * these columns are private to the sync adapter. Other clients of the API
823      * should not attempt to either read or write this column.
824      *
825      * @see RawContacts
826      * @see Groups
827      */
828     protected interface BaseSyncColumns {
829 
830         /** Generic column for use by sync adapters. */
831         public static final String SYNC1 = "sync1";
832         /** Generic column for use by sync adapters. */
833         public static final String SYNC2 = "sync2";
834         /** Generic column for use by sync adapters. */
835         public static final String SYNC3 = "sync3";
836         /** Generic column for use by sync adapters. */
837         public static final String SYNC4 = "sync4";
838     }
839 
840     /**
841      * Columns that appear when each row of a table belongs to a specific
842      * account, including sync information that an account may need.
843      *
844      * @see RawContacts
845      * @see Groups
846      */
847     protected interface SyncColumns extends BaseSyncColumns {
848         /**
849          * The name of the account instance to which this row belongs, which when paired with
850          * {@link #ACCOUNT_TYPE} identifies a specific account.
851          * <P>Type: TEXT</P>
852          */
853         public static final String ACCOUNT_NAME = "account_name";
854 
855         /**
856          * The type of account to which this row belongs, which when paired with
857          * {@link #ACCOUNT_NAME} identifies a specific account.
858          * <P>Type: TEXT</P>
859          */
860         public static final String ACCOUNT_TYPE = "account_type";
861 
862         /**
863          * String that uniquely identifies this row to its source account.
864          * <P>Type: TEXT</P>
865          */
866         public static final String SOURCE_ID = "sourceid";
867 
868         /**
869          * Version number that is updated whenever this row or its related data
870          * changes.
871          * <P>Type: INTEGER</P>
872          */
873         public static final String VERSION = "version";
874 
875         /**
876          * Flag indicating that {@link #VERSION} has changed, and this row needs
877          * to be synchronized by its owning account.
878          * <P>Type: INTEGER (boolean)</P>
879          */
880         public static final String DIRTY = "dirty";
881     }
882 
883     /**
884      * Columns of {@link ContactsContract.Contacts} that track the user's
885      * preferences for, or interactions with, the contact.
886      *
887      * @see Contacts
888      * @see RawContacts
889      * @see ContactsContract.Data
890      * @see PhoneLookup
891      * @see ContactsContract.Contacts.AggregationSuggestions
892      */
893     protected interface ContactOptionsColumns {
894         /**
895          * The number of times a contact has been contacted.
896          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
897          * this field is obsolete, regardless of Android version. For more information, see the
898          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
899          * page.</p>
900          * <P>Type: INTEGER</P>
901          *
902          * @deprecated Contacts affinity information is no longer supported as of
903          * Android version {@link android.os.Build.VERSION_CODES#Q}. This column
904          * always contains 0.
905          */
906         @Deprecated
907         public static final String TIMES_CONTACTED = "times_contacted";
908 
909         /**
910          * The last time a contact was contacted.
911          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
912          * this field is obsolete, regardless of Android version. For more information, see the
913          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
914          * page.</p>
915          * <P>Type: INTEGER</P>
916          *
917          * @deprecated Contacts affinity information is no longer supported as of
918          * Android version {@link android.os.Build.VERSION_CODES#Q}. This column
919          * always contains 0.
920          */
921         @Deprecated
922         public static final String LAST_TIME_CONTACTED = "last_time_contacted";
923 
924         /** @hide Raw value. */
925         public static final String RAW_TIMES_CONTACTED = HIDDEN_COLUMN_PREFIX + TIMES_CONTACTED;
926 
927         /** @hide Raw value. */
928         public static final String RAW_LAST_TIME_CONTACTED =
929                 HIDDEN_COLUMN_PREFIX + LAST_TIME_CONTACTED;
930 
931         /**
932          * @hide
933          * Low res version.  Same as {@link #TIMES_CONTACTED} but use it in CP2 for clarification.
934          */
935         public static final String LR_TIMES_CONTACTED = TIMES_CONTACTED;
936 
937         /**
938          * @hide
939          * Low res version.  Same as {@link #TIMES_CONTACTED} but use it in CP2 for clarification.
940          */
941         public static final String LR_LAST_TIME_CONTACTED = LAST_TIME_CONTACTED;
942 
943         /**
944          * Is the contact starred?
945          * <P>Type: INTEGER (boolean)</P>
946          */
947         public static final String STARRED = "starred";
948 
949         /**
950          * The position at which the contact is pinned. If {@link PinnedPositions#UNPINNED},
951          * the contact is not pinned. Also see {@link PinnedPositions}.
952          * <P>Type: INTEGER </P>
953          */
954         public static final String PINNED = "pinned";
955 
956         /**
957          * URI for a custom ringtone associated with the contact. If null or missing,
958          * the default ringtone is used.
959          * <P>Type: TEXT (URI to the ringtone)</P>
960          */
961         public static final String CUSTOM_RINGTONE = "custom_ringtone";
962 
963         /**
964          * Whether the contact should always be sent to voicemail. If missing,
965          * defaults to false.
966          * <P>Type: INTEGER (0 for false, 1 for true)</P>
967          */
968         public static final String SEND_TO_VOICEMAIL = "send_to_voicemail";
969     }
970 
971     /**
972      * Columns of {@link ContactsContract.Contacts} that refer to intrinsic
973      * properties of the contact, as opposed to the user-specified options
974      * found in {@link ContactOptionsColumns}.
975      *
976      * @see Contacts
977      * @see ContactsContract.Data
978      * @see PhoneLookup
979      * @see ContactsContract.Contacts.AggregationSuggestions
980      */
981     protected interface ContactsColumns {
982         /**
983          * The display name for the contact.
984          * <P>Type: TEXT</P>
985          */
986         public static final String DISPLAY_NAME = ContactNameColumns.DISPLAY_NAME_PRIMARY;
987 
988         /**
989          * Reference to the row in the RawContacts table holding the contact name.
990          * <P>Type: INTEGER REFERENCES raw_contacts(_id)</P>
991          */
992         public static final String NAME_RAW_CONTACT_ID = "name_raw_contact_id";
993 
994         /**
995          * Reference to the row in the data table holding the photo.  A photo can
996          * be referred to either by ID (this field) or by URI (see {@link #PHOTO_THUMBNAIL_URI}
997          * and {@link #PHOTO_URI}).
998          * If PHOTO_ID is null, consult {@link #PHOTO_URI} or {@link #PHOTO_THUMBNAIL_URI},
999          * which is a more generic mechanism for referencing the contact photo, especially for
1000          * contacts returned by non-local directories (see {@link Directory}).
1001          *
1002          * <P>Type: INTEGER REFERENCES data(_id)</P>
1003          */
1004         public static final String PHOTO_ID = "photo_id";
1005 
1006         /**
1007          * Photo file ID of the full-size photo.  If present, this will be used to populate
1008          * {@link #PHOTO_URI}.  The ID can also be used with
1009          * {@link ContactsContract.DisplayPhoto#CONTENT_URI} to create a URI to the photo.
1010          * If this is present, {@link #PHOTO_ID} is also guaranteed to be populated.
1011          *
1012          * <P>Type: INTEGER</P>
1013          */
1014         public static final String PHOTO_FILE_ID = "photo_file_id";
1015 
1016         /**
1017          * A URI that can be used to retrieve the contact's full-size photo.
1018          * If PHOTO_FILE_ID is not null, this will be populated with a URI based off
1019          * {@link ContactsContract.DisplayPhoto#CONTENT_URI}.  Otherwise, this will
1020          * be populated with the same value as {@link #PHOTO_THUMBNAIL_URI}.
1021          * A photo can be referred to either by a URI (this field) or by ID
1022          * (see {@link #PHOTO_ID}). If either PHOTO_FILE_ID or PHOTO_ID is not null,
1023          * PHOTO_URI and PHOTO_THUMBNAIL_URI shall not be null (but not necessarily
1024          * vice versa).  Thus using PHOTO_URI is a more robust method of retrieving
1025          * contact photos.
1026          *
1027          * <P>Type: TEXT</P>
1028          */
1029         public static final String PHOTO_URI = "photo_uri";
1030 
1031         /**
1032          * A URI that can be used to retrieve a thumbnail of the contact's photo.
1033          * A photo can be referred to either by a URI (this field or {@link #PHOTO_URI})
1034          * or by ID (see {@link #PHOTO_ID}). If PHOTO_ID is not null, PHOTO_URI and
1035          * PHOTO_THUMBNAIL_URI shall not be null (but not necessarily vice versa).
1036          * If the content provider does not differentiate between full-size photos
1037          * and thumbnail photos, PHOTO_THUMBNAIL_URI and {@link #PHOTO_URI} can contain
1038          * the same value, but either both shall be null or both not null.
1039          *
1040          * <P>Type: TEXT</P>
1041          */
1042         public static final String PHOTO_THUMBNAIL_URI = "photo_thumb_uri";
1043 
1044         /**
1045          * Flag that reflects whether the contact exists inside the default directory.
1046          * Ie, whether the contact is designed to only be visible outside search.
1047          */
1048         public static final String IN_DEFAULT_DIRECTORY = "in_default_directory";
1049 
1050         /**
1051          * Flag that reflects the {@link Groups#GROUP_VISIBLE} state of any
1052          * {@link CommonDataKinds.GroupMembership} for this contact.
1053          */
1054         public static final String IN_VISIBLE_GROUP = "in_visible_group";
1055 
1056         /**
1057          * Flag that reflects whether this contact represents the user's
1058          * personal profile entry.
1059          */
1060         public static final String IS_USER_PROFILE = "is_user_profile";
1061 
1062         /**
1063          * An indicator of whether this contact has at least one phone number. "1" if there is
1064          * at least one phone number, "0" otherwise.
1065          * <P>Type: INTEGER</P>
1066          */
1067         public static final String HAS_PHONE_NUMBER = "has_phone_number";
1068 
1069         /**
1070          * An opaque value that contains hints on how to find the contact if
1071          * its row id changed as a result of a sync or aggregation.
1072          */
1073         public static final String LOOKUP_KEY = "lookup";
1074 
1075         /**
1076          * Timestamp (milliseconds since epoch) of when this contact was last updated.  This
1077          * includes updates to all data associated with this contact including raw contacts.  Any
1078          * modification (including deletes and inserts) of underlying contact data are also
1079          * reflected in this timestamp.
1080          */
1081         public static final String CONTACT_LAST_UPDATED_TIMESTAMP =
1082                 "contact_last_updated_timestamp";
1083     }
1084 
1085     /**
1086      * @see Contacts
1087      */
1088     protected interface ContactStatusColumns {
1089         /**
1090          * Contact presence status. See {@link StatusUpdates} for individual status
1091          * definitions.
1092          * <p>Type: NUMBER</p>
1093          */
1094         public static final String CONTACT_PRESENCE = "contact_presence";
1095 
1096         /**
1097          * Contact Chat Capabilities. See {@link StatusUpdates} for individual
1098          * definitions.
1099          * <p>Type: NUMBER</p>
1100          */
1101         public static final String CONTACT_CHAT_CAPABILITY = "contact_chat_capability";
1102 
1103         /**
1104          * Contact's latest status update.
1105          * <p>Type: TEXT</p>
1106          */
1107         public static final String CONTACT_STATUS = "contact_status";
1108 
1109         /**
1110          * The absolute time in milliseconds when the latest status was
1111          * inserted/updated.
1112          * <p>Type: NUMBER</p>
1113          */
1114         public static final String CONTACT_STATUS_TIMESTAMP = "contact_status_ts";
1115 
1116         /**
1117          * The package containing resources for this status: label and icon.
1118          * <p>Type: TEXT</p>
1119          */
1120         public static final String CONTACT_STATUS_RES_PACKAGE = "contact_status_res_package";
1121 
1122         /**
1123          * The resource ID of the label describing the source of contact
1124          * status, e.g. "Google Talk". This resource is scoped by the
1125          * {@link #CONTACT_STATUS_RES_PACKAGE}.
1126          * <p>Type: NUMBER</p>
1127          */
1128         public static final String CONTACT_STATUS_LABEL = "contact_status_label";
1129 
1130         /**
1131          * The resource ID of the icon for the source of contact status. This
1132          * resource is scoped by the {@link #CONTACT_STATUS_RES_PACKAGE}.
1133          * <p>Type: NUMBER</p>
1134          */
1135         public static final String CONTACT_STATUS_ICON = "contact_status_icon";
1136     }
1137 
1138     /**
1139      * Constants for various styles of combining given name, family name etc into
1140      * a full name.  For example, the western tradition follows the pattern
1141      * 'given name' 'middle name' 'family name' with the alternative pattern being
1142      * 'family name', 'given name' 'middle name'.  The CJK tradition is
1143      * 'family name' 'middle name' 'given name', with Japanese favoring a space between
1144      * the names and Chinese omitting the space.
1145      */
1146     public interface FullNameStyle {
1147         public static final int UNDEFINED = 0;
1148         public static final int WESTERN = 1;
1149 
1150         /**
1151          * Used if the name is written in Hanzi/Kanji/Hanja and we could not determine
1152          * which specific language it belongs to: Chinese, Japanese or Korean.
1153          */
1154         public static final int CJK = 2;
1155 
1156         public static final int CHINESE = 3;
1157         public static final int JAPANESE = 4;
1158         public static final int KOREAN = 5;
1159     }
1160 
1161     /**
1162      * Constants for various styles of capturing the pronunciation of a person's name.
1163      */
1164     public interface PhoneticNameStyle {
1165         public static final int UNDEFINED = 0;
1166 
1167         /**
1168          * Pinyin is a phonetic method of entering Chinese characters. Typically not explicitly
1169          * shown in UIs, but used for searches and sorting.
1170          */
1171         public static final int PINYIN = 3;
1172 
1173         /**
1174          * Hiragana and Katakana are two common styles of writing out the pronunciation
1175          * of a Japanese names.
1176          */
1177         public static final int JAPANESE = 4;
1178 
1179         /**
1180          * Hangul is the Korean phonetic alphabet.
1181          */
1182         public static final int KOREAN = 5;
1183     }
1184 
1185     /**
1186      * Types of data used to produce the display name for a contact. In the order
1187      * of increasing priority: {@link #EMAIL}, {@link #PHONE},
1188      * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_PHONETIC_NAME},
1189      * {@link #STRUCTURED_NAME}.
1190      */
1191     public interface DisplayNameSources {
1192         public static final int UNDEFINED = 0;
1193         public static final int EMAIL = 10;
1194         public static final int PHONE = 20;
1195         public static final int ORGANIZATION = 30;
1196         public static final int NICKNAME = 35;
1197         /** Display name comes from a structured name that only has phonetic components. */
1198         public static final int STRUCTURED_PHONETIC_NAME = 37;
1199         public static final int STRUCTURED_NAME = 40;
1200     }
1201 
1202     /**
1203      * Contact name and contact name metadata columns in the RawContacts table.
1204      *
1205      * @see Contacts
1206      * @see RawContacts
1207      */
1208     protected interface ContactNameColumns {
1209 
1210         /**
1211          * The kind of data that is used as the display name for the contact, such as
1212          * structured name or email address.  See {@link DisplayNameSources}.
1213          */
1214         public static final String DISPLAY_NAME_SOURCE = "display_name_source";
1215 
1216         /**
1217          * <p>
1218          * The standard text shown as the contact's display name, based on the best
1219          * available information for the contact (for example, it might be the email address
1220          * if the name is not available).
1221          * The information actually used to compute the name is stored in
1222          * {@link #DISPLAY_NAME_SOURCE}.
1223          * </p>
1224          * <p>
1225          * A contacts provider is free to choose whatever representation makes most
1226          * sense for its target market.
1227          * For example in the default Android Open Source Project implementation,
1228          * if the display name is
1229          * based on the structured name and the structured name follows
1230          * the Western full-name style, then this field contains the "given name first"
1231          * version of the full name.
1232          * <p>
1233          *
1234          * @see ContactsContract.ContactNameColumns#DISPLAY_NAME_ALTERNATIVE
1235          */
1236         public static final String DISPLAY_NAME_PRIMARY = "display_name";
1237 
1238         /**
1239          * <p>
1240          * An alternative representation of the display name, such as "family name first"
1241          * instead of "given name first" for Western names.  If an alternative is not
1242          * available, the values should be the same as {@link #DISPLAY_NAME_PRIMARY}.
1243          * </p>
1244          * <p>
1245          * A contacts provider is free to provide alternatives as necessary for
1246          * its target market.
1247          * For example the default Android Open Source Project contacts provider
1248          * currently provides an
1249          * alternative in a single case:  if the display name is
1250          * based on the structured name and the structured name follows
1251          * the Western full name style, then the field contains the "family name first"
1252          * version of the full name.
1253          * Other cases may be added later.
1254          * </p>
1255          */
1256         public static final String DISPLAY_NAME_ALTERNATIVE = "display_name_alt";
1257 
1258         /**
1259          * The phonetic alphabet used to represent the {@link #PHONETIC_NAME}.  See
1260          * {@link PhoneticNameStyle}.
1261          */
1262         public static final String PHONETIC_NAME_STYLE = "phonetic_name_style";
1263 
1264         /**
1265          * <p>
1266          * Pronunciation of the full name in the phonetic alphabet specified by
1267          * {@link #PHONETIC_NAME_STYLE}.
1268          * </p>
1269          * <p>
1270          * The value may be set manually by the user. This capability is of
1271          * interest only in countries with commonly used phonetic alphabets,
1272          * such as Japan and Korea. See {@link PhoneticNameStyle}.
1273          * </p>
1274          */
1275         public static final String PHONETIC_NAME = "phonetic_name";
1276 
1277         /**
1278          * Sort key that takes into account locale-based traditions for sorting
1279          * names in address books.  The default
1280          * sort key is {@link #DISPLAY_NAME_PRIMARY}.  For Chinese names
1281          * the sort key is the name's Pinyin spelling, and for Japanese names
1282          * it is the Hiragana version of the phonetic name.
1283          */
1284         public static final String SORT_KEY_PRIMARY = "sort_key";
1285 
1286         /**
1287          * Sort key based on the alternative representation of the full name,
1288          * {@link #DISPLAY_NAME_ALTERNATIVE}.  Thus for Western names,
1289          * it is the one using the "family name first" format.
1290          */
1291         public static final String SORT_KEY_ALTERNATIVE = "sort_key_alt";
1292     }
1293 
1294     interface ContactCounts {
1295 
1296         /**
1297          * Add this query parameter to a URI to get back row counts grouped by the address book
1298          * index as cursor extras. For most languages it is the first letter of the sort key. This
1299          * parameter does not affect the main content of the cursor.
1300          *
1301          * <p>
1302          * <pre>
1303          * Example:
1304          *
1305          * import android.provider.ContactsContract.Contacts;
1306          *
1307          * Uri uri = Contacts.CONTENT_URI.buildUpon()
1308          *          .appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true")
1309          *          .build();
1310          * Cursor cursor = getContentResolver().query(uri,
1311          *          new String[] {Contacts.DISPLAY_NAME},
1312          *          null, null, null);
1313          * Bundle bundle = cursor.getExtras();
1314          * if (bundle.containsKey(Contacts.EXTRA_ADDRESS_BOOK_INDEX_TITLES) &&
1315          *         bundle.containsKey(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS)) {
1316          *     String sections[] =
1317          *             bundle.getStringArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_TITLES);
1318          *     int counts[] = bundle.getIntArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS);
1319          * }
1320          * </pre>
1321          * </p>
1322          */
1323         public static final String EXTRA_ADDRESS_BOOK_INDEX =
1324                 "android.provider.extra.ADDRESS_BOOK_INDEX";
1325 
1326         /**
1327          * The array of address book index titles, which are returned in the
1328          * same order as the data in the cursor.
1329          * <p>TYPE: String[]</p>
1330          */
1331         public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES =
1332                 "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
1333 
1334         /**
1335          * The array of group counts for the corresponding group.  Contains the same number
1336          * of elements as the EXTRA_ADDRESS_BOOK_INDEX_TITLES array.
1337          * <p>TYPE: int[]</p>
1338          */
1339         public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS =
1340                 "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
1341     }
1342 
1343     /**
1344      * Constants for the contacts table, which contains a record per aggregate
1345      * of raw contacts representing the same person.
1346      * <h3>Operations</h3>
1347      * <dl>
1348      * <dt><b>Insert</b></dt>
1349      * <dd>A Contact cannot be created explicitly. When a raw contact is
1350      * inserted, the provider will first try to find a Contact representing the
1351      * same person. If one is found, the raw contact's
1352      * {@link RawContacts#CONTACT_ID} column gets the _ID of the aggregate
1353      * Contact. If no match is found, the provider automatically inserts a new
1354      * Contact and puts its _ID into the {@link RawContacts#CONTACT_ID} column
1355      * of the newly inserted raw contact.</dd>
1356      * <dt><b>Update</b></dt>
1357      * <dd>Only certain columns of Contact are modifiable:
1358      * {@link #STARRED}, {@link #CUSTOM_RINGTONE}, {@link #SEND_TO_VOICEMAIL}. Changing any of
1359      * these columns on the Contact also changes them on all constituent raw
1360      * contacts.</dd>
1361      * <dt><b>Delete</b></dt>
1362      * <dd>Be careful with deleting Contacts! Deleting an aggregate contact
1363      * deletes all constituent raw contacts. The corresponding sync adapters
1364      * will notice the deletions of their respective raw contacts and remove
1365      * them from their back end storage.</dd>
1366      * <dt><b>Query</b></dt>
1367      * <dd>
1368      * <ul>
1369      * <li>If you need to read an individual contact, consider using
1370      * {@link #CONTENT_LOOKUP_URI} instead of {@link #CONTENT_URI}.</li>
1371      * <li>If you need to look up a contact by the phone number, use
1372      * {@link PhoneLookup#CONTENT_FILTER_URI PhoneLookup.CONTENT_FILTER_URI},
1373      * which is optimized for this purpose.</li>
1374      * <li>If you need to look up a contact by partial name, e.g. to produce
1375      * filter-as-you-type suggestions, use the {@link #CONTENT_FILTER_URI} URI.
1376      * <li>If you need to look up a contact by some data element like email
1377      * address, nickname, etc, use a query against the {@link ContactsContract.Data} table.
1378      * The result will contain contact ID, name etc.
1379      * </ul>
1380      * </dd>
1381      * </dl>
1382      * <h2>Columns</h2>
1383      * <table class="jd-sumtable">
1384      * <tr>
1385      * <th colspan='4'>Contacts</th>
1386      * </tr>
1387      * <tr>
1388      * <td>long</td>
1389      * <td>{@link #_ID}</td>
1390      * <td>read-only</td>
1391      * <td>Row ID. Consider using {@link #LOOKUP_KEY} instead.</td>
1392      * </tr>
1393      * <tr>
1394      * <td>String</td>
1395      * <td>{@link #LOOKUP_KEY}</td>
1396      * <td>read-only</td>
1397      * <td>An opaque value that contains hints on how to find the contact if its
1398      * row id changed as a result of a sync or aggregation.</td>
1399      * </tr>
1400      * <tr>
1401      * <td>long</td>
1402      * <td>NAME_RAW_CONTACT_ID</td>
1403      * <td>read-only</td>
1404      * <td>The ID of the raw contact that contributes the display name
1405      * to the aggregate contact. During aggregation one of the constituent
1406      * raw contacts is chosen using a heuristic: a longer name or a name
1407      * with more diacritic marks or more upper case characters is chosen.</td>
1408      * </tr>
1409      * <tr>
1410      * <td>String</td>
1411      * <td>DISPLAY_NAME_PRIMARY</td>
1412      * <td>read-only</td>
1413      * <td>The display name for the contact. It is the display name
1414      * contributed by the raw contact referred to by the NAME_RAW_CONTACT_ID
1415      * column.</td>
1416      * </tr>
1417      * <tr>
1418      * <td>long</td>
1419      * <td>{@link #PHOTO_ID}</td>
1420      * <td>read-only</td>
1421      * <td>Reference to the row in the {@link ContactsContract.Data} table holding the photo.
1422      * That row has the mime type
1423      * {@link CommonDataKinds.Photo#CONTENT_ITEM_TYPE}. The value of this field
1424      * is computed automatically based on the
1425      * {@link CommonDataKinds.Photo#IS_SUPER_PRIMARY} field of the data rows of
1426      * that mime type.</td>
1427      * </tr>
1428      * <tr>
1429      * <td>long</td>
1430      * <td>{@link #PHOTO_URI}</td>
1431      * <td>read-only</td>
1432      * <td>A URI that can be used to retrieve the contact's full-size photo. This
1433      * column is the preferred method of retrieving the contact photo.</td>
1434      * </tr>
1435      * <tr>
1436      * <td>long</td>
1437      * <td>{@link #PHOTO_THUMBNAIL_URI}</td>
1438      * <td>read-only</td>
1439      * <td>A URI that can be used to retrieve the thumbnail of contact's photo.  This
1440      * column is the preferred method of retrieving the contact photo.</td>
1441      * </tr>
1442      * <tr>
1443      * <td>int</td>
1444      * <td>{@link #IN_VISIBLE_GROUP}</td>
1445      * <td>read-only</td>
1446      * <td>An indicator of whether this contact is supposed to be visible in the
1447      * UI. "1" if the contact has at least one raw contact that belongs to a
1448      * visible group; "0" otherwise.</td>
1449      * </tr>
1450      * <tr>
1451      * <td>int</td>
1452      * <td>{@link #HAS_PHONE_NUMBER}</td>
1453      * <td>read-only</td>
1454      * <td>An indicator of whether this contact has at least one phone number.
1455      * "1" if there is at least one phone number, "0" otherwise.</td>
1456      * </tr>
1457      * <tr>
1458      * <td>int</td>
1459      * <td>{@link #STARRED}</td>
1460      * <td>read/write</td>
1461      * <td>An indicator for favorite contacts: '1' if favorite, '0' otherwise.
1462      * When raw contacts are aggregated, this field is automatically computed:
1463      * if any constituent raw contacts are starred, then this field is set to
1464      * '1'. Setting this field automatically changes the corresponding field on
1465      * all constituent raw contacts.</td>
1466      * </tr>
1467      * <tr>
1468      * <td>String</td>
1469      * <td>{@link #CUSTOM_RINGTONE}</td>
1470      * <td>read/write</td>
1471      * <td>A custom ringtone associated with a contact. Typically this is the
1472      * URI returned by an activity launched with the
1473      * {@link android.media.RingtoneManager#ACTION_RINGTONE_PICKER} intent.</td>
1474      * </tr>
1475      * <tr>
1476      * <td>int</td>
1477      * <td>{@link #SEND_TO_VOICEMAIL}</td>
1478      * <td>read/write</td>
1479      * <td>An indicator of whether calls from this contact should be forwarded
1480      * directly to voice mail ('1') or not ('0'). When raw contacts are
1481      * aggregated, this field is automatically computed: if <i>all</i>
1482      * constituent raw contacts have SEND_TO_VOICEMAIL=1, then this field is set
1483      * to '1'. Setting this field automatically changes the corresponding field
1484      * on all constituent raw contacts.</td>
1485      * </tr>
1486      * <tr>
1487      * <td>int</td>
1488      * <td>{@link #CONTACT_PRESENCE}</td>
1489      * <td>read-only</td>
1490      * <td>Contact IM presence status. See {@link StatusUpdates} for individual
1491      * status definitions. Automatically computed as the highest presence of all
1492      * constituent raw contacts. The provider may choose not to store this value
1493      * in persistent storage. The expectation is that presence status will be
1494      * updated on a regular basis.</td>
1495      * </tr>
1496      * <tr>
1497      * <td>String</td>
1498      * <td>{@link #CONTACT_STATUS}</td>
1499      * <td>read-only</td>
1500      * <td>Contact's latest status update. Automatically computed as the latest
1501      * of all constituent raw contacts' status updates.</td>
1502      * </tr>
1503      * <tr>
1504      * <td>long</td>
1505      * <td>{@link #CONTACT_STATUS_TIMESTAMP}</td>
1506      * <td>read-only</td>
1507      * <td>The absolute time in milliseconds when the latest status was
1508      * inserted/updated.</td>
1509      * </tr>
1510      * <tr>
1511      * <td>String</td>
1512      * <td>{@link #CONTACT_STATUS_RES_PACKAGE}</td>
1513      * <td>read-only</td>
1514      * <td> The package containing resources for this status: label and icon.</td>
1515      * </tr>
1516      * <tr>
1517      * <td>long</td>
1518      * <td>{@link #CONTACT_STATUS_LABEL}</td>
1519      * <td>read-only</td>
1520      * <td>The resource ID of the label describing the source of contact status,
1521      * e.g. "Google Talk". This resource is scoped by the
1522      * {@link #CONTACT_STATUS_RES_PACKAGE}.</td>
1523      * </tr>
1524      * <tr>
1525      * <td>long</td>
1526      * <td>{@link #CONTACT_STATUS_ICON}</td>
1527      * <td>read-only</td>
1528      * <td>The resource ID of the icon for the source of contact status. This
1529      * resource is scoped by the {@link #CONTACT_STATUS_RES_PACKAGE}.</td>
1530      * </tr>
1531      * </table>
1532      */
1533     public static class Contacts implements BaseColumns, ContactsColumns,
1534             ContactOptionsColumns, ContactNameColumns, ContactStatusColumns, ContactCounts {
1535         /**
1536          * This utility class cannot be instantiated
1537          */
Contacts()1538         private Contacts()  {}
1539 
1540         /**
1541          * The content:// style URI for this table
1542          */
1543         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "contacts");
1544 
1545         /**
1546          * URI used for getting all contacts from both the calling user and the managed profile
1547          * that is linked to it.
1548          * <p>
1549          * It supports the same semantics as {@link #CONTENT_URI} and returns the same columns.<br>
1550          * If the calling user has no managed profile, it behaves in the exact same way as
1551          * {@link #CONTENT_URI}.<br>
1552          * If there is a managed profile linked to the calling user, it will return merged results
1553          * from both.
1554          * <p>
1555          * Note: this query returns the calling user results before the managed profile results,
1556          * and this order is not affected by the sorting parameter.
1557          * <p>
1558          * If a result is from the managed profile, the following changes are made to the data:
1559          * <ul>
1560          *     <li>{@link #PHOTO_THUMBNAIL_URI} and {@link #PHOTO_URI} will be rewritten to special
1561          *     URIs. Use {@link ContentResolver#openAssetFileDescriptor} or its siblings to
1562          *     load pictures from them.
1563          *     <li>{@link #PHOTO_ID} and {@link #PHOTO_FILE_ID} will be set to null. Don't use them.
1564          *     <li>{@link #_ID} and {@link #LOOKUP_KEY} will be replaced with artificial values.
1565          *     These values will be consistent across multiple queries, but do not use them in
1566          *     places that do not explicitly say they accept them. If they are used in the
1567          *     {@code selection} param in {@link android.content.ContentProvider#query}, the result
1568          *     is undefined.
1569          *     <li>In order to tell whether a contact is from the managed profile, use
1570          *     {@link ContactsContract.Contacts#isEnterpriseContactId(long)}.
1571          */
1572         public static final @NonNull Uri ENTERPRISE_CONTENT_URI = Uri.withAppendedPath(
1573                 CONTENT_URI, "enterprise");
1574 
1575         /**
1576          * Special contacts URI to refer to contacts on the managed profile from the calling user.
1577          * <p>
1578          * It's supported only by a few specific places for referring to contact pictures that
1579          * are in the managed profile provider for enterprise caller-ID. Contact picture URIs
1580          * returned from {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI} and similar APIs may
1581          * contain this kind of URI.
1582          *
1583          * @hide
1584          */
1585         @UnsupportedAppUsage
1586         public static final Uri CORP_CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
1587                 "contacts_corp");
1588 
1589         /**
1590          * A content:// style URI for this table that should be used to create
1591          * shortcuts or otherwise create long-term links to contacts. This URI
1592          * should always be followed by a "/" and the contact's {@link #LOOKUP_KEY}.
1593          * It can optionally also have a "/" and last known contact ID appended after
1594          * that. This "complete" format is an important optimization and is highly recommended.
1595          * <p>
1596          * As long as the contact's row ID remains the same, this URI is
1597          * equivalent to {@link #CONTENT_URI}. If the contact's row ID changes
1598          * as a result of a sync or aggregation, this URI will look up the
1599          * contact using indirect information (sync IDs or constituent raw
1600          * contacts).
1601          * <p>
1602          * Lookup key should be appended unencoded - it is stored in the encoded
1603          * form, ready for use in a URI.
1604          */
1605         public static final Uri CONTENT_LOOKUP_URI = Uri.withAppendedPath(CONTENT_URI,
1606                 "lookup");
1607 
1608         /**
1609          * Base {@link Uri} for referencing a single {@link Contacts} entry,
1610          * created by appending {@link #LOOKUP_KEY} using
1611          * {@link Uri#withAppendedPath(Uri, String)}. Provides
1612          * {@link OpenableColumns} columns when queried, or returns the
1613          * referenced contact formatted as a vCard when opened through
1614          * {@link ContentResolver#openAssetFileDescriptor(Uri, String)}.
1615          */
1616         public static final Uri CONTENT_VCARD_URI = Uri.withAppendedPath(CONTENT_URI,
1617                 "as_vcard");
1618 
1619        /**
1620         * Boolean parameter that may be used with {@link #CONTENT_VCARD_URI}
1621         * and {@link #CONTENT_MULTI_VCARD_URI} to indicate that the returned
1622         * vcard should not contain a photo.
1623         *
1624         * This is useful for obtaining a space efficient vcard.
1625         */
1626         public static final String QUERY_PARAMETER_VCARD_NO_PHOTO = "no_photo";
1627 
1628         /**
1629          * Base {@link Uri} for referencing multiple {@link Contacts} entry,
1630          * created by appending {@link #LOOKUP_KEY} using
1631          * {@link Uri#withAppendedPath(Uri, String)}. The lookup keys have to be
1632          * joined with the colon (":") separator, and the resulting string encoded.
1633          *
1634          * Provides {@link OpenableColumns} columns when queried, or returns the
1635          * referenced contact formatted as a vCard when opened through
1636          * {@link ContentResolver#openAssetFileDescriptor(Uri, String)}.
1637          *
1638          * <p>
1639          * Usage example:
1640          * <dl>
1641          * <dt>The following code snippet creates a multi-vcard URI that references all the
1642          * contacts in a user's database.</dt>
1643          * <dd>
1644          *
1645          * <pre>
1646          * public Uri getAllContactsVcardUri() {
1647          *     Cursor cursor = getActivity().getContentResolver().query(Contacts.CONTENT_URI,
1648          *         new String[] {Contacts.LOOKUP_KEY}, null, null, null);
1649          *     if (cursor == null) {
1650          *         return null;
1651          *     }
1652          *     try {
1653          *         StringBuilder uriListBuilder = new StringBuilder();
1654          *         int index = 0;
1655          *         while (cursor.moveToNext()) {
1656          *             if (index != 0) uriListBuilder.append(':');
1657          *             uriListBuilder.append(cursor.getString(0));
1658          *             index++;
1659          *         }
1660          *         return Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI,
1661          *                 Uri.encode(uriListBuilder.toString()));
1662          *     } finally {
1663          *         cursor.close();
1664          *     }
1665          * }
1666          * </pre>
1667          *
1668          * </p>
1669          */
1670         public static final Uri CONTENT_MULTI_VCARD_URI = Uri.withAppendedPath(CONTENT_URI,
1671                 "as_multi_vcard");
1672 
1673         /**
1674          * Builds a {@link #CONTENT_LOOKUP_URI} style {@link Uri} describing the
1675          * requested {@link Contacts} entry.
1676          *
1677          * @param contactUri A {@link #CONTENT_URI} row, or an existing
1678          *            {@link #CONTENT_LOOKUP_URI} to attempt refreshing.
1679          */
getLookupUri(ContentResolver resolver, Uri contactUri)1680         public static Uri getLookupUri(ContentResolver resolver, Uri contactUri) {
1681             final Cursor c = resolver.query(contactUri, new String[] {
1682                     Contacts.LOOKUP_KEY, Contacts._ID
1683             }, null, null, null);
1684             if (c == null) {
1685                 return null;
1686             }
1687 
1688             try {
1689                 if (c.moveToFirst()) {
1690                     final String lookupKey = c.getString(0);
1691                     final long contactId = c.getLong(1);
1692                     return getLookupUri(contactId, lookupKey);
1693                 }
1694             } finally {
1695                 c.close();
1696             }
1697             return null;
1698         }
1699 
1700         /**
1701          * Build a {@link #CONTENT_LOOKUP_URI} lookup {@link Uri} using the
1702          * given {@link ContactsContract.Contacts#_ID} and {@link #LOOKUP_KEY}.
1703          * <p>
1704          * Returns null if unable to construct a valid lookup URI from the
1705          * provided parameters.
1706          */
getLookupUri(long contactId, String lookupKey)1707         public static Uri getLookupUri(long contactId, String lookupKey) {
1708             if (TextUtils.isEmpty(lookupKey)) {
1709                 return null;
1710             }
1711             return ContentUris.withAppendedId(Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI,
1712                     lookupKey), contactId);
1713         }
1714 
1715         /**
1716          * Computes a content URI (see {@link #CONTENT_URI}) given a lookup URI.
1717          * <p>
1718          * Returns null if the contact cannot be found.
1719          */
lookupContact(ContentResolver resolver, Uri lookupUri)1720         public static Uri lookupContact(ContentResolver resolver, Uri lookupUri) {
1721             if (lookupUri == null) {
1722                 return null;
1723             }
1724 
1725             Cursor c = resolver.query(lookupUri, new String[]{Contacts._ID}, null, null, null);
1726             if (c == null) {
1727                 return null;
1728             }
1729 
1730             try {
1731                 if (c.moveToFirst()) {
1732                     long contactId = c.getLong(0);
1733                     return ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
1734                 }
1735             } finally {
1736                 c.close();
1737             }
1738             return null;
1739         }
1740 
1741         /**
1742          * Mark a contact as having been contacted. Updates two fields:
1743          * {@link #TIMES_CONTACTED} and {@link #LAST_TIME_CONTACTED}. The
1744          * TIMES_CONTACTED field is incremented by 1 and the LAST_TIME_CONTACTED
1745          * field is populated with the current system time.
1746          *
1747          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
1748          * this field is obsolete, regardless of Android version. For more information, see the
1749          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
1750          * page.</p>
1751          *
1752          * @param resolver the ContentResolver to use
1753          * @param contactId the person who was contacted
1754          *
1755          * @deprecated Contacts affinity information is no longer supported as of
1756          * Android version {@link android.os.Build.VERSION_CODES#Q}. This method
1757          * is no-op.
1758          */
1759         @Deprecated
markAsContacted(ContentResolver resolver, long contactId)1760         public static void markAsContacted(ContentResolver resolver, long contactId) {
1761         }
1762 
1763         /**
1764          * The content:// style URI used for "type-to-filter" functionality on the
1765          * {@link #CONTENT_URI} URI. The filter string will be used to match
1766          * various parts of the contact name. The filter argument should be passed
1767          * as an additional path segment after this URI.
1768          */
1769         public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(
1770                 CONTENT_URI, "filter");
1771 
1772         /**
1773          * It supports the similar semantics as {@link #CONTENT_FILTER_URI} and returns the same
1774          * columns. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in parameters,
1775          * otherwise it will throw IllegalArgumentException. The passed directory can belong either
1776          * to the calling user or to a managed profile that is linked to it.
1777          */
1778         public static final Uri ENTERPRISE_CONTENT_FILTER_URI = Uri.withAppendedPath(
1779                 CONTENT_URI, "filter_enterprise");
1780 
1781         /**
1782          * The content:// style URI for this table joined with useful data from
1783          * {@link ContactsContract.Data}, filtered to include only starred contacts.
1784          * Frequent contacts are no longer included in the result as of
1785          * Android version {@link android.os.Build.VERSION_CODES#Q}.
1786          *
1787          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
1788          * field doesn't sort results based on contacts frequency. For more information, see the
1789          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
1790          * page.
1791          */
1792         public static final Uri CONTENT_STREQUENT_URI = Uri.withAppendedPath(
1793                 CONTENT_URI, "strequent");
1794 
1795         /**
1796          * The content:// style URI for showing a list of frequently contacted people.
1797          *
1798          * @deprecated Frequent contacts are no longer supported as of
1799          * Android version {@link android.os.Build.VERSION_CODES#Q}.
1800          * This URI always returns an empty cursor.
1801          *
1802          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
1803          * field doesn't sort results based on contacts frequency. For more information, see the
1804          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
1805          * page.
1806          */
1807         @Deprecated
1808         public static final Uri CONTENT_FREQUENT_URI = Uri.withAppendedPath(
1809                 CONTENT_URI, "frequent");
1810 
1811         /**
1812          * <p>The content:// style URI used for "type-to-filter" functionality on the
1813          * {@link #CONTENT_STREQUENT_URI} URI. The filter string will be used to match
1814          * various parts of the contact name. The filter argument should be passed
1815          * as an additional path segment after this URI.
1816          *
1817          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
1818          * field doesn't sort results based on contacts frequency. For more information, see the
1819          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
1820          * page.
1821          */
1822         public static final Uri CONTENT_STREQUENT_FILTER_URI = Uri.withAppendedPath(
1823                 CONTENT_STREQUENT_URI, "filter");
1824 
1825         public static final Uri CONTENT_GROUP_URI = Uri.withAppendedPath(
1826                 CONTENT_URI, "group");
1827 
1828         /**
1829          * The MIME type of {@link #CONTENT_URI} providing a directory of
1830          * people.
1831          */
1832         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact";
1833 
1834         /**
1835          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
1836          * person.
1837          */
1838         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact";
1839 
1840         /**
1841          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
1842          * person.
1843          */
1844         public static final String CONTENT_VCARD_TYPE = "text/x-vcard";
1845 
1846         /**
1847          * Mimimal ID for managed profile contacts returned from
1848          * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI} and similar APIs
1849          *
1850          * @hide
1851          */
1852         public static long ENTERPRISE_CONTACT_ID_BASE = 1000000000; // slightly smaller than 2 ** 30
1853 
1854         /**
1855          * Prefix for managed profile contacts returned from
1856          * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI} and similar APIs.
1857          *
1858          * @hide
1859          */
1860         public static String ENTERPRISE_CONTACT_LOOKUP_PREFIX = "c-";
1861 
1862         /**
1863          * Return {@code true} if a contact ID is from the contacts provider on the managed profile.
1864          *
1865          * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI} and similar APIs may return such IDs.
1866          */
isEnterpriseContactId(long contactId)1867         public static boolean isEnterpriseContactId(long contactId) {
1868             return (contactId >= ENTERPRISE_CONTACT_ID_BASE) && (contactId < Profile.MIN_ID);
1869         }
1870 
1871         /**
1872          * A sub-directory of a single contact that contains all of the constituent raw contact
1873          * {@link ContactsContract.Data} rows.  This directory can be used either
1874          * with a {@link #CONTENT_URI} or {@link #CONTENT_LOOKUP_URI}.
1875          */
1876         public static final class Data implements BaseColumns, DataColumns {
1877             /**
1878              * no public constructor since this is a utility class
1879              */
Data()1880             private Data() {}
1881 
1882             /**
1883              * The directory twig for this sub-table
1884              */
1885             public static final String CONTENT_DIRECTORY = "data";
1886         }
1887 
1888         /**
1889          * <p>
1890          * A sub-directory of a contact that contains all of its
1891          * {@link ContactsContract.RawContacts} as well as
1892          * {@link ContactsContract.Data} rows. To access this directory append
1893          * {@link #CONTENT_DIRECTORY} to the contact URI.
1894          * </p>
1895          * <p>
1896          * Entity has three ID fields: {@link #CONTACT_ID} for the contact,
1897          * {@link #RAW_CONTACT_ID} for the raw contact and {@link #DATA_ID} for
1898          * the data rows. Entity always contains at least one row per
1899          * constituent raw contact, even if there are no actual data rows. In
1900          * this case the {@link #DATA_ID} field will be null.
1901          * </p>
1902          * <p>
1903          * Entity reads all data for the entire contact in one transaction, to
1904          * guarantee consistency.  There is significant data duplication
1905          * in the Entity (each row repeats all Contact columns and all RawContact
1906          * columns), so the benefits of transactional consistency should be weighed
1907          * against the cost of transferring large amounts of denormalized data
1908          * from the Provider.
1909          * </p>
1910          * <p>
1911          * To reduce the amount of data duplication the contacts provider and directory
1912          * providers implementing this protocol are allowed to provide common Contacts
1913          * and RawContacts fields in the first row returned for each raw contact only and
1914          * leave them as null in subsequent rows.
1915          * </p>
1916          */
1917         public static final class Entity implements BaseColumns, ContactsColumns,
1918                 ContactNameColumns, RawContactsColumns, BaseSyncColumns, SyncColumns, DataColumns,
1919                 StatusColumns, ContactOptionsColumns, ContactStatusColumns, DataUsageStatColumns {
1920             /**
1921              * no public constructor since this is a utility class
1922              */
Entity()1923             private Entity() {
1924             }
1925 
1926             /**
1927              * The directory twig for this sub-table
1928              */
1929             public static final String CONTENT_DIRECTORY = "entities";
1930 
1931             /**
1932              * The ID of the raw contact row.
1933              * <P>Type: INTEGER</P>
1934              */
1935             public static final String RAW_CONTACT_ID = "raw_contact_id";
1936 
1937             /**
1938              * The ID of the data row. The value will be null if this raw contact has no
1939              * data rows.
1940              * <P>Type: INTEGER</P>
1941              */
1942             public static final String DATA_ID = "data_id";
1943         }
1944 
1945         /**
1946          * <p>
1947          * A sub-directory of a single contact that contains all of the constituent raw contact
1948          * {@link ContactsContract.StreamItems} rows.  This directory can be used either
1949          * with a {@link #CONTENT_URI} or {@link #CONTENT_LOOKUP_URI}.
1950          * </p>
1951          * <p>
1952          * Querying for social stream data requires android.permission.READ_SOCIAL_STREAM
1953          * permission.
1954          * </p>
1955          *
1956          * @deprecated - Do not use. This will not be supported in the future. In the future,
1957          * cursors returned from related queries will be empty.
1958          *
1959          * @removed
1960          */
1961         @Deprecated
1962         public static final class StreamItems implements StreamItemsColumns {
1963             /**
1964              * no public constructor since this is a utility class
1965              *
1966              * @deprecated - Do not use. This will not be supported in the future. In the future,
1967              * cursors returned from related queries will be empty.
1968              */
1969             @Deprecated
StreamItems()1970             private StreamItems() {}
1971 
1972             /**
1973              * The directory twig for this sub-table
1974              *
1975              * @deprecated - Do not use. This will not be supported in the future. In the future,
1976              * cursors returned from related queries will be empty.
1977              */
1978             @Deprecated
1979             public static final String CONTENT_DIRECTORY = "stream_items";
1980         }
1981 
1982         /**
1983          * <p>
1984          * A <i>read-only</i> sub-directory of a single contact aggregate that
1985          * contains all aggregation suggestions (other contacts). The
1986          * aggregation suggestions are computed based on approximate data
1987          * matches with this contact.
1988          * </p>
1989          * <p>
1990          * <i>Note: this query may be expensive! If you need to use it in bulk,
1991          * make sure the user experience is acceptable when the query runs for a
1992          * long time.</i>
1993          * <p>
1994          * Usage example:
1995          *
1996          * <pre>
1997          * Uri uri = Contacts.CONTENT_URI.buildUpon()
1998          *          .appendEncodedPath(String.valueOf(contactId))
1999          *          .appendPath(Contacts.AggregationSuggestions.CONTENT_DIRECTORY)
2000          *          .appendQueryParameter(&quot;limit&quot;, &quot;3&quot;)
2001          *          .build()
2002          * Cursor cursor = getContentResolver().query(suggestionsUri,
2003          *          new String[] {Contacts.DISPLAY_NAME, Contacts._ID, Contacts.LOOKUP_KEY},
2004          *          null, null, null);
2005          * </pre>
2006          *
2007          * </p>
2008          * <p>
2009          * This directory can be used either with a {@link #CONTENT_URI} or
2010          * {@link #CONTENT_LOOKUP_URI}.
2011          * </p>
2012          */
2013         public static final class AggregationSuggestions implements BaseColumns, ContactsColumns,
2014                 ContactOptionsColumns, ContactStatusColumns {
2015             /**
2016              * No public constructor since this is a utility class
2017              */
AggregationSuggestions()2018             private AggregationSuggestions() {}
2019 
2020             /**
2021              * The directory twig for this sub-table. The URI can be followed by an optional
2022              * type-to-filter, similar to
2023              * {@link android.provider.ContactsContract.Contacts#CONTENT_FILTER_URI}.
2024              */
2025             public static final String CONTENT_DIRECTORY = "suggestions";
2026 
2027             /**
2028              * Used to specify what kind of data is supplied for the suggestion query.
2029              *
2030              * @hide
2031              */
2032             public static final String PARAMETER_MATCH_NAME = "name";
2033 
2034             /**
2035              * A convenience builder for aggregation suggestion content URIs.
2036              */
2037             public static final class Builder {
2038                 private long mContactId;
2039                 private final ArrayList<String> mValues = new ArrayList<String>();
2040                 private int mLimit;
2041 
2042                 /**
2043                  * Optional existing contact ID.  If it is not provided, the search
2044                  * will be based exclusively on the values supplied with {@link #addNameParameter}.
2045                  *
2046                  * @param contactId contact to find aggregation suggestions for
2047                  * @return This Builder object to allow for chaining of calls to builder methods
2048                  */
setContactId(long contactId)2049                 public Builder setContactId(long contactId) {
2050                     this.mContactId = contactId;
2051                     return this;
2052                 }
2053 
2054                 /**
2055                  * Add a name to be used when searching for aggregation suggestions.
2056                  *
2057                  * @param name name to find aggregation suggestions for
2058                  * @return This Builder object to allow for chaining of calls to builder methods
2059                  */
addNameParameter(String name)2060                 public Builder addNameParameter(String name) {
2061                     mValues.add(name);
2062                     return this;
2063                 }
2064 
2065                 /**
2066                  * Sets the Maximum number of suggested aggregations that should be returned.
2067                  * @param limit The maximum number of suggested aggregations
2068                  *
2069                  * @return This Builder object to allow for chaining of calls to builder methods
2070                  */
setLimit(int limit)2071                 public Builder setLimit(int limit) {
2072                     mLimit = limit;
2073                     return this;
2074                 }
2075 
2076                 /**
2077                  * Combine all of the options that have been set and return a new {@link Uri}
2078                  * object for fetching aggregation suggestions.
2079                  */
build()2080                 public Uri build() {
2081                     android.net.Uri.Builder builder = Contacts.CONTENT_URI.buildUpon();
2082                     builder.appendEncodedPath(String.valueOf(mContactId));
2083                     builder.appendPath(Contacts.AggregationSuggestions.CONTENT_DIRECTORY);
2084                     if (mLimit != 0) {
2085                         builder.appendQueryParameter("limit", String.valueOf(mLimit));
2086                     }
2087 
2088                     int count = mValues.size();
2089                     for (int i = 0; i < count; i++) {
2090                         builder.appendQueryParameter("query", PARAMETER_MATCH_NAME
2091                                 + ":" + mValues.get(i));
2092                     }
2093 
2094                     return builder.build();
2095                 }
2096             }
2097 
2098             /**
2099              * @hide
2100              */
2101             @UnsupportedAppUsage
builder()2102             public static final Builder builder() {
2103                 return new Builder();
2104             }
2105         }
2106 
2107         /**
2108          * A <i>read-only</i> sub-directory of a single contact that contains
2109          * the contact's primary photo.  The photo may be stored in up to two ways -
2110          * the default "photo" is a thumbnail-sized image stored directly in the data
2111          * row, while the "display photo", if present, is a larger version stored as
2112          * a file.
2113          * <p>
2114          * Usage example:
2115          * <dl>
2116          * <dt>Retrieving the thumbnail-sized photo</dt>
2117          * <dd>
2118          * <pre>
2119          * public InputStream openPhoto(long contactId) {
2120          *     Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
2121          *     Uri photoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.CONTENT_DIRECTORY);
2122          *     Cursor cursor = getContentResolver().query(photoUri,
2123          *          new String[] {Contacts.Photo.PHOTO}, null, null, null);
2124          *     if (cursor == null) {
2125          *         return null;
2126          *     }
2127          *     try {
2128          *         if (cursor.moveToFirst()) {
2129          *             byte[] data = cursor.getBlob(0);
2130          *             if (data != null) {
2131          *                 return new ByteArrayInputStream(data);
2132          *             }
2133          *         }
2134          *     } finally {
2135          *         cursor.close();
2136          *     }
2137          *     return null;
2138          * }
2139          * </pre>
2140          * </dd>
2141          * <dt>Retrieving the larger photo version</dt>
2142          * <dd>
2143          * <pre>
2144          * public InputStream openDisplayPhoto(long contactId) {
2145          *     Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
2146          *     Uri displayPhotoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.DISPLAY_PHOTO);
2147          *     try {
2148          *         AssetFileDescriptor fd =
2149          *             getContentResolver().openAssetFileDescriptor(displayPhotoUri, "r");
2150          *         return fd.createInputStream();
2151          *     } catch (IOException e) {
2152          *         return null;
2153          *     }
2154          * }
2155          * </pre>
2156          * </dd>
2157          * </dl>
2158          *
2159          * </p>
2160          * <p>You may also consider using the convenience method
2161          * {@link ContactsContract.Contacts#openContactPhotoInputStream(ContentResolver, Uri, boolean)}
2162          * to retrieve the raw photo contents of either the thumbnail-sized or the full-sized photo.
2163          * </p>
2164          * <p>
2165          * This directory can be used either with a {@link #CONTENT_URI} or
2166          * {@link #CONTENT_LOOKUP_URI}.
2167          * </p>
2168          */
2169         public static final class Photo implements BaseColumns, DataColumnsWithJoins {
2170             /**
2171              * no public constructor since this is a utility class
2172              */
Photo()2173             private Photo() {}
2174 
2175             /**
2176              * The directory twig for this sub-table
2177              */
2178             public static final String CONTENT_DIRECTORY = "photo";
2179 
2180             /**
2181              * The directory twig for retrieving the full-size display photo.
2182              */
2183             public static final String DISPLAY_PHOTO = "display_photo";
2184 
2185             /**
2186              * Full-size photo file ID of the raw contact.
2187              * See {@link ContactsContract.DisplayPhoto}.
2188              * <p>
2189              * Type: NUMBER
2190              */
2191             public static final String PHOTO_FILE_ID = DATA14;
2192 
2193             /**
2194              * Thumbnail photo of the raw contact. This is the raw bytes of an image
2195              * that could be inflated using {@link android.graphics.BitmapFactory}.
2196              * <p>
2197              * Type: BLOB
2198              */
2199             public static final String PHOTO = DATA15;
2200         }
2201 
2202         /**
2203          * Opens an InputStream for the contacts's photo and returns the
2204          * photo as a byte stream.
2205          * @param cr The content resolver to use for querying
2206          * @param contactUri the contact whose photo should be used. This can be used with
2207          * either a {@link #CONTENT_URI} or a {@link #CONTENT_LOOKUP_URI} URI.
2208          * @param preferHighres If this is true and the contact has a higher resolution photo
2209          * available, it is returned. If false, this function always tries to get the thumbnail
2210          * @return an InputStream of the photo, or null if no photo is present
2211          */
openContactPhotoInputStream(ContentResolver cr, Uri contactUri, boolean preferHighres)2212         public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri,
2213                 boolean preferHighres) {
2214             if (preferHighres) {
2215                 final Uri displayPhotoUri = Uri.withAppendedPath(contactUri,
2216                         Contacts.Photo.DISPLAY_PHOTO);
2217                 try {
2218                     AssetFileDescriptor fd = cr.openAssetFileDescriptor(displayPhotoUri, "r");
2219                     if (fd != null) {
2220                         return fd.createInputStream();
2221                     }
2222                 } catch (IOException e) {
2223                     // fallback to the thumbnail code
2224                 }
2225            }
2226 
2227             Uri photoUri = Uri.withAppendedPath(contactUri, Photo.CONTENT_DIRECTORY);
2228             if (photoUri == null) {
2229                 return null;
2230             }
2231             Cursor cursor = cr.query(photoUri,
2232                     new String[] {
2233                         ContactsContract.CommonDataKinds.Photo.PHOTO
2234                     }, null, null, null);
2235             try {
2236                 if (cursor == null || !cursor.moveToNext()) {
2237                     return null;
2238                 }
2239                 byte[] data = cursor.getBlob(0);
2240                 if (data == null) {
2241                     return null;
2242                 }
2243                 return new ByteArrayInputStream(data);
2244             } finally {
2245                 if (cursor != null) {
2246                     cursor.close();
2247                 }
2248             }
2249         }
2250 
2251         /**
2252          * Opens an InputStream for the contacts's thumbnail photo and returns the
2253          * photo as a byte stream.
2254          * @param cr The content resolver to use for querying
2255          * @param contactUri the contact whose photo should be used. This can be used with
2256          * either a {@link #CONTENT_URI} or a {@link #CONTENT_LOOKUP_URI} URI.
2257          * @return an InputStream of the photo, or null if no photo is present
2258          * @see #openContactPhotoInputStream(ContentResolver, Uri, boolean), if instead
2259          * of the thumbnail the high-res picture is preferred
2260          */
openContactPhotoInputStream(ContentResolver cr, Uri contactUri)2261         public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri) {
2262             return openContactPhotoInputStream(cr, contactUri, false);
2263         }
2264 
2265         /**
2266          * Creates and returns a corp lookup URI from the given enterprise lookup URI by removing
2267          * {@link #ENTERPRISE_CONTACT_LOOKUP_PREFIX} from the key. Returns {@code null} if the given
2268          * URI is not an enterprise lookup URI.
2269          *
2270          * @hide
2271          */
2272         @Nullable
createCorpLookupUriFromEnterpriseLookupUri( @onNull Uri enterpriseLookupUri)2273         public static Uri createCorpLookupUriFromEnterpriseLookupUri(
2274                 @NonNull Uri enterpriseLookupUri) {
2275             final List<String> pathSegments = enterpriseLookupUri.getPathSegments();
2276             if (pathSegments == null || pathSegments.size() <= 2) {
2277                 return null;
2278             }
2279             final String key = pathSegments.get(2);
2280             if (TextUtils.isEmpty(key) || !key.startsWith(ENTERPRISE_CONTACT_LOOKUP_PREFIX)) {
2281                 return null;
2282             }
2283             final String actualKey = key.substring(ENTERPRISE_CONTACT_LOOKUP_PREFIX.length());
2284             return Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, actualKey);
2285         }
2286     }
2287 
2288     /**
2289      * <p>
2290      * Constants for the user's profile data, which is represented as a single contact on
2291      * the device that represents the user.  The profile contact is not aggregated
2292      * together automatically in the same way that normal contacts are; instead, each
2293      * account (including data set, if applicable) on the device may contribute a single
2294      * raw contact representing the user's personal profile data from that source.
2295      * </p>
2296      * <p>
2297      * Access to the profile entry through these URIs (or incidental access to parts of
2298      * the profile if retrieved directly via ID) requires additional permissions beyond
2299      * the read/write contact permissions required by the provider.  Querying for profile
2300      * data requires android.permission.READ_PROFILE permission, and inserting or
2301      * updating profile data requires android.permission.WRITE_PROFILE permission.
2302      * </p>
2303      * <h3>Operations</h3>
2304      * <dl>
2305      * <dt><b>Insert</b></dt>
2306      * <dd>The user's profile entry cannot be created explicitly (attempting to do so
2307      * will throw an exception). When a raw contact is inserted into the profile, the
2308      * provider will check for the existence of a profile on the device.  If one is
2309      * found, the raw contact's {@link RawContacts#CONTACT_ID} column gets the _ID of
2310      * the profile Contact. If no match is found, the profile Contact is created and
2311      * its _ID is put into the {@link RawContacts#CONTACT_ID} column of the newly
2312      * inserted raw contact.</dd>
2313      * <dt><b>Update</b></dt>
2314      * <dd>The profile Contact has the same update restrictions as Contacts in general,
2315      * but requires the android.permission.WRITE_PROFILE permission.</dd>
2316      * <dt><b>Delete</b></dt>
2317      * <dd>The profile Contact cannot be explicitly deleted.  It will be removed
2318      * automatically if all of its constituent raw contact entries are deleted.</dd>
2319      * <dt><b>Query</b></dt>
2320      * <dd>
2321      * <ul>
2322      * <li>The {@link #CONTENT_URI} for profiles behaves in much the same way as
2323      * retrieving a contact by ID, except that it will only ever return the user's
2324      * profile contact.
2325      * </li>
2326      * <li>
2327      * The profile contact supports all of the same sub-paths as an individual contact
2328      * does - the content of the profile contact can be retrieved as entities or
2329      * data rows.  Similarly, specific raw contact entries can be retrieved by appending
2330      * the desired raw contact ID within the profile.
2331      * </li>
2332      * </ul>
2333      * </dd>
2334      * </dl>
2335      */
2336     public static final class Profile implements BaseColumns, ContactsColumns,
2337             ContactOptionsColumns, ContactNameColumns, ContactStatusColumns {
2338         /**
2339          * This utility class cannot be instantiated
2340          */
Profile()2341         private Profile() {
2342         }
2343 
2344         /**
2345          * The content:// style URI for this table, which requests the contact entry
2346          * representing the user's personal profile data.
2347          */
2348         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "profile");
2349 
2350         /**
2351          * {@link Uri} for referencing the user's profile {@link Contacts} entry,
2352          * Provides {@link OpenableColumns} columns when queried, or returns the
2353          * user's profile contact formatted as a vCard when opened through
2354          * {@link ContentResolver#openAssetFileDescriptor(Uri, String)}.
2355          */
2356         public static final Uri CONTENT_VCARD_URI = Uri.withAppendedPath(CONTENT_URI,
2357                 "as_vcard");
2358 
2359         /**
2360          * {@link Uri} for referencing the raw contacts that make up the user's profile
2361          * {@link Contacts} entry.  An individual raw contact entry within the profile
2362          * can be addressed by appending the raw contact ID.  The entities or data within
2363          * that specific raw contact can be requested by appending the entity or data
2364          * path as well.
2365          */
2366         public static final Uri CONTENT_RAW_CONTACTS_URI = Uri.withAppendedPath(CONTENT_URI,
2367                 "raw_contacts");
2368 
2369         /**
2370          * The minimum ID for any entity that belongs to the profile.  This essentially
2371          * defines an ID-space in which profile data is stored, and is used by the provider
2372          * to determine whether a request via a non-profile-specific URI should be directed
2373          * to the profile data rather than general contacts data, along with all the special
2374          * permission checks that entails.
2375          *
2376          * Callers may use {@link #isProfileId} to check whether a specific ID falls into
2377          * the set of data intended for the profile.
2378          */
2379         public static final long MIN_ID = Long.MAX_VALUE - (long) Integer.MAX_VALUE;
2380     }
2381 
2382     /**
2383      * This method can be used to identify whether the given ID is associated with profile
2384      * data.  It does not necessarily indicate that the ID is tied to valid data, merely
2385      * that accessing data using this ID will result in profile access checks and will only
2386      * return data from the profile.
2387      *
2388      * @param id The ID to check.
2389      * @return Whether the ID is associated with profile data.
2390      */
isProfileId(long id)2391     public static boolean isProfileId(long id) {
2392         return id >= Profile.MIN_ID;
2393     }
2394 
2395     protected interface DeletedContactsColumns {
2396 
2397         /**
2398          * A reference to the {@link ContactsContract.Contacts#_ID} that was deleted.
2399          * <P>Type: INTEGER</P>
2400          */
2401         public static final String CONTACT_ID = "contact_id";
2402 
2403         /**
2404          * Time (milliseconds since epoch) that the contact was deleted.
2405          */
2406         public static final String CONTACT_DELETED_TIMESTAMP = "contact_deleted_timestamp";
2407     }
2408 
2409     /**
2410      * Constants for the deleted contact table.  This table holds a log of deleted contacts.
2411      * <p>
2412      * Log older than {@link #DAYS_KEPT_MILLISECONDS} may be deleted.
2413      */
2414     public static final class DeletedContacts implements DeletedContactsColumns {
2415 
2416         /**
2417          * This utility class cannot be instantiated
2418          */
DeletedContacts()2419         private DeletedContacts() {
2420         }
2421 
2422         /**
2423          * The content:// style URI for this table, which requests a directory of raw contact rows
2424          * matching the selection criteria.
2425          */
2426         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
2427                 "deleted_contacts");
2428 
2429         /**
2430          * Number of days that the delete log will be kept.  After this time, delete records may be
2431          * deleted.
2432          *
2433          * @hide
2434          */
2435         private static final int DAYS_KEPT = 30;
2436 
2437         /**
2438          * Milliseconds that the delete log will be kept.  After this time, delete records may be
2439          * deleted.
2440          */
2441         public static final long DAYS_KEPT_MILLISECONDS = 1000L * 60L * 60L * 24L * (long)DAYS_KEPT;
2442     }
2443 
2444     protected interface RawContactsColumns {
2445         /**
2446          * A reference to the {@link ContactsContract.Contacts#_ID} that this
2447          * data belongs to.
2448          * <P>Type: INTEGER</P>
2449          */
2450         public static final String CONTACT_ID = "contact_id";
2451 
2452         /**
2453          * Persistent unique id for each raw_contact within its account.
2454          * This id is provided by its own data source, and can be used to backup metadata
2455          * to the server.
2456          * This should be unique within each set of account_name/account_type/data_set
2457          */
2458         public static final String BACKUP_ID = "backup_id";
2459 
2460         /**
2461          * The data set within the account that this row belongs to.  This allows
2462          * multiple sync adapters for the same account type to distinguish between
2463          * each others' data.
2464          *
2465          * This is empty by default, and is completely optional.  It only needs to
2466          * be populated if multiple sync adapters are entering distinct data for
2467          * the same account type and account name.
2468          * <P>Type: TEXT</P>
2469          */
2470         public static final String DATA_SET = "data_set";
2471 
2472         /**
2473          * A concatenation of the account type and data set (delimited by a forward
2474          * slash) - if the data set is empty, this will be the same as the account
2475          * type.  For applications that need to be aware of the data set, this can
2476          * be used instead of account type to distinguish sets of data.  This is
2477          * never intended to be used for specifying accounts.
2478          * <p>
2479          * This column does *not* escape forward slashes in the account type or the data set.
2480          * If this is an issue, consider using
2481          * {@link ContactsContract.RawContacts#ACCOUNT_TYPE} and
2482          * {@link ContactsContract.RawContacts#DATA_SET} directly.
2483          */
2484         public static final String ACCOUNT_TYPE_AND_DATA_SET = "account_type_and_data_set";
2485 
2486         /**
2487          * The aggregation mode for this contact.
2488          * <P>Type: INTEGER</P>
2489          */
2490         public static final String AGGREGATION_MODE = "aggregation_mode";
2491 
2492         /**
2493          * The "deleted" flag: "0" by default, "1" if the row has been marked
2494          * for deletion. When {@link android.content.ContentResolver#delete} is
2495          * called on a raw contact, it is marked for deletion and removed from its
2496          * aggregate contact. The sync adaptor deletes the raw contact on the server and
2497          * then calls ContactResolver.delete once more, this time passing the
2498          * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to finalize
2499          * the data removal.
2500          * <P>Type: INTEGER</P>
2501          */
2502         public static final String DELETED = "deleted";
2503 
2504         /**
2505          * The "read-only" flag: "0" by default, "1" if the row cannot be modified or
2506          * deleted except by a sync adapter.  See {@link ContactsContract#CALLER_IS_SYNCADAPTER}.
2507          * <P>Type: INTEGER</P>
2508          */
2509         public static final String RAW_CONTACT_IS_READ_ONLY = "raw_contact_is_read_only";
2510 
2511         /**
2512          * Flag that reflects whether this raw contact belongs to the user's
2513          * personal profile entry.
2514          */
2515         public static final String RAW_CONTACT_IS_USER_PROFILE = "raw_contact_is_user_profile";
2516 
2517         /**
2518          * Flag indicating that a raw contact's metadata has changed, and its metadata
2519          * needs to be synchronized by the server.
2520          * <P>Type: INTEGER (boolean)</P>
2521          *
2522          * @deprecated This column never actually worked since added. It will not supported as
2523          * of Android version {@link android.os.Build.VERSION_CODES#R}.
2524          */
2525         @Deprecated
2526         public static final String METADATA_DIRTY = "metadata_dirty";
2527     }
2528 
2529     /**
2530      * Constants for the raw contacts table, which contains one row of contact
2531      * information for each person in each synced account. Sync adapters and
2532      * contact management apps
2533      * are the primary consumers of this API.
2534      *
2535      * <h3>Aggregation</h3>
2536      * <p>
2537      * As soon as a raw contact is inserted or whenever its constituent data
2538      * changes, the provider will check if the raw contact matches other
2539      * existing raw contacts and if so will aggregate it with those. The
2540      * aggregation is reflected in the {@link RawContacts} table by the change of the
2541      * {@link #CONTACT_ID} field, which is the reference to the aggregate contact.
2542      * </p>
2543      * <p>
2544      * Changes to the structured name, organization, phone number, email address,
2545      * or nickname trigger a re-aggregation.
2546      * </p>
2547      * <p>
2548      * See also {@link AggregationExceptions} for a mechanism to control
2549      * aggregation programmatically.
2550      * </p>
2551      *
2552      * <h3>Operations</h3>
2553      * <dl>
2554      * <dt><b>Insert</b></dt>
2555      * <dd>
2556      * <p>
2557      * Raw contacts can be inserted incrementally or in a batch.
2558      * The incremental method is more traditional but less efficient.
2559      * It should be used
2560      * only if no {@link Data} values are available at the time the raw contact is created:
2561      * <pre>
2562      * ContentValues values = new ContentValues();
2563      * values.put(RawContacts.ACCOUNT_TYPE, accountType);
2564      * values.put(RawContacts.ACCOUNT_NAME, accountName);
2565      * Uri rawContactUri = getContentResolver().insert(RawContacts.CONTENT_URI, values);
2566      * long rawContactId = ContentUris.parseId(rawContactUri);
2567      * </pre>
2568      * </p>
2569      * <p>
2570      * Once {@link Data} values become available, insert those.
2571      * For example, here's how you would insert a name:
2572      *
2573      * <pre>
2574      * values.clear();
2575      * values.put(Data.RAW_CONTACT_ID, rawContactId);
2576      * values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
2577      * values.put(StructuredName.DISPLAY_NAME, &quot;Mike Sullivan&quot;);
2578      * getContentResolver().insert(Data.CONTENT_URI, values);
2579      * </pre>
2580      * </p>
2581      * <p>
2582      * The batch method is by far preferred.  It inserts the raw contact and its
2583      * constituent data rows in a single database transaction
2584      * and causes at most one aggregation pass.
2585      * <pre>
2586      * ArrayList&lt;ContentProviderOperation&gt; ops =
2587      *          new ArrayList&lt;ContentProviderOperation&gt;();
2588      * ...
2589      * int rawContactInsertIndex = ops.size();
2590      * ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
2591      *          .withValue(RawContacts.ACCOUNT_TYPE, accountType)
2592      *          .withValue(RawContacts.ACCOUNT_NAME, accountName)
2593      *          .build());
2594      *
2595      * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
2596      *          .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
2597      *          .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
2598      *          .withValue(StructuredName.DISPLAY_NAME, &quot;Mike Sullivan&quot;)
2599      *          .build());
2600      *
2601      * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
2602      * </pre>
2603      * </p>
2604      * <p>
2605      * Note the use of {@link ContentProviderOperation.Builder#withValueBackReference(String, int)}
2606      * to refer to the as-yet-unknown index value of the raw contact inserted in the
2607      * first operation.
2608      * </p>
2609      *
2610      * <dt><b>Update</b></dt>
2611      * <dd><p>
2612      * Raw contacts can be updated incrementally or in a batch.
2613      * Batch mode should be used whenever possible.
2614      * The procedures and considerations are analogous to those documented above for inserts.
2615      * </p></dd>
2616      * <dt><b>Delete</b></dt>
2617      * <dd><p>When a raw contact is deleted, all of its Data rows as well as StatusUpdates,
2618      * AggregationExceptions, PhoneLookup rows are deleted automatically. When all raw
2619      * contacts associated with a {@link Contacts} row are deleted, the {@link Contacts} row
2620      * itself is also deleted automatically.
2621      * </p>
2622      * <p>
2623      * The invocation of {@code resolver.delete(...)}, does not immediately delete
2624      * a raw contacts row.
2625      * Instead, it sets the {@link #DELETED} flag on the raw contact and
2626      * removes the raw contact from its aggregate contact.
2627      * The sync adapter then deletes the raw contact from the server and
2628      * finalizes phone-side deletion by calling {@code resolver.delete(...)}
2629      * again and passing the {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter.<p>
2630      * <p>Some sync adapters are read-only, meaning that they only sync server-side
2631      * changes to the phone, but not the reverse.  If one of those raw contacts
2632      * is marked for deletion, it will remain on the phone.  However it will be
2633      * effectively invisible, because it will not be part of any aggregate contact.
2634      * </dd>
2635      *
2636      * <dt><b>Query</b></dt>
2637      * <dd>
2638      * <p>
2639      * It is easy to find all raw contacts in a Contact:
2640      * <pre>
2641      * Cursor c = getContentResolver().query(RawContacts.CONTENT_URI,
2642      *          new String[]{RawContacts._ID},
2643      *          RawContacts.CONTACT_ID + "=?",
2644      *          new String[]{String.valueOf(contactId)}, null);
2645      * </pre>
2646      * </p>
2647      * <p>
2648      * To find raw contacts within a specific account,
2649      * you can either put the account name and type in the selection or pass them as query
2650      * parameters.  The latter approach is preferable, especially when you can reuse the
2651      * URI:
2652      * <pre>
2653      * Uri rawContactUri = RawContacts.CONTENT_URI.buildUpon()
2654      *          .appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName)
2655      *          .appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType)
2656      *          .build();
2657      * Cursor c1 = getContentResolver().query(rawContactUri,
2658      *          RawContacts.STARRED + "&lt;&gt;0", null, null, null);
2659      * ...
2660      * Cursor c2 = getContentResolver().query(rawContactUri,
2661      *          RawContacts.DELETED + "&lt;&gt;0", null, null, null);
2662      * </pre>
2663      * </p>
2664      * <p>The best way to read a raw contact along with all the data associated with it is
2665      * by using the {@link Entity} directory. If the raw contact has data rows,
2666      * the Entity cursor will contain a row for each data row.  If the raw contact has no
2667      * data rows, the cursor will still contain one row with the raw contact-level information.
2668      * <pre>
2669      * Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
2670      * Uri entityUri = Uri.withAppendedPath(rawContactUri, Entity.CONTENT_DIRECTORY);
2671      * Cursor c = getContentResolver().query(entityUri,
2672      *          new String[]{RawContacts.SOURCE_ID, Entity.DATA_ID, Entity.MIMETYPE, Entity.DATA1},
2673      *          null, null, null);
2674      * try {
2675      *     while (c.moveToNext()) {
2676      *         String sourceId = c.getString(0);
2677      *         if (!c.isNull(1)) {
2678      *             String mimeType = c.getString(2);
2679      *             String data = c.getString(3);
2680      *             ...
2681      *         }
2682      *     }
2683      * } finally {
2684      *     c.close();
2685      * }
2686      * </pre>
2687      * </p>
2688      * </dd>
2689      * </dl>
2690      * <h2>Columns</h2>
2691      *
2692      * <table class="jd-sumtable">
2693      * <tr>
2694      * <th colspan='4'>RawContacts</th>
2695      * </tr>
2696      * <tr>
2697      * <td>long</td>
2698      * <td>{@link #_ID}</td>
2699      * <td>read-only</td>
2700      * <td>Row ID. Sync adapters should try to preserve row IDs during updates. In other words,
2701      * it is much better for a sync adapter to update a raw contact rather than to delete and
2702      * re-insert it.</td>
2703      * </tr>
2704      * <tr>
2705      * <td>long</td>
2706      * <td>{@link #CONTACT_ID}</td>
2707      * <td>read-only</td>
2708      * <td>The ID of the row in the {@link ContactsContract.Contacts} table
2709      * that this raw contact belongs
2710      * to. Raw contacts are linked to contacts by the aggregation process, which can be controlled
2711      * by the {@link #AGGREGATION_MODE} field and {@link AggregationExceptions}.</td>
2712      * </tr>
2713      * <tr>
2714      * <td>int</td>
2715      * <td>{@link #AGGREGATION_MODE}</td>
2716      * <td>read/write</td>
2717      * <td>A mechanism that allows programmatic control of the aggregation process. The allowed
2718      * values are {@link #AGGREGATION_MODE_DEFAULT}, {@link #AGGREGATION_MODE_DISABLED}
2719      * and {@link #AGGREGATION_MODE_SUSPENDED}. See also {@link AggregationExceptions}.</td>
2720      * </tr>
2721      * <tr>
2722      * <td>int</td>
2723      * <td>{@link #DELETED}</td>
2724      * <td>read/write</td>
2725      * <td>The "deleted" flag: "0" by default, "1" if the row has been marked
2726      * for deletion. When {@link android.content.ContentResolver#delete} is
2727      * called on a raw contact, it is marked for deletion and removed from its
2728      * aggregate contact. The sync adaptor deletes the raw contact on the server and
2729      * then calls ContactResolver.delete once more, this time passing the
2730      * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to finalize
2731      * the data removal.</td>
2732      * </tr>
2733      * <tr>
2734      * <td>int</td>
2735      * <td>{@link #STARRED}</td>
2736      * <td>read/write</td>
2737      * <td>An indicator for favorite contacts: '1' if favorite, '0' otherwise.
2738      * Changing this field immediately affects the corresponding aggregate contact:
2739      * if any raw contacts in that aggregate contact are starred, then the contact
2740      * itself is marked as starred.</td>
2741      * </tr>
2742      * <tr>
2743      * <td>String</td>
2744      * <td>{@link #CUSTOM_RINGTONE}</td>
2745      * <td>read/write</td>
2746      * <td>A custom ringtone associated with a raw contact. Typically this is the
2747      * URI returned by an activity launched with the
2748      * {@link android.media.RingtoneManager#ACTION_RINGTONE_PICKER} intent.
2749      * To have an effect on the corresponding value of the aggregate contact, this field
2750      * should be set at the time the raw contact is inserted. To set a custom
2751      * ringtone on a contact, use the field {@link ContactsContract.Contacts#CUSTOM_RINGTONE
2752      * Contacts.CUSTOM_RINGTONE}
2753      * instead.</td>
2754      * </tr>
2755      * <tr>
2756      * <td>int</td>
2757      * <td>{@link #SEND_TO_VOICEMAIL}</td>
2758      * <td>read/write</td>
2759      * <td>An indicator of whether calls from this raw contact should be forwarded
2760      * directly to voice mail ('1') or not ('0'). To have an effect
2761      * on the corresponding value of the aggregate contact, this field
2762      * should be set at the time the raw contact is inserted.</td>
2763      * </tr>
2764      * <tr>
2765      * <td>String</td>
2766      * <td>{@link #ACCOUNT_NAME}</td>
2767      * <td>read/write-once</td>
2768      * <td>The name of the account instance to which this row belongs, which when paired with
2769      * {@link #ACCOUNT_TYPE} identifies a specific account.
2770      * For example, this will be the Gmail address if it is a Google account.
2771      * It should be set at the time the raw contact is inserted and never
2772      * changed afterwards.</td>
2773      * </tr>
2774      * <tr>
2775      * <td>String</td>
2776      * <td>{@link #ACCOUNT_TYPE}</td>
2777      * <td>read/write-once</td>
2778      * <td>
2779      * <p>
2780      * The type of account to which this row belongs, which when paired with
2781      * {@link #ACCOUNT_NAME} identifies a specific account.
2782      * It should be set at the time the raw contact is inserted and never
2783      * changed afterwards.
2784      * </p>
2785      * <p>
2786      * To ensure uniqueness, new account types should be chosen according to the
2787      * Java package naming convention.  Thus a Google account is of type "com.google".
2788      * </p>
2789      * </td>
2790      * </tr>
2791      * <tr>
2792      * <td>String</td>
2793      * <td>{@link #DATA_SET}</td>
2794      * <td>read/write-once</td>
2795      * <td>
2796      * <p>
2797      * The data set within the account that this row belongs to.  This allows
2798      * multiple sync adapters for the same account type to distinguish between
2799      * each others' data.  The combination of {@link #ACCOUNT_TYPE},
2800      * {@link #ACCOUNT_NAME}, and {@link #DATA_SET} identifies a set of data
2801      * that is associated with a single sync adapter.
2802      * </p>
2803      * <p>
2804      * This is empty by default, and is completely optional.  It only needs to
2805      * be populated if multiple sync adapters are entering distinct data for
2806      * the same account type and account name.
2807      * </p>
2808      * <p>
2809      * It should be set at the time the raw contact is inserted and never
2810      * changed afterwards.
2811      * </p>
2812      * </td>
2813      * </tr>
2814      * <tr>
2815      * <td>String</td>
2816      * <td>{@link #SOURCE_ID}</td>
2817      * <td>read/write</td>
2818      * <td>String that uniquely identifies this row to its source account.
2819      * Typically it is set at the time the raw contact is inserted and never
2820      * changed afterwards. The one notable exception is a new raw contact: it
2821      * will have an account name and type (and possibly a data set), but no
2822      * source id. This indicates to the sync adapter that a new contact needs
2823      * to be created server-side and its ID stored in the corresponding
2824      * SOURCE_ID field on the phone.
2825      * </td>
2826      * </tr>
2827      * <tr>
2828      * <td>int</td>
2829      * <td>{@link #VERSION}</td>
2830      * <td>read-only</td>
2831      * <td>Version number that is updated whenever this row or its related data
2832      * changes. This field can be used for optimistic locking of a raw contact.
2833      * </td>
2834      * </tr>
2835      * <tr>
2836      * <td>int</td>
2837      * <td>{@link #DIRTY}</td>
2838      * <td>read/write</td>
2839      * <td>Flag indicating that {@link #VERSION} has changed, and this row needs
2840      * to be synchronized by its owning account.  The value is set to "1" automatically
2841      * whenever the raw contact changes, unless the URI has the
2842      * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter specified.
2843      * The sync adapter should always supply this query parameter to prevent
2844      * unnecessary synchronization: user changes some data on the server,
2845      * the sync adapter updates the contact on the phone (without the
2846      * CALLER_IS_SYNCADAPTER flag) flag, which sets the DIRTY flag,
2847      * which triggers a sync to bring the changes to the server.
2848      * </td>
2849      * </tr>
2850      * <tr>
2851      * <td>String</td>
2852      * <td>{@link #SYNC1}</td>
2853      * <td>read/write</td>
2854      * <td>Generic column provided for arbitrary use by sync adapters.
2855      * The content provider
2856      * stores this information on behalf of the sync adapter but does not
2857      * interpret it in any way.
2858      * </td>
2859      * </tr>
2860      * <tr>
2861      * <td>String</td>
2862      * <td>{@link #SYNC2}</td>
2863      * <td>read/write</td>
2864      * <td>Generic column for use by sync adapters.
2865      * </td>
2866      * </tr>
2867      * <tr>
2868      * <td>String</td>
2869      * <td>{@link #SYNC3}</td>
2870      * <td>read/write</td>
2871      * <td>Generic column for use by sync adapters.
2872      * </td>
2873      * </tr>
2874      * <tr>
2875      * <td>String</td>
2876      * <td>{@link #SYNC4}</td>
2877      * <td>read/write</td>
2878      * <td>Generic column for use by sync adapters.
2879      * </td>
2880      * </tr>
2881      * </table>
2882      */
2883     public static final class RawContacts implements BaseColumns, RawContactsColumns,
2884             ContactOptionsColumns, ContactNameColumns, SyncColumns  {
2885         /**
2886          * This utility class cannot be instantiated
2887          */
RawContacts()2888         private RawContacts() {
2889         }
2890 
2891         /**
2892          * The content:// style URI for this table, which requests a directory of
2893          * raw contact rows matching the selection criteria.
2894          */
2895         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "raw_contacts");
2896 
2897         /**
2898          * The MIME type of the results from {@link #CONTENT_URI} when a specific
2899          * ID value is not provided, and multiple raw contacts may be returned.
2900          */
2901         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact";
2902 
2903         /**
2904          * The MIME type of the results when a raw contact ID is appended to {@link #CONTENT_URI},
2905          * yielding a subdirectory of a single person.
2906          */
2907         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/raw_contact";
2908 
2909         /**
2910          * Aggregation mode: aggregate immediately after insert or update operation(s) are complete.
2911          */
2912         public static final int AGGREGATION_MODE_DEFAULT = 0;
2913 
2914         /**
2915          * Aggregation mode: aggregate at the time the raw contact is inserted/updated.
2916          * @deprecated Aggregation is synchronous, this historic value is a no-op
2917          */
2918         @Deprecated
2919         public static final int AGGREGATION_MODE_IMMEDIATE = 1;
2920 
2921         /**
2922          * <p>
2923          * Aggregation mode: aggregation suspended temporarily, and is likely to be resumed later.
2924          * Changes to the raw contact will update the associated aggregate contact but will not
2925          * result in any change in how the contact is aggregated. Similar to
2926          * {@link #AGGREGATION_MODE_DISABLED}, but maintains a link to the corresponding
2927          * {@link Contacts} aggregate.
2928          * </p>
2929          * <p>
2930          * This can be used to postpone aggregation until after a series of updates, for better
2931          * performance and/or user experience.
2932          * </p>
2933          * <p>
2934          * Note that changing
2935          * {@link #AGGREGATION_MODE} from {@link #AGGREGATION_MODE_SUSPENDED} to
2936          * {@link #AGGREGATION_MODE_DEFAULT} does not trigger an aggregation pass, but any
2937          * subsequent
2938          * change to the raw contact's data will.
2939          * </p>
2940          */
2941         public static final int AGGREGATION_MODE_SUSPENDED = 2;
2942 
2943         /**
2944          * <p>
2945          * Aggregation mode: never aggregate this raw contact.  The raw contact will not
2946          * have a corresponding {@link Contacts} aggregate and therefore will not be included in
2947          * {@link Contacts} query results.
2948          * </p>
2949          * <p>
2950          * For example, this mode can be used for a raw contact that is marked for deletion while
2951          * waiting for the deletion to occur on the server side.
2952          * </p>
2953          *
2954          * @see #AGGREGATION_MODE_SUSPENDED
2955          */
2956         public static final int AGGREGATION_MODE_DISABLED = 3;
2957 
2958         /**
2959          * Build a {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}
2960          * style {@link Uri} for the parent {@link android.provider.ContactsContract.Contacts}
2961          * entry of the given {@link RawContacts} entry.
2962          */
getContactLookupUri(ContentResolver resolver, Uri rawContactUri)2963         public static Uri getContactLookupUri(ContentResolver resolver, Uri rawContactUri) {
2964             // TODO: use a lighter query by joining rawcontacts with contacts in provider
2965             final Uri dataUri = Uri.withAppendedPath(rawContactUri, Data.CONTENT_DIRECTORY);
2966             final Cursor cursor = resolver.query(dataUri, new String[] {
2967                     RawContacts.CONTACT_ID, Contacts.LOOKUP_KEY
2968             }, null, null, null);
2969 
2970             Uri lookupUri = null;
2971             try {
2972                 if (cursor != null && cursor.moveToFirst()) {
2973                     final long contactId = cursor.getLong(0);
2974                     final String lookupKey = cursor.getString(1);
2975                     return Contacts.getLookupUri(contactId, lookupKey);
2976                 }
2977             } finally {
2978                 if (cursor != null) cursor.close();
2979             }
2980             return lookupUri;
2981         }
2982 
2983         /**
2984          * The default value used for {@link #ACCOUNT_NAME} of raw contacts when they are inserted
2985          * without a value for this column.
2986          *
2987          * <p>This account is used to identify contacts that are only stored locally in the
2988          * contacts database instead of being associated with an {@link Account} managed by an
2989          * installed application.
2990          *
2991          * <p>When this returns null then {@link #getLocalAccountType} will also return null and
2992          * when it is non-null {@link #getLocalAccountType} will also return a non-null value.
2993          */
2994         @Nullable
getLocalAccountName(@onNull Context context)2995         public static String getLocalAccountName(@NonNull Context context) {
2996             //  config_rawContactsLocalAccountName is defined in
2997             //  platform/frameworks/base/core/res/res/values/config.xml
2998             return TextUtils.nullIfEmpty(context.getString(
2999                     com.android.internal.R.string.config_rawContactsLocalAccountName));
3000         }
3001 
3002         /**
3003          * The default value used for {@link #ACCOUNT_TYPE} of raw contacts when they are inserted
3004          * without a value for this column.
3005          *
3006          * <p>This account is used to identify contacts that are only stored locally in the
3007          * contacts database instead of being associated with an {@link Account} managed by an
3008          * installed application.
3009          *
3010          * <p>When this returns null then {@link #getLocalAccountName} will also return null and
3011          * when it is non-null {@link #getLocalAccountName} will also return a non-null value.
3012          */
3013         @Nullable
getLocalAccountType(@onNull Context context)3014         public static String getLocalAccountType(@NonNull Context context) {
3015             //  config_rawContactsLocalAccountType is defined in
3016             //  platform/frameworks/base/core/res/res/values/config.xml
3017             return TextUtils.nullIfEmpty(context.getString(
3018                     com.android.internal.R.string.config_rawContactsLocalAccountType));
3019         }
3020 
3021 
3022 
3023         /**
3024          * Class containing utility methods around the default account.
3025          * New raw contacts requested to be inserted without a specified {@link Account} will be
3026          * saved in the default account.
3027          */
3028         @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
3029         public static final class DefaultAccount {
3030             /**
3031              * no public constructor since this is a utility class
3032              */
DefaultAccount()3033             private DefaultAccount() {
3034 
3035             }
3036 
3037             /**
3038              * Key in the outgoing Bundle for the default account list.
3039              *
3040              * @hide
3041              */
3042             public static final String KEY_ELIGIBLE_DEFAULT_ACCOUNTS =
3043                     "key_eligible_default_accounts";
3044             /**
3045              * The method to invoke in order to query eligiblie default accounts.
3046              *
3047              * @hide
3048              */
3049             public static final String QUERY_ELIGIBLE_DEFAULT_ACCOUNTS_METHOD =
3050                     "queryEligibleDefaultAccounts";
3051             /**
3052              * Key in the Bundle for the default account state.
3053              *
3054              * @hide
3055              */
3056             public static final String KEY_DEFAULT_ACCOUNT_STATE =
3057                     "key_default_account_state";
3058             /**
3059              * The method to invoke in order to set the default account.
3060              *
3061              * @hide
3062              */
3063             public static final String SET_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD =
3064                     "setDefaultAccountForNewContacts";
3065             /**
3066              * The method to invoke in order to query the default account.
3067              *
3068              * @hide
3069              */
3070             public static final String QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD =
3071                     "queryDefaultAccountForNewContacts";
3072 
3073             /**
3074              * Action used to launch the UI to move contacts to the default account.
3075              */
3076             @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
3077             public static final String ACTION_MOVE_CONTACTS_TO_DEFAULT_ACCOUNT =
3078                     "android.provider.action.MOVE_CONTACTS_TO_DEFAULT_ACCOUNT";
3079 
3080 
3081             /**
3082              * Represents the state of the default account, and the actual {@link Account} if it's
3083              * a cloud account.
3084              * If the default account is set to {@link #DEFAULT_ACCOUNT_STATE_LOCAL} or
3085              * {@link #DEFAULT_ACCOUNT_STATE_CLOUD}, new raw contacts requested for insertion
3086              * without a
3087              * specified {@link Account} will be saved in the default account.
3088              * The default account can have one of the following four states:
3089              * <ul>
3090              * <li> {@link #DEFAULT_ACCOUNT_STATE_NOT_SET}: The default account has not
3091              * been set by the user. </li>
3092              * <li> {@link #DEFAULT_ACCOUNT_STATE_LOCAL}: The default account is set to
3093              * the local device storage. New raw contacts requested for insertion without a
3094              * specified
3095              * {@link Account} will be saved in a null or custom local account. </li>
3096              * <li> {@link #DEFAULT_ACCOUNT_STATE_CLOUD}: The default account is set to a
3097              * cloud-synced account. New raw contacts requested for insertion without a specified
3098              * {@link Account} will be saved in the default cloud account. </li>
3099              * <li> {@link #DEFAULT_ACCOUNT_STATE_SIM}: The default account is set to a
3100              * account that is associated with one of
3101              * {@link SimContacts#getSimAccounts(ContentResolver)}. New raw contacts requested
3102              * for insertion without a specified {@link Account} will be
3103              * saved in this SIM account. </li>
3104              * </ul>
3105              */
3106             @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
3107             public static final class DefaultAccountAndState {
3108                 /** A state indicating that default account is not set. */
3109                 public static final int DEFAULT_ACCOUNT_STATE_NOT_SET = 1;
3110 
3111                 /** A state indicating that default account is set to local device storage. */
3112                 public static final int DEFAULT_ACCOUNT_STATE_LOCAL = 2;
3113 
3114                 /**
3115                  * A state indicating that the default account is set as an account that is synced
3116                  * to the cloud.
3117                  */
3118                 public static final int DEFAULT_ACCOUNT_STATE_CLOUD = 3;
3119 
3120                 /**
3121                  * A state indicating that the default account is set as an account that is
3122                  * associated with one of {@link SimContacts#getSimAccounts(ContentResolver)}.
3123                  */
3124                 public static final int DEFAULT_ACCOUNT_STATE_SIM = 4;
3125 
3126                 /**
3127                  * The state of the default account. One of
3128                  * {@link #DEFAULT_ACCOUNT_STATE_NOT_SET},
3129                  * {@link #DEFAULT_ACCOUNT_STATE_LOCAL},
3130                  * {@link #DEFAULT_ACCOUNT_STATE_CLOUD}
3131                  * {@link #DEFAULT_ACCOUNT_STATE_SIM}.
3132                  */
3133                 @DefaultAccountState
3134                 private final int mState;
3135 
3136                 /**
3137                  * The account of the default account, when {@link #mState} is {
3138                  *
3139                  * @link #DEFAULT_ACCOUNT_STATE_CLOUD} or {@link #DEFAULT_ACCOUNT_STATE_SIM}, or
3140                  * null otherwise.
3141                  */
3142                 private final Account mAccount;
3143 
3144                 /**
3145                  * Constructs a new `DefaultAccountAndState` instance with the specified state and
3146                  * cloud
3147                  * account.
3148                  *
3149                  * @param state   The state of the default account.
3150                  * @param account The account associated with the default account if the state is
3151                  *                {@link #DEFAULT_ACCOUNT_STATE_CLOUD} or
3152                  *                {@link #DEFAULT_ACCOUNT_STATE_SIM}, or null otherwise.
3153                  */
DefaultAccountAndState(@efaultAccountState int state, @Nullable Account account)3154                 private DefaultAccountAndState(@DefaultAccountState int state,
3155                         @Nullable Account account) {
3156                     if (!isValidDefaultAccountState(state)) {
3157                         throw new IllegalArgumentException("Invalid default account state.");
3158                     }
3159                     if (isCloudOrSimAccount(state) != (account != null)) {
3160                         throw new IllegalArgumentException(
3161                                 "Default account can be set to cloud or SIM if and only if the "
3162                                         + "account is provided.");
3163                     }
3164                     this.mState = state;
3165                     this.mAccount = isCloudOrSimAccount(state) ? account : null;
3166                 }
3167 
3168                 /**
3169                  * Creates a `DefaultAccountAndState` instance representing a default account
3170                  * that is set to the cloud and associated with the specified cloud account.
3171                  *
3172                  * @param cloudAccount The non-null cloud account associated with the default
3173                  *                     contacts
3174                  *                     account.
3175                  * @return A new `DefaultAccountAndState` instance with state
3176                  * {@link #DEFAULT_ACCOUNT_STATE_CLOUD}.
3177                  */
ofCloud( @onNull Account cloudAccount)3178                 public static @NonNull DefaultAccountAndState ofCloud(
3179                         @NonNull Account cloudAccount) {
3180                     return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_CLOUD, cloudAccount);
3181                 }
3182 
3183 
3184                 /**
3185                  * Creates a `DefaultAccountAndState` instance representing a default account
3186                  * that is set to the sim and associated with the specified sim account.
3187                  *
3188                  * @param simAccount The non-null sim account associated with the default
3189                  *                   contacts account.
3190                  * @return A new `DefaultAccountAndState` instance with state
3191                  * {@link #DEFAULT_ACCOUNT_STATE_SIM}.
3192                  */
ofSim( @onNull Account simAccount)3193                 public static @NonNull DefaultAccountAndState ofSim(
3194                         @NonNull Account simAccount) {
3195                     return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_SIM, simAccount);
3196                 }
3197 
3198                 /**
3199                  * Creates a `DefaultAccountAndState` instance representing a default account
3200                  * that is set to the local device storage.
3201                  *
3202                  * @return A new `DefaultAccountAndState` instance with state
3203                  * {@link #DEFAULT_ACCOUNT_STATE_LOCAL}.
3204                  */
ofLocal()3205                 public static @NonNull DefaultAccountAndState ofLocal() {
3206                     return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_LOCAL, null);
3207                 }
3208 
3209                 /**
3210                  * Creates a `DefaultAccountAndState` instance representing a default account
3211                  * that is not set.
3212                  *
3213                  * @return A new `DefaultAccountAndState` instance with state
3214                  * {@link #DEFAULT_ACCOUNT_STATE_NOT_SET}.
3215                  */
ofNotSet()3216                 public static @NonNull DefaultAccountAndState ofNotSet() {
3217                     return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_NOT_SET, null);
3218                 }
3219 
3220                 /**
3221                  *
3222                  * @hide
3223                  */
isCloudOrSimAccount(@efaultAccountState int state)3224                 public static boolean isCloudOrSimAccount(@DefaultAccountState int state) {
3225                     return state == DEFAULT_ACCOUNT_STATE_CLOUD
3226                             || state == DEFAULT_ACCOUNT_STATE_SIM;
3227                 }
3228 
isValidDefaultAccountState(int state)3229                 private static boolean isValidDefaultAccountState(int state) {
3230                     return state == DEFAULT_ACCOUNT_STATE_NOT_SET
3231                             || state == DEFAULT_ACCOUNT_STATE_LOCAL
3232                             || state == DEFAULT_ACCOUNT_STATE_CLOUD
3233                             || state == DEFAULT_ACCOUNT_STATE_SIM;
3234                 }
3235 
3236                 /**
3237                  * @return the state of the default account.
3238                  */
3239                 @DefaultAccountState
getState()3240                 public int getState() {
3241                     return mState;
3242                 }
3243 
3244                 /**
3245                  * @return the cloud account associated with the default account if the
3246                  * state is {@link #DEFAULT_ACCOUNT_STATE_CLOUD} or
3247                  * {@link #DEFAULT_ACCOUNT_STATE_SIM}.
3248                  */
getAccount()3249                 public @Nullable Account getAccount() {
3250                     return mAccount;
3251                 }
3252 
3253                 @Override
hashCode()3254                 public int hashCode() {
3255                     return Objects.hash(mState, mAccount);
3256                 }
3257 
3258                 @Override
equals(Object obj)3259                 public boolean equals(Object obj) {
3260                     if (this == obj) {
3261                         return true;
3262                     }
3263                     if (!(obj instanceof DefaultAccountAndState that)) {
3264                         return false;
3265                     }
3266 
3267                     return mState == that.mState && Objects.equals(mAccount,
3268                             that.mAccount);
3269                 }
3270 
3271                 /**
3272                  * Annotation for all default account states.
3273                  *
3274                  * @hide
3275                  */
3276                 @Retention(RetentionPolicy.SOURCE)
3277                 @IntDef(
3278                         prefix = {"DEFAULT_ACCOUNT_STATE_"},
3279                         value = {DEFAULT_ACCOUNT_STATE_NOT_SET,
3280                                 DEFAULT_ACCOUNT_STATE_LOCAL, DEFAULT_ACCOUNT_STATE_CLOUD,
3281                                 DEFAULT_ACCOUNT_STATE_SIM})
3282                 public @interface DefaultAccountState {
3283                 }
3284             }
3285 
3286             /**
3287              * Get the account that is set as the default account for new contacts, which should be
3288              * initially selected when creating a new contact on contact management apps.
3289              *
3290              * @param resolver the ContentResolver to query.
3291              *
3292              * @return the default account state for new contacts.
3293              * @throws RuntimeException if failed to look up the default account.
3294              * @throws IllegalStateException if the default account is in an invalid state.
3295              */
3296             @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
getDefaultAccountForNewContacts( @onNull ContentResolver resolver)3297             public static @NonNull DefaultAccountAndState getDefaultAccountForNewContacts(
3298                     @NonNull ContentResolver resolver) {
3299                 Bundle response = nullSafeCall(resolver, ContactsContract.AUTHORITY_URI,
3300                         QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD, null, null);
3301 
3302                 int defaultAccountState = response.getInt(KEY_DEFAULT_ACCOUNT_STATE, -1);
3303                 if (DefaultAccountAndState.isCloudOrSimAccount(defaultAccountState)) {
3304                     String accountName = response.getString(Settings.ACCOUNT_NAME);
3305                     String accountType = response.getString(Settings.ACCOUNT_TYPE);
3306                     if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
3307                         throw new IllegalStateException(
3308                                 "account name and type cannot be null or empty");
3309                     }
3310                     return new DefaultAccountAndState(defaultAccountState,
3311                             new Account(accountName, accountType));
3312                 } else if (defaultAccountState == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_LOCAL
3313                         || defaultAccountState
3314                         == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_NOT_SET) {
3315                     return new DefaultAccountAndState(defaultAccountState, /*account=*/
3316                             null);
3317                 } else {
3318                     throw new IllegalStateException("Invalid default account state");
3319                 }
3320             }
3321 
3322             /**
3323              * Sets the default account that should be initially selected when creating a new
3324              * contact on
3325              * contact management apps. Apps can only set one of
3326              * The following accounts as the default account:
3327              * <ol>
3328              *   <li> local account
3329              *   <li> cloud account that are eligible to be set as default account.
3330              * </ol>
3331              *
3332              * @param resolver               the ContentResolver to query.
3333              * @param defaultAccountAndState the default account and state to be set. To set the
3334              *                               local
3335              *                               account as the
3336              *                               default account, this parameter should be
3337              *                               {@link DefaultAccountAndState#ofLocal()}. To set the a
3338              *                               cloud
3339              *                               account as the default account, this parameter should
3340              *                               be
3341              *                               {@link DefaultAccountAndState#ofCloud(Account)}. To
3342              *                               set
3343              *                               the
3344              *                               default account to a "not set" state, this parameter
3345              *                               should
3346              *                               be {@link DefaultAccountAndState#ofNotSet()}.
3347              *
3348              * @throws RuntimeException if it fails to set the default account.
3349              *
3350              * @hide
3351              */
3352             @RequiresPermission(android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS)
3353             @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
3354             @SystemApi
setDefaultAccountForNewContacts(@onNull ContentResolver resolver, @NonNull DefaultAccountAndState defaultAccountAndState)3355             public static void setDefaultAccountForNewContacts(@NonNull ContentResolver resolver,
3356                     @NonNull DefaultAccountAndState defaultAccountAndState) {
3357                 Bundle extras = new Bundle();
3358 
3359                 extras.putInt(KEY_DEFAULT_ACCOUNT_STATE, defaultAccountAndState.getState());
3360                 if (DefaultAccountAndState.isCloudOrSimAccount(defaultAccountAndState.getState())) {
3361                     Account account = defaultAccountAndState.getAccount();
3362                     assert account != null;
3363                     extras.putString(Settings.ACCOUNT_NAME, account.name);
3364                     extras.putString(Settings.ACCOUNT_TYPE, account.type);
3365                 }
3366                 nullSafeCall(resolver, ContactsContract.AUTHORITY_URI,
3367                         SET_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD, null, extras);
3368             }
3369 
3370             /**
3371              * Get a list of cloud accounts that is eligible to set as default account with state of
3372              * {@link DefaultAccountAndState#DEFAULT_ACCOUNT_STATE_CLOUD}. May be empty but never
3373              * null.
3374              *
3375              * @param resolver content resolver to query.
3376              * @return a of cloud accounts that is eligible to set as default account with state of
3377              * {@link DefaultAccountAndState#DEFAULT_ACCOUNT_STATE_CLOUD}.
3378              * @throws RuntimeException if the query fails.
3379              *
3380              * @hide
3381              */
3382             @RequiresPermission(android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS)
3383             @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
3384             @SystemApi
getEligibleCloudAccounts( @onNull ContentResolver resolver)3385             public static @NonNull List<Account> getEligibleCloudAccounts(
3386                     @NonNull ContentResolver resolver) {
3387                 Bundle response = nullSafeCall(resolver, ContactsContract.AUTHORITY_URI,
3388                         QUERY_ELIGIBLE_DEFAULT_ACCOUNTS_METHOD, null, null);
3389                 List<Account> result = response.getParcelableArrayList(
3390                         KEY_ELIGIBLE_DEFAULT_ACCOUNTS, Account.class);
3391                 if (result == null) {
3392                     return new ArrayList<>();
3393                 }
3394                 return result;
3395             }
3396 
3397 
3398 
3399             /**
3400              * The method to invoke to move local {@link RawContacts} and {@link Groups} from local
3401              * account(s) to the Cloud Default Account (if any).
3402              *
3403              * @hide
3404              */
3405             public static final String MOVE_LOCAL_CONTACTS_TO_CLOUD_DEFAULT_ACCOUNT_METHOD =
3406                     "moveLocalContactsToCloudDefaultAccount";
3407 
3408             /**
3409              * Move {@link RawContacts} and {@link Groups} (if any) from the local account to the
3410              * Cloud Default Account (if any).
3411              * @param resolver the ContentResolver to query.
3412              * @throws RuntimeException if it fails to move contacts to the default account.
3413              *
3414              * @hide
3415              */
3416             @SystemApi
3417             @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
3418             @RequiresPermission(allOf = {android.Manifest.permission.WRITE_CONTACTS,
3419                     android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS})
moveLocalContactsToCloudDefaultAccount( @onNull ContentResolver resolver)3420             public static void moveLocalContactsToCloudDefaultAccount(
3421                     @NonNull ContentResolver resolver) {
3422 
3423                 Bundle extras = new Bundle();
3424                 Bundle result = nullSafeCall(
3425                         resolver,
3426                         ContactsContract.AUTHORITY_URI,
3427                         MOVE_LOCAL_CONTACTS_TO_CLOUD_DEFAULT_ACCOUNT_METHOD,
3428                         null,
3429                         extras);
3430             }
3431 
3432             /**
3433              * The method to invoke to move {@link RawContacts} and {@link Groups} from SIM
3434              * account(s) to the Cloud Default Account (if any).
3435              *
3436              * @hide
3437              */
3438             public static final String MOVE_SIM_CONTACTS_TO_CLOUD_DEFAULT_ACCOUNT_METHOD =
3439                     "moveSimContactsToCloudDefaultAccount";
3440 
3441             /**
3442              * Move {@link RawContacts} and {@link Groups} (if any) from the local account to the
3443              * Cloud Default Account (if any).
3444              * @param resolver the ContentResolver to query.
3445              * @throws RuntimeException if it fails to move contacts to the default account.
3446              *
3447              * @hide
3448              */
3449             @SystemApi
3450             @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
3451             @RequiresPermission(allOf = {android.Manifest.permission.WRITE_CONTACTS,
3452                     android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS})
moveSimContactsToCloudDefaultAccount( @onNull ContentResolver resolver)3453             public static void moveSimContactsToCloudDefaultAccount(
3454                     @NonNull ContentResolver resolver) {
3455                 Bundle result = nullSafeCall(
3456                         resolver,
3457                         ContactsContract.AUTHORITY_URI,
3458                         MOVE_SIM_CONTACTS_TO_CLOUD_DEFAULT_ACCOUNT_METHOD,
3459                         /* arg= */ null,
3460                         /* extras= */ null);
3461             }
3462 
3463             /**
3464              * The method to invoke to get the number of {@link RawContacts} that are in local
3465              * account(s) and movable to the Cloud Default Account (if any).
3466              *
3467              * @hide
3468              */
3469             public static final String GET_NUMBER_OF_MOVABLE_LOCAL_CONTACTS_METHOD =
3470                     "getNumberOfMovableLocalContacts";
3471 
3472             /**
3473              * The result key for moving local {@link RawContacts} and {@link Groups} from SIM
3474              * account(s) to the Cloud Default Account (if any).
3475              *
3476              * @hide
3477              */
3478             public static final String KEY_NUMBER_OF_MOVABLE_LOCAL_CONTACTS =
3479                     "key_number_of_movable_local_contacts";
3480 
3481             /**
3482              * Gets the number of {@link RawContacts} in the local account(s) which may be moved
3483              * using {@link DefaultAccount#moveLocalContactsToCloudDefaultAccount} (if any).
3484              * @param resolver the ContentResolver to query.
3485              * @return the number of {@link RawContacts} in the local account(s), or 0 if there is
3486              * no Cloud Default Account.
3487              * @throws RuntimeException if it fails get the number of movable local contacts.
3488              *
3489              * @hide
3490              */
3491             @SystemApi
3492             @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
3493             @RequiresPermission(allOf = {android.Manifest.permission.READ_CONTACTS,
3494                     android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS})
getNumberOfMovableLocalContacts( @onNull ContentResolver resolver)3495             public static int getNumberOfMovableLocalContacts(
3496                     @NonNull ContentResolver resolver) {
3497                 Bundle result = nullSafeCall(
3498                         resolver,
3499                         ContactsContract.AUTHORITY_URI,
3500                         GET_NUMBER_OF_MOVABLE_LOCAL_CONTACTS_METHOD,
3501                         /* arg= */ null,
3502                         /* extras= */ null);
3503                 return result.getInt(KEY_NUMBER_OF_MOVABLE_LOCAL_CONTACTS,
3504                         /* defaultValue= */ 0);
3505             }
3506 
3507             /**
3508              * The method to invoke to get the number of {@link RawContacts} that are in SIM
3509              * account(s) and movable to the Cloud Default Account (if any).
3510              *
3511              * @hide
3512              */
3513             public static final String GET_NUMBER_OF_MOVABLE_SIM_CONTACTS_METHOD =
3514                     "getNumberOfMovableSimContacts";
3515 
3516             /**
3517              * The result key for moving local {@link RawContacts} and {@link Groups} from SIM
3518              * account(s) to the Cloud Default Account (if any).
3519              *
3520              * @hide
3521              */
3522             public static final String KEY_NUMBER_OF_MOVABLE_SIM_CONTACTS =
3523                     "key_number_of_movable_sim_contacts";
3524 
3525             /**
3526              * Gets the number of {@link RawContacts} in the SIM account(s) which may be moved using
3527              * {@link DefaultAccount#moveSimContactsToCloudDefaultAccount} (if any).
3528              * @param resolver the ContentResolver to query.
3529              * @return the number of {@link RawContacts} in the SIM account(s), or 0 if there is
3530              * no Cloud Default Account.
3531              * @throws RuntimeException if it fails get the number of movable sim contacts.
3532              *
3533              * @hide
3534              */
3535             @SystemApi
3536             @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
3537             @RequiresPermission(allOf = {android.Manifest.permission.READ_CONTACTS,
3538                     android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS})
getNumberOfMovableSimContacts( @onNull ContentResolver resolver)3539             public static int getNumberOfMovableSimContacts(
3540                     @NonNull ContentResolver resolver) {
3541                 Bundle result = nullSafeCall(
3542                         resolver,
3543                         ContactsContract.AUTHORITY_URI,
3544                         GET_NUMBER_OF_MOVABLE_SIM_CONTACTS_METHOD,
3545                         /* arg= */ null,
3546                         /* extras= */ null);
3547                 return result.getInt(KEY_NUMBER_OF_MOVABLE_SIM_CONTACTS,
3548                         /* defaultValue= */ 0);
3549             }
3550 
3551         }
3552 
3553         /**
3554          * A sub-directory of a single raw contact that contains all of its
3555          * {@link ContactsContract.Data} rows. To access this directory
3556          * append {@link Data#CONTENT_DIRECTORY} to the raw contact URI.
3557          */
3558         public static final class Data implements BaseColumns, DataColumns {
3559             /**
3560              * no public constructor since this is a utility class
3561              */
Data()3562             private Data() {
3563             }
3564 
3565             /**
3566              * The directory twig for this sub-table
3567              */
3568             public static final String CONTENT_DIRECTORY = "data";
3569         }
3570 
3571         /**
3572          * <p>
3573          * A sub-directory of a single raw contact that contains all of its
3574          * {@link ContactsContract.Data} rows. To access this directory append
3575          * {@link RawContacts.Entity#CONTENT_DIRECTORY} to the raw contact URI. See
3576          * {@link RawContactsEntity} for a stand-alone table containing the same
3577          * data.
3578          * </p>
3579          * <p>
3580          * Entity has two ID fields: {@link #_ID} for the raw contact
3581          * and {@link #DATA_ID} for the data rows.
3582          * Entity always contains at least one row, even if there are no
3583          * actual data rows. In this case the {@link #DATA_ID} field will be
3584          * null.
3585          * </p>
3586          * <p>
3587          * Using Entity should be preferred to using two separate queries:
3588          * RawContacts followed by Data. The reason is that Entity reads all
3589          * data for a raw contact in one transaction, so there is no possibility
3590          * of the data changing between the two queries.
3591          */
3592         public static final class Entity implements BaseColumns, DataColumns {
3593             /**
3594              * no public constructor since this is a utility class
3595              */
Entity()3596             private Entity() {
3597             }
3598 
3599             /**
3600              * The directory twig for this sub-table
3601              */
3602             public static final String CONTENT_DIRECTORY = "entity";
3603 
3604             /**
3605              * The ID of the data row. The value will be null if this raw contact has no
3606              * data rows.
3607              * <P>Type: INTEGER</P>
3608              */
3609             public static final String DATA_ID = "data_id";
3610         }
3611 
3612         /**
3613          * <p>
3614          * A sub-directory of a single raw contact that contains all of its
3615          * {@link ContactsContract.StreamItems} rows. To access this directory append
3616          * {@link RawContacts.StreamItems#CONTENT_DIRECTORY} to the raw contact URI. See
3617          * {@link ContactsContract.StreamItems} for a stand-alone table containing the
3618          * same data.
3619          * </p>
3620          * <p>
3621          * Access to the social stream through this sub-directory requires additional permissions
3622          * beyond the read/write contact permissions required by the provider.  Querying for
3623          * social stream data requires android.permission.READ_SOCIAL_STREAM permission, and
3624          * inserting or updating social stream items requires android.permission.WRITE_SOCIAL_STREAM
3625          * permission.
3626          * </p>
3627          *
3628          * @deprecated - Do not use. This will not be supported in the future. In the future,
3629          * cursors returned from related queries will be empty.
3630          *
3631          * @removed
3632          */
3633         @Deprecated
3634         public static final class StreamItems implements BaseColumns, StreamItemsColumns {
3635             /**
3636              * No public constructor since this is a utility class
3637              *
3638              * @deprecated - Do not use. This will not be supported in the future. In the future,
3639              * cursors returned from related queries will be empty.
3640              */
3641             @Deprecated
StreamItems()3642             private StreamItems() {
3643             }
3644 
3645             /**
3646              * The directory twig for this sub-table
3647              *
3648              * @deprecated - Do not use. This will not be supported in the future. In the future,
3649              * cursors returned from related queries will be empty.
3650              */
3651             @Deprecated
3652             public static final String CONTENT_DIRECTORY = "stream_items";
3653         }
3654 
3655         /**
3656          * <p>
3657          * A sub-directory of a single raw contact that represents its primary
3658          * display photo.  To access this directory append
3659          * {@link RawContacts.DisplayPhoto#CONTENT_DIRECTORY} to the raw contact URI.
3660          * The resulting URI represents an image file, and should be interacted with
3661          * using ContentResolver.openAssetFileDescriptor.
3662          * <p>
3663          * <p>
3664          * Note that this sub-directory also supports opening the photo as an asset file
3665          * in write mode.  Callers can create or replace the primary photo associated
3666          * with this raw contact by opening the asset file and writing the full-size
3667          * photo contents into it.  When the file is closed, the image will be parsed,
3668          * sized down if necessary for the full-size display photo and thumbnail
3669          * dimensions, and stored.
3670          * </p>
3671          * <p>
3672          * Usage example:
3673          * <pre>
3674          * public void writeDisplayPhoto(long rawContactId, byte[] photo) {
3675          *     Uri rawContactPhotoUri = Uri.withAppendedPath(
3676          *             ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
3677          *             RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
3678          *     try {
3679          *         AssetFileDescriptor fd =
3680          *             getContentResolver().openAssetFileDescriptor(rawContactPhotoUri, "rw");
3681          *         OutputStream os = fd.createOutputStream();
3682          *         os.write(photo);
3683          *         os.close();
3684          *         fd.close();
3685          *     } catch (IOException e) {
3686          *         // Handle error cases.
3687          *     }
3688          * }
3689          * </pre>
3690          * </p>
3691          */
3692         public static final class DisplayPhoto {
3693             /**
3694              * No public constructor since this is a utility class
3695              */
DisplayPhoto()3696             private DisplayPhoto() {
3697             }
3698 
3699             /**
3700              * The directory twig for this sub-table
3701              */
3702             public static final String CONTENT_DIRECTORY = "display_photo";
3703         }
3704 
3705         /**
3706          * TODO: javadoc
3707          * @param cursor
3708          * @return
3709          */
newEntityIterator(Cursor cursor)3710         public static EntityIterator newEntityIterator(Cursor cursor) {
3711             return new EntityIteratorImpl(cursor);
3712         }
3713 
3714         private static class EntityIteratorImpl extends CursorEntityIterator {
3715             private static final String[] DATA_KEYS = new String[]{
3716                     Data.DATA1,
3717                     Data.DATA2,
3718                     Data.DATA3,
3719                     Data.DATA4,
3720                     Data.DATA5,
3721                     Data.DATA6,
3722                     Data.DATA7,
3723                     Data.DATA8,
3724                     Data.DATA9,
3725                     Data.DATA10,
3726                     Data.DATA11,
3727                     Data.DATA12,
3728                     Data.DATA13,
3729                     Data.DATA14,
3730                     Data.DATA15,
3731                     Data.SYNC1,
3732                     Data.SYNC2,
3733                     Data.SYNC3,
3734                     Data.SYNC4};
3735 
EntityIteratorImpl(Cursor cursor)3736             public EntityIteratorImpl(Cursor cursor) {
3737                 super(cursor);
3738             }
3739 
3740             @Override
getEntityAndIncrementCursor(Cursor cursor)3741             public android.content.Entity getEntityAndIncrementCursor(Cursor cursor)
3742                     throws RemoteException {
3743                 final int columnRawContactId = cursor.getColumnIndexOrThrow(RawContacts._ID);
3744                 final long rawContactId = cursor.getLong(columnRawContactId);
3745 
3746                 // we expect the cursor is already at the row we need to read from
3747                 ContentValues cv = new ContentValues();
3748                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, ACCOUNT_NAME);
3749                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, ACCOUNT_TYPE);
3750                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, DATA_SET);
3751                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, _ID);
3752                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DIRTY);
3753                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, VERSION);
3754                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SOURCE_ID);
3755                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC1);
3756                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC2);
3757                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC3);
3758                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, SYNC4);
3759                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DELETED);
3760                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, CONTACT_ID);
3761                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, STARRED);
3762                 android.content.Entity contact = new android.content.Entity(cv);
3763 
3764                 // read data rows until the contact id changes
3765                 do {
3766                     if (rawContactId != cursor.getLong(columnRawContactId)) {
3767                         break;
3768                     }
3769                     // add the data to to the contact
3770                     cv = new ContentValues();
3771                     cv.put(Data._ID, cursor.getLong(cursor.getColumnIndexOrThrow(Entity.DATA_ID)));
3772                     DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv,
3773                             Data.RES_PACKAGE);
3774                     DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Data.MIMETYPE);
3775                     DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, Data.IS_PRIMARY);
3776                     DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv,
3777                             Data.IS_SUPER_PRIMARY);
3778                     DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, Data.DATA_VERSION);
3779                     DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv,
3780                             CommonDataKinds.GroupMembership.GROUP_SOURCE_ID);
3781                     DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv,
3782                             Data.DATA_VERSION);
3783                     for (String key : DATA_KEYS) {
3784                         final int columnIndex = cursor.getColumnIndexOrThrow(key);
3785                         switch (cursor.getType(columnIndex)) {
3786                             case Cursor.FIELD_TYPE_NULL:
3787                                 // don't put anything
3788                                 break;
3789                             case Cursor.FIELD_TYPE_INTEGER:
3790                             case Cursor.FIELD_TYPE_FLOAT:
3791                             case Cursor.FIELD_TYPE_STRING:
3792                                 cv.put(key, cursor.getString(columnIndex));
3793                                 break;
3794                             case Cursor.FIELD_TYPE_BLOB:
3795                                 cv.put(key, cursor.getBlob(columnIndex));
3796                                 break;
3797                             default:
3798                                 throw new IllegalStateException("Invalid or unhandled data type");
3799                         }
3800                     }
3801                     contact.addSubValue(ContactsContract.Data.CONTENT_URI, cv);
3802                 } while (cursor.moveToNext());
3803 
3804                 return contact;
3805             }
3806 
3807         }
3808     }
3809 
3810     /**
3811      * Social status update columns.
3812      *
3813      * @see StatusUpdates
3814      * @see ContactsContract.Data
3815      */
3816     protected interface StatusColumns {
3817         /**
3818          * Contact's latest presence level.
3819          * <P>Type: INTEGER (one of the values below)</P>
3820          */
3821         public static final String PRESENCE = "mode";
3822 
3823         /**
3824          * @deprecated use {@link #PRESENCE}
3825          */
3826         @Deprecated
3827         public static final String PRESENCE_STATUS = PRESENCE;
3828 
3829         /**
3830          * An allowed value of {@link #PRESENCE}.
3831          */
3832         int OFFLINE = 0;
3833 
3834         /**
3835          * An allowed value of {@link #PRESENCE}.
3836          */
3837         int INVISIBLE = 1;
3838 
3839         /**
3840          * An allowed value of {@link #PRESENCE}.
3841          */
3842         int AWAY = 2;
3843 
3844         /**
3845          * An allowed value of {@link #PRESENCE}.
3846          */
3847         int IDLE = 3;
3848 
3849         /**
3850          * An allowed value of {@link #PRESENCE}.
3851          */
3852         int DO_NOT_DISTURB = 4;
3853 
3854         /**
3855          * An allowed value of {@link #PRESENCE}.
3856          */
3857         int AVAILABLE = 5;
3858 
3859         /**
3860          * Contact latest status update.
3861          * <p>Type: TEXT</p>
3862          */
3863         public static final String STATUS = "status";
3864 
3865         /**
3866          * @deprecated use {@link #STATUS}
3867          */
3868         @Deprecated
3869         public static final String PRESENCE_CUSTOM_STATUS = STATUS;
3870 
3871         /**
3872          * The absolute time in milliseconds when the latest status was inserted/updated.
3873          * <p>Type: NUMBER</p>
3874          */
3875         public static final String STATUS_TIMESTAMP = "status_ts";
3876 
3877         /**
3878          * The package containing resources for this status: label and icon.
3879          * <p>Type: TEXT</p>
3880          */
3881         public static final String STATUS_RES_PACKAGE = "status_res_package";
3882 
3883         /**
3884          * The resource ID of the label describing the source of the status update, e.g. "Google
3885          * Talk".  This resource should be scoped by the {@link #STATUS_RES_PACKAGE}.
3886          * <p>Type: NUMBER</p>
3887          */
3888         public static final String STATUS_LABEL = "status_label";
3889 
3890         /**
3891          * The resource ID of the icon for the source of the status update.
3892          * This resource should be scoped by the {@link #STATUS_RES_PACKAGE}.
3893          * <p>Type: NUMBER</p>
3894          */
3895         public static final String STATUS_ICON = "status_icon";
3896 
3897         /**
3898          * Contact's audio/video chat capability level.
3899          * <P>Type: INTEGER (one of the values below)</P>
3900          */
3901         public static final String CHAT_CAPABILITY = "chat_capability";
3902 
3903         /**
3904          * An allowed flag of {@link #CHAT_CAPABILITY}. Indicates audio-chat capability (microphone
3905          * and speaker)
3906          */
3907         public static final int CAPABILITY_HAS_VOICE = 1;
3908 
3909         /**
3910          * An allowed flag of {@link #CHAT_CAPABILITY}. Indicates that the contact's device can
3911          * display a video feed.
3912          */
3913         public static final int CAPABILITY_HAS_VIDEO = 2;
3914 
3915         /**
3916          * An allowed flag of {@link #CHAT_CAPABILITY}. Indicates that the contact's device has a
3917          * camera that can be used for video chat (e.g. a front-facing camera on a phone).
3918          */
3919         public static final int CAPABILITY_HAS_CAMERA = 4;
3920     }
3921 
3922     /**
3923      * <p>
3924      * Constants for the stream_items table, which contains social stream updates from
3925      * the user's contact list.
3926      * </p>
3927      * <p>
3928      * Only a certain number of stream items will ever be stored under a given raw contact.
3929      * Users of this API can query {@link ContactsContract.StreamItems#CONTENT_LIMIT_URI} to
3930      * determine this limit, and should restrict the number of items inserted in any given
3931      * transaction correspondingly.  Insertion of more items beyond the limit will
3932      * automatically lead to deletion of the oldest items, by {@link StreamItems#TIMESTAMP}.
3933      * </p>
3934      * <p>
3935      * Access to the social stream through these URIs requires additional permissions beyond the
3936      * read/write contact permissions required by the provider.  Querying for social stream data
3937      * requires android.permission.READ_SOCIAL_STREAM permission, and inserting or updating social
3938      * stream items requires android.permission.WRITE_SOCIAL_STREAM permission.
3939      * </p>
3940      * <h3>Account check</h3>
3941      * <p>
3942      * The content URIs to the insert, update and delete operations are required to have the account
3943      * information matching that of the owning raw contact as query parameters, namely
3944      * {@link RawContacts#ACCOUNT_TYPE} and {@link RawContacts#ACCOUNT_NAME}.
3945      * {@link RawContacts#DATA_SET} isn't required.
3946      * </p>
3947      * <h3>Operations</h3>
3948      * <dl>
3949      * <dt><b>Insert</b></dt>
3950      * <dd>
3951      * <p>Social stream updates are always associated with a raw contact.  There are a couple
3952      * of ways to insert these entries.
3953      * <dl>
3954      * <dt>Via the {@link RawContacts.StreamItems#CONTENT_DIRECTORY} sub-path of a raw contact:</dt>
3955      * <dd>
3956      * <pre>
3957      * ContentValues values = new ContentValues();
3958      * values.put(StreamItems.TEXT, "Breakfasted at Tiffanys");
3959      * values.put(StreamItems.TIMESTAMP, timestamp);
3960      * values.put(StreamItems.COMMENTS, "3 people reshared this");
3961      * Uri.Builder builder = RawContacts.CONTENT_URI.buildUpon();
3962      * ContentUris.appendId(builder, rawContactId);
3963      * builder.appendEncodedPath(RawContacts.StreamItems.CONTENT_DIRECTORY);
3964      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
3965      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
3966      * Uri streamItemUri = getContentResolver().insert(builder.build(), values);
3967      * long streamItemId = ContentUris.parseId(streamItemUri);
3968      * </pre>
3969      * </dd>
3970      * <dt>Via {@link StreamItems#CONTENT_URI}:</dt>
3971      * <dd>
3972      *<pre>
3973      * ContentValues values = new ContentValues();
3974      * values.put(StreamItems.RAW_CONTACT_ID, rawContactId);
3975      * values.put(StreamItems.TEXT, "Breakfasted at Tiffanys");
3976      * values.put(StreamItems.TIMESTAMP, timestamp);
3977      * values.put(StreamItems.COMMENTS, "3 people reshared this");
3978      * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
3979      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
3980      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
3981      * Uri streamItemUri = getContentResolver().insert(builder.build(), values);
3982      * long streamItemId = ContentUris.parseId(streamItemUri);
3983      *</pre>
3984      * </dd>
3985      * </dl>
3986      * </dd>
3987      * </p>
3988      * <p>
3989      * Once a {@link StreamItems} entry has been inserted, photos associated with that
3990      * social update can be inserted.  For example, after one of the insertions above,
3991      * photos could be added to the stream item in one of the following ways:
3992      * <dl>
3993      * <dt>Via a URI including the stream item ID:</dt>
3994      * <dd>
3995      * <pre>
3996      * values.clear();
3997      * values.put(StreamItemPhotos.SORT_INDEX, 1);
3998      * values.put(StreamItemPhotos.PHOTO, photoData);
3999      * getContentResolver().insert(Uri.withAppendedPath(
4000      *     ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId),
4001      *     StreamItems.StreamItemPhotos.CONTENT_DIRECTORY), values);
4002      * </pre>
4003      * </dd>
4004      * <dt>Via {@link ContactsContract.StreamItems#CONTENT_PHOTO_URI}:</dt>
4005      * <dd>
4006      * <pre>
4007      * values.clear();
4008      * values.put(StreamItemPhotos.STREAM_ITEM_ID, streamItemId);
4009      * values.put(StreamItemPhotos.SORT_INDEX, 1);
4010      * values.put(StreamItemPhotos.PHOTO, photoData);
4011      * getContentResolver().insert(StreamItems.CONTENT_PHOTO_URI, values);
4012      * </pre>
4013      * <p>Note that this latter form allows the insertion of a stream item and its
4014      * photos in a single transaction, by using {@link ContentProviderOperation} with
4015      * back references to populate the stream item ID in the {@link ContentValues}.
4016      * </dd>
4017      * </dl>
4018      * </p>
4019      * </dd>
4020      * <dt><b>Update</b></dt>
4021      * <dd>Updates can be performed by appending the stream item ID to the
4022      * {@link StreamItems#CONTENT_URI} URI.  Only social stream entries that were
4023      * created by the calling package can be updated.</dd>
4024      * <dt><b>Delete</b></dt>
4025      * <dd>Deletes can be performed by appending the stream item ID to the
4026      * {@link StreamItems#CONTENT_URI} URI.  Only social stream entries that were
4027      * created by the calling package can be deleted.</dd>
4028      * <dt><b>Query</b></dt>
4029      * <dl>
4030      * <dt>Finding all social stream updates for a given contact</dt>
4031      * <dd>By Contact ID:
4032      * <pre>
4033      * Cursor c = getContentResolver().query(Uri.withAppendedPath(
4034      *          ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
4035      *          Contacts.StreamItems.CONTENT_DIRECTORY),
4036      *          null, null, null, null);
4037      * </pre>
4038      * </dd>
4039      * <dd>By lookup key:
4040      * <pre>
4041      * Cursor c = getContentResolver().query(Contacts.CONTENT_URI.buildUpon()
4042      *          .appendPath(lookupKey)
4043      *          .appendPath(Contacts.StreamItems.CONTENT_DIRECTORY).build(),
4044      *          null, null, null, null);
4045      * </pre>
4046      * </dd>
4047      * <dt>Finding all social stream updates for a given raw contact</dt>
4048      * <dd>
4049      * <pre>
4050      * Cursor c = getContentResolver().query(Uri.withAppendedPath(
4051      *          ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
4052      *          RawContacts.StreamItems.CONTENT_DIRECTORY)),
4053      *          null, null, null, null);
4054      * </pre>
4055      * </dd>
4056      * <dt>Querying for a specific stream item by ID</dt>
4057      * <dd>
4058      * <pre>
4059      * Cursor c = getContentResolver().query(ContentUris.withAppendedId(
4060      *          StreamItems.CONTENT_URI, streamItemId),
4061      *          null, null, null, null);
4062      * </pre>
4063      * </dd>
4064      * </dl>
4065      *
4066      * @deprecated - Do not use. This will not be supported in the future. In the future,
4067      * cursors returned from related queries will be empty.
4068      *
4069      * @removed
4070      */
4071     @Deprecated
4072     public static final class StreamItems implements BaseColumns, StreamItemsColumns {
4073         /**
4074          * This utility class cannot be instantiated
4075          *
4076          * @deprecated - Do not use. This will not be supported in the future. In the future,
4077          * cursors returned from related queries will be empty.
4078          */
4079         @Deprecated
StreamItems()4080         private StreamItems() {
4081         }
4082 
4083         /**
4084          * The content:// style URI for this table, which handles social network stream
4085          * updates for the user's contacts.
4086          *
4087          * @deprecated - Do not use. This will not be supported in the future. In the future,
4088          * cursors returned from related queries will be empty.
4089          */
4090         @Deprecated
4091         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "stream_items");
4092 
4093         /**
4094          * <p>
4095          * A content:// style URI for the photos stored in a sub-table underneath
4096          * stream items.  This is only used for inserts, and updates - queries and deletes
4097          * for photos should be performed by appending
4098          * {@link StreamItems.StreamItemPhotos#CONTENT_DIRECTORY} path to URIs for a
4099          * specific stream item.
4100          * </p>
4101          * <p>
4102          * When using this URI, the stream item ID for the photo(s) must be identified
4103          * in the {@link ContentValues} passed in.
4104          * </p>
4105          *
4106          * @deprecated - Do not use. This will not be supported in the future. In the future,
4107          * cursors returned from related queries will be empty.
4108          */
4109         @Deprecated
4110         public static final Uri CONTENT_PHOTO_URI = Uri.withAppendedPath(CONTENT_URI, "photo");
4111 
4112         /**
4113          * This URI allows the caller to query for the maximum number of stream items
4114          * that will be stored under any single raw contact.
4115          *
4116          * @deprecated - Do not use. This will not be supported in the future. In the future,
4117          * cursors returned from related queries will be empty.
4118          */
4119         @Deprecated
4120         public static final Uri CONTENT_LIMIT_URI =
4121                 Uri.withAppendedPath(AUTHORITY_URI, "stream_items_limit");
4122 
4123         /**
4124          * The MIME type of a directory of stream items.
4125          *
4126          * @deprecated - Do not use. This will not be supported in the future. In the future,
4127          * cursors returned from related queries will be empty.
4128          */
4129         @Deprecated
4130         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item";
4131 
4132         /**
4133          * The MIME type of a single stream item.
4134          *
4135          * @deprecated - Do not use. This will not be supported in the future. In the future,
4136          * cursors returned from related queries will be empty.
4137          */
4138         @Deprecated
4139         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item";
4140 
4141         /**
4142          * Queries to {@link ContactsContract.StreamItems#CONTENT_LIMIT_URI} will
4143          * contain this column, with the value indicating the maximum number of
4144          * stream items that will be stored under any single raw contact.
4145          *
4146          * @deprecated - Do not use. This will not be supported in the future. In the future,
4147          * cursors returned from related queries will be empty.
4148          */
4149         @Deprecated
4150         public static final String MAX_ITEMS = "max_items";
4151 
4152         /**
4153          * <p>
4154          * A sub-directory of a single stream item entry that contains all of its
4155          * photo rows. To access this
4156          * directory append {@link StreamItems.StreamItemPhotos#CONTENT_DIRECTORY} to
4157          * an individual stream item URI.
4158          * </p>
4159          * <p>
4160          * Access to social stream photos requires additional permissions beyond the read/write
4161          * contact permissions required by the provider.  Querying for social stream photos
4162          * requires android.permission.READ_SOCIAL_STREAM permission, and inserting or updating
4163          * social stream photos requires android.permission.WRITE_SOCIAL_STREAM permission.
4164          * </p>
4165          *
4166          * @deprecated - Do not use. This will not be supported in the future. In the future,
4167          * cursors returned from related queries will be empty.
4168          *
4169          * @removed
4170          */
4171         @Deprecated
4172         public static final class StreamItemPhotos
4173                 implements BaseColumns, StreamItemPhotosColumns {
4174             /**
4175              * No public constructor since this is a utility class
4176              *
4177              * @deprecated - Do not use. This will not be supported in the future. In the future,
4178              * cursors returned from related queries will be empty.
4179              */
4180             @Deprecated
StreamItemPhotos()4181             private StreamItemPhotos() {
4182             }
4183 
4184             /**
4185              * The directory twig for this sub-table
4186              *
4187              * @deprecated - Do not use. This will not be supported in the future. In the future,
4188              * cursors returned from related queries will be empty.
4189              */
4190             @Deprecated
4191             public static final String CONTENT_DIRECTORY = "photo";
4192 
4193             /**
4194              * The MIME type of a directory of stream item photos.
4195              *
4196              * @deprecated - Do not use. This will not be supported in the future. In the future,
4197              * cursors returned from related queries will be empty.
4198              */
4199             @Deprecated
4200             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item_photo";
4201 
4202             /**
4203              * The MIME type of a single stream item photo.
4204              *
4205              * @deprecated - Do not use. This will not be supported in the future. In the future,
4206              * cursors returned from related queries will be empty.
4207              */
4208             @Deprecated
4209             public static final String CONTENT_ITEM_TYPE
4210                     = "vnd.android.cursor.item/stream_item_photo";
4211         }
4212     }
4213 
4214     /**
4215      * Columns in the StreamItems table.
4216      *
4217      * @see ContactsContract.StreamItems
4218      * @deprecated - Do not use. This will not be supported in the future. In the future,
4219      * cursors returned from related queries will be empty.
4220      *
4221      * @removed
4222      */
4223     @Deprecated
4224     protected interface StreamItemsColumns {
4225         /**
4226          * A reference to the {@link android.provider.ContactsContract.Contacts#_ID}
4227          * that this stream item belongs to.
4228          *
4229          * <p>Type: INTEGER</p>
4230          * <p>read-only</p>
4231          *
4232          * @deprecated - Do not use. This will not be supported in the future. In the future,
4233          * cursors returned from related queries will be empty.
4234          */
4235         @Deprecated
4236         public static final String CONTACT_ID = "contact_id";
4237 
4238         /**
4239          * A reference to the {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY}
4240          * that this stream item belongs to.
4241          *
4242          * <p>Type: TEXT</p>
4243          * <p>read-only</p>
4244          *
4245          * @deprecated - Do not use. This will not be supported in the future. In the future,
4246          * cursors returned from related queries will be empty.
4247          */
4248         @Deprecated
4249         public static final String CONTACT_LOOKUP_KEY = "contact_lookup";
4250 
4251         /**
4252          * A reference to the {@link RawContacts#_ID}
4253          * that this stream item belongs to.
4254          * <p>Type: INTEGER</p>
4255          *
4256          * @deprecated - Do not use. This will not be supported in the future. In the future,
4257          * cursors returned from related queries will be empty.
4258          */
4259         @Deprecated
4260         public static final String RAW_CONTACT_ID = "raw_contact_id";
4261 
4262         /**
4263          * The package name to use when creating {@link Resources} objects for
4264          * this stream item. This value is only designed for use when building
4265          * user interfaces, and should not be used to infer the owner.
4266          * <P>Type: TEXT</P>
4267          *
4268          * @deprecated - Do not use. This will not be supported in the future. In the future,
4269          * cursors returned from related queries will be empty.
4270          */
4271         @Deprecated
4272         public static final String RES_PACKAGE = "res_package";
4273 
4274         /**
4275          * The account type to which the raw_contact of this item is associated. See
4276          * {@link RawContacts#ACCOUNT_TYPE}
4277          *
4278          * <p>Type: TEXT</p>
4279          * <p>read-only</p>
4280          *
4281          * @deprecated - Do not use. This will not be supported in the future. In the future,
4282          * cursors returned from related queries will be empty.
4283          */
4284         @Deprecated
4285         public static final String ACCOUNT_TYPE = "account_type";
4286 
4287         /**
4288          * The account name to which the raw_contact of this item is associated. See
4289          * {@link RawContacts#ACCOUNT_NAME}
4290          *
4291          * <p>Type: TEXT</p>
4292          * <p>read-only</p>
4293          *
4294          * @deprecated - Do not use. This will not be supported in the future. In the future,
4295          * cursors returned from related queries will be empty.
4296          */
4297         @Deprecated
4298         public static final String ACCOUNT_NAME = "account_name";
4299 
4300         /**
4301          * The data set within the account that the raw_contact of this row belongs to. This allows
4302          * multiple sync adapters for the same account type to distinguish between
4303          * each others' data.
4304          * {@link RawContacts#DATA_SET}
4305          *
4306          * <P>Type: TEXT</P>
4307          * <p>read-only</p>
4308          *
4309          * @deprecated - Do not use. This will not be supported in the future. In the future,
4310          * cursors returned from related queries will be empty.
4311          */
4312         @Deprecated
4313         public static final String DATA_SET = "data_set";
4314 
4315         /**
4316          * The source_id of the raw_contact that this row belongs to.
4317          * {@link RawContacts#SOURCE_ID}
4318          *
4319          * <P>Type: TEXT</P>
4320          * <p>read-only</p>
4321          *
4322          * @deprecated - Do not use. This will not be supported in the future. In the future,
4323          * cursors returned from related queries will be empty.
4324          */
4325         @Deprecated
4326         public static final String RAW_CONTACT_SOURCE_ID = "raw_contact_source_id";
4327 
4328         /**
4329          * The resource name of the icon for the source of the stream item.
4330          * This resource should be scoped by the {@link #RES_PACKAGE}. As this can only reference
4331          * drawables, the "@drawable/" prefix must be omitted.
4332          * <P>Type: TEXT</P>
4333          *
4334          * @deprecated - Do not use. This will not be supported in the future. In the future,
4335          * cursors returned from related queries will be empty.
4336          */
4337         @Deprecated
4338         public static final String RES_ICON = "icon";
4339 
4340         /**
4341          * The resource name of the label describing the source of the status update, e.g. "Google
4342          * Talk". This resource should be scoped by the {@link #RES_PACKAGE}. As this can only
4343          * reference strings, the "@string/" prefix must be omitted.
4344          * <p>Type: TEXT</p>
4345          *
4346          * @deprecated - Do not use. This will not be supported in the future. In the future,
4347          * cursors returned from related queries will be empty.
4348          */
4349         @Deprecated
4350         public static final String RES_LABEL = "label";
4351 
4352         /**
4353          * <P>
4354          * The main textual contents of the item. Typically this is content
4355          * that was posted by the source of this stream item, but it can also
4356          * be a textual representation of an action (e.g. ”Checked in at Joe's”).
4357          * This text is displayed to the user and allows formatting and embedded
4358          * resource images via HTML (as parseable via
4359          * {@link android.text.Html#fromHtml}).
4360          * </P>
4361          * <P>
4362          * Long content may be truncated and/or ellipsized - the exact behavior
4363          * is unspecified, but it should not break tags.
4364          * </P>
4365          * <P>Type: TEXT</P>
4366          *
4367          * @deprecated - Do not use. This will not be supported in the future. In the future,
4368          * cursors returned from related queries will be empty.
4369          */
4370         @Deprecated
4371         public static final String TEXT = "text";
4372 
4373         /**
4374          * The absolute time (milliseconds since epoch) when this stream item was
4375          * inserted/updated.
4376          * <P>Type: NUMBER</P>
4377          *
4378          * @deprecated - Do not use. This will not be supported in the future. In the future,
4379          * cursors returned from related queries will be empty.
4380          */
4381         @Deprecated
4382         public static final String TIMESTAMP = "timestamp";
4383 
4384         /**
4385          * <P>
4386          * Summary information about the stream item, for example to indicate how
4387          * many people have reshared it, how many have liked it, how many thumbs
4388          * up and/or thumbs down it has, what the original source was, etc.
4389          * </P>
4390          * <P>
4391          * This text is displayed to the user and allows simple formatting via
4392          * HTML, in the same manner as {@link #TEXT} allows.
4393          * </P>
4394          * <P>
4395          * Long content may be truncated and/or ellipsized - the exact behavior
4396          * is unspecified, but it should not break tags.
4397          * </P>
4398          * <P>Type: TEXT</P>
4399          *
4400          * @deprecated - Do not use. This will not be supported in the future. In the future,
4401          * cursors returned from related queries will be empty.
4402          */
4403         @Deprecated
4404         public static final String COMMENTS = "comments";
4405 
4406         /**
4407          * Generic column for use by sync adapters.
4408          *
4409          * @deprecated - Do not use. This will not be supported in the future. In the future,
4410          * cursors returned from related queries will be empty.
4411          */
4412         @Deprecated
4413         public static final String SYNC1 = "stream_item_sync1";
4414         /**
4415          * Generic column for use by sync adapters.
4416          *
4417          * @deprecated - Do not use. This will not be supported in the future. In the future,
4418          * cursors returned from related queries will be empty.
4419          */
4420         @Deprecated
4421         public static final String SYNC2 = "stream_item_sync2";
4422         /**
4423          * Generic column for use by sync adapters.
4424          *
4425          * @deprecated - Do not use. This will not be supported in the future. In the future,
4426          * cursors returned from related queries will be empty.
4427          */
4428         @Deprecated
4429         public static final String SYNC3 = "stream_item_sync3";
4430         /**
4431          * Generic column for use by sync adapters.
4432          *
4433          * @deprecated - Do not use. This will not be supported in the future. In the future,
4434          * cursors returned from related queries will be empty.
4435          */
4436         @Deprecated
4437         public static final String SYNC4 = "stream_item_sync4";
4438     }
4439 
4440     /**
4441      * <p>
4442      * Constants for the stream_item_photos table, which contains photos associated with
4443      * social stream updates.
4444      * </p>
4445      * <p>
4446      * Access to social stream photos requires additional permissions beyond the read/write
4447      * contact permissions required by the provider.  Querying for social stream photos
4448      * requires android.permission.READ_SOCIAL_STREAM permission, and inserting or updating
4449      * social stream photos requires android.permission.WRITE_SOCIAL_STREAM permission.
4450      * </p>
4451      * <h3>Account check</h3>
4452      * <p>
4453      * The content URIs to the insert, update and delete operations are required to have the account
4454      * information matching that of the owning raw contact as query parameters, namely
4455      * {@link RawContacts#ACCOUNT_TYPE} and {@link RawContacts#ACCOUNT_NAME}.
4456      * {@link RawContacts#DATA_SET} isn't required.
4457      * </p>
4458      * <h3>Operations</h3>
4459      * <dl>
4460      * <dt><b>Insert</b></dt>
4461      * <dd>
4462      * <p>Social stream photo entries are associated with a social stream item.  Photos
4463      * can be inserted into a social stream item in a couple of ways:
4464      * <dl>
4465      * <dt>
4466      * Via the {@link StreamItems.StreamItemPhotos#CONTENT_DIRECTORY} sub-path of a
4467      * stream item:
4468      * </dt>
4469      * <dd>
4470      * <pre>
4471      * ContentValues values = new ContentValues();
4472      * values.put(StreamItemPhotos.SORT_INDEX, 1);
4473      * values.put(StreamItemPhotos.PHOTO, photoData);
4474      * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
4475      * ContentUris.appendId(builder, streamItemId);
4476      * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY);
4477      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
4478      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
4479      * Uri photoUri = getContentResolver().insert(builder.build(), values);
4480      * long photoId = ContentUris.parseId(photoUri);
4481      * </pre>
4482      * </dd>
4483      * <dt>Via the {@link ContactsContract.StreamItems#CONTENT_PHOTO_URI} URI:</dt>
4484      * <dd>
4485      * <pre>
4486      * ContentValues values = new ContentValues();
4487      * values.put(StreamItemPhotos.STREAM_ITEM_ID, streamItemId);
4488      * values.put(StreamItemPhotos.SORT_INDEX, 1);
4489      * values.put(StreamItemPhotos.PHOTO, photoData);
4490      * Uri.Builder builder = StreamItems.CONTENT_PHOTO_URI.buildUpon();
4491      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
4492      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
4493      * Uri photoUri = getContentResolver().insert(builder.build(), values);
4494      * long photoId = ContentUris.parseId(photoUri);
4495      * </pre>
4496      * </dd>
4497      * </dl>
4498      * </p>
4499      * </dd>
4500      * <dt><b>Update</b></dt>
4501      * <dd>
4502      * <p>Updates can only be made against a specific {@link StreamItemPhotos} entry,
4503      * identified by both the stream item ID it belongs to and the stream item photo ID.
4504      * This can be specified in two ways.
4505      * <dl>
4506      * <dt>Via the {@link StreamItems.StreamItemPhotos#CONTENT_DIRECTORY} sub-path of a
4507      * stream item:
4508      * </dt>
4509      * <dd>
4510      * <pre>
4511      * ContentValues values = new ContentValues();
4512      * values.put(StreamItemPhotos.PHOTO, newPhotoData);
4513      * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
4514      * ContentUris.appendId(builder, streamItemId);
4515      * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY);
4516      * ContentUris.appendId(builder, streamItemPhotoId);
4517      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
4518      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
4519      * getContentResolver().update(builder.build(), values, null, null);
4520      * </pre>
4521      * </dd>
4522      * <dt>Via the {@link ContactsContract.StreamItems#CONTENT_PHOTO_URI} URI:</dt>
4523      * <dd>
4524      * <pre>
4525      * ContentValues values = new ContentValues();
4526      * values.put(StreamItemPhotos.STREAM_ITEM_ID, streamItemId);
4527      * values.put(StreamItemPhotos.PHOTO, newPhotoData);
4528      * Uri.Builder builder = StreamItems.CONTENT_PHOTO_URI.buildUpon();
4529      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
4530      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
4531      * getContentResolver().update(builder.build(), values);
4532      * </pre>
4533      * </dd>
4534      * </dl>
4535      * </p>
4536      * </dd>
4537      * <dt><b>Delete</b></dt>
4538      * <dd>Deletes can be made against either a specific photo item in a stream item, or
4539      * against all or a selected subset of photo items under a stream item.
4540      * For example:
4541      * <dl>
4542      * <dt>Deleting a single photo via the
4543      * {@link StreamItems.StreamItemPhotos#CONTENT_DIRECTORY} sub-path of a stream item:
4544      * </dt>
4545      * <dd>
4546      * <pre>
4547      * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
4548      * ContentUris.appendId(builder, streamItemId);
4549      * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY);
4550      * ContentUris.appendId(builder, streamItemPhotoId);
4551      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
4552      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
4553      * getContentResolver().delete(builder.build(), null, null);
4554      * </pre>
4555      * </dd>
4556      * <dt>Deleting all photos under a stream item</dt>
4557      * <dd>
4558      * <pre>
4559      * Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
4560      * ContentUris.appendId(builder, streamItemId);
4561      * builder.appendEncodedPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY);
4562      * builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
4563      * builder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
4564      * getContentResolver().delete(builder.build(), null, null);
4565      * </pre>
4566      * </dd>
4567      * </dl>
4568      * </dd>
4569      * <dt><b>Query</b></dt>
4570      * <dl>
4571      * <dt>Querying for a specific photo in a stream item</dt>
4572      * <dd>
4573      * <pre>
4574      * Cursor c = getContentResolver().query(
4575      *     ContentUris.withAppendedId(
4576      *         Uri.withAppendedPath(
4577      *             ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId)
4578      *             StreamItems.StreamItemPhotos#CONTENT_DIRECTORY),
4579      *         streamItemPhotoId), null, null, null, null);
4580      * </pre>
4581      * </dd>
4582      * <dt>Querying for all photos in a stream item</dt>
4583      * <dd>
4584      * <pre>
4585      * Cursor c = getContentResolver().query(
4586      *     Uri.withAppendedPath(
4587      *         ContentUris.withAppendedId(StreamItems.CONTENT_URI, streamItemId)
4588      *         StreamItems.StreamItemPhotos#CONTENT_DIRECTORY),
4589      *     null, null, null, StreamItemPhotos.SORT_INDEX);
4590      * </pre>
4591      * </dl>
4592      * The record will contain both a {@link StreamItemPhotos#PHOTO_FILE_ID} and a
4593      * {@link StreamItemPhotos#PHOTO_URI}.  The {@link StreamItemPhotos#PHOTO_FILE_ID}
4594      * can be used in conjunction with the {@link ContactsContract.DisplayPhoto} API to
4595      * retrieve photo content, or you can open the {@link StreamItemPhotos#PHOTO_URI} as
4596      * an asset file, as follows:
4597      * <pre>
4598      * public InputStream openDisplayPhoto(String photoUri) {
4599      *     try {
4600      *         AssetFileDescriptor fd = getContentResolver().openAssetFileDescriptor(photoUri, "r");
4601      *         return fd.createInputStream();
4602      *     } catch (IOException e) {
4603      *         return null;
4604      *     }
4605      * }
4606      * <pre>
4607      * </dd>
4608      * </dl>
4609      *
4610      * @deprecated - Do not use. This will not be supported in the future. In the future,
4611      * cursors returned from related queries will be empty.
4612      *
4613      * @removed
4614      */
4615     @Deprecated
4616     public static final class StreamItemPhotos implements BaseColumns, StreamItemPhotosColumns {
4617         /**
4618          * No public constructor since this is a utility class
4619          *
4620          * @deprecated - Do not use. This will not be supported in the future. In the future,
4621          * cursors returned from related queries will be empty.
4622          */
4623         @Deprecated
StreamItemPhotos()4624         private StreamItemPhotos() {
4625         }
4626 
4627         /**
4628          * <p>
4629          * The binary representation of the photo.  Any size photo can be inserted;
4630          * the provider will resize it appropriately for storage and display.
4631          * </p>
4632          * <p>
4633          * This is only intended for use when inserting or updating a stream item photo.
4634          * To retrieve the photo that was stored, open {@link StreamItemPhotos#PHOTO_URI}
4635          * as an asset file.
4636          * </p>
4637          * <P>Type: BLOB</P>
4638          *
4639          * @deprecated - Do not use. This will not be supported in the future. In the future,
4640          * cursors returned from related queries will be empty.
4641          */
4642         @Deprecated
4643         public static final String PHOTO = "photo";
4644     }
4645 
4646     /**
4647      * Columns in the StreamItemPhotos table.
4648      *
4649      * @see ContactsContract.StreamItemPhotos
4650      * @deprecated - Do not use. This will not be supported in the future. In the future,
4651      * cursors returned from related queries will be empty.
4652      *
4653      * @removed
4654      */
4655     @Deprecated
4656     protected interface StreamItemPhotosColumns {
4657         /**
4658          * A reference to the {@link StreamItems#_ID} this photo is associated with.
4659          * <P>Type: NUMBER</P>
4660          *
4661          * @deprecated - Do not use. This will not be supported in the future. In the future,
4662          * cursors returned from related queries will be empty.
4663          */
4664         @Deprecated
4665         public static final String STREAM_ITEM_ID = "stream_item_id";
4666 
4667         /**
4668          * An integer to use for sort order for photos in the stream item.  If not
4669          * specified, the {@link StreamItemPhotos#_ID} will be used for sorting.
4670          * <P>Type: NUMBER</P>
4671          *
4672          * @deprecated - Do not use. This will not be supported in the future. In the future,
4673          * cursors returned from related queries will be empty.
4674          */
4675         @Deprecated
4676         public static final String SORT_INDEX = "sort_index";
4677 
4678         /**
4679          * Photo file ID for the photo.
4680          * See {@link ContactsContract.DisplayPhoto}.
4681          * <P>Type: NUMBER</P>
4682          *
4683          * @deprecated - Do not use. This will not be supported in the future. In the future,
4684          * cursors returned from related queries will be empty.
4685          */
4686         @Deprecated
4687         public static final String PHOTO_FILE_ID = "photo_file_id";
4688 
4689         /**
4690          * URI for retrieving the photo content, automatically populated.  Callers
4691          * may retrieve the photo content by opening this URI as an asset file.
4692          * <P>Type: TEXT</P>
4693          *
4694          * @deprecated - Do not use. This will not be supported in the future. In the future,
4695          * cursors returned from related queries will be empty.
4696          */
4697         @Deprecated
4698         public static final String PHOTO_URI = "photo_uri";
4699 
4700         /**
4701          * Generic column for use by sync adapters.
4702          *
4703          * @deprecated - Do not use. This will not be supported in the future. In the future,
4704          * cursors returned from related queries will be empty.
4705          */
4706         @Deprecated
4707         public static final String SYNC1 = "stream_item_photo_sync1";
4708         /**
4709          * Generic column for use by sync adapters.
4710          *
4711          * @deprecated - Do not use. This will not be supported in the future. In the future,
4712          * cursors returned from related queries will be empty.
4713          */
4714         @Deprecated
4715         public static final String SYNC2 = "stream_item_photo_sync2";
4716         /**
4717          * Generic column for use by sync adapters.
4718          *
4719          * @deprecated - Do not use. This will not be supported in the future. In the future,
4720          * cursors returned from related queries will be empty.
4721          */
4722         @Deprecated
4723         public static final String SYNC3 = "stream_item_photo_sync3";
4724         /**
4725          * Generic column for use by sync adapters.
4726          *
4727          * @deprecated - Do not use. This will not be supported in the future. In the future,
4728          * cursors returned from related queries will be empty.
4729          */
4730         @Deprecated
4731         public static final String SYNC4 = "stream_item_photo_sync4";
4732     }
4733 
4734     /**
4735      * <p>
4736      * Constants for the photo files table, which tracks metadata for hi-res photos
4737      * stored in the file system.
4738      * </p>
4739      *
4740      * @hide
4741      */
4742     public static final class PhotoFiles implements BaseColumns, PhotoFilesColumns {
4743         /**
4744          * No public constructor since this is a utility class
4745          */
PhotoFiles()4746         private PhotoFiles() {
4747         }
4748     }
4749 
4750     /**
4751      * Columns in the PhotoFiles table.
4752      *
4753      * @see ContactsContract.PhotoFiles
4754      *
4755      * @hide
4756      */
4757     protected interface PhotoFilesColumns {
4758 
4759         /**
4760          * The height, in pixels, of the photo this entry is associated with.
4761          * <P>Type: NUMBER</P>
4762          */
4763         public static final String HEIGHT = "height";
4764 
4765         /**
4766          * The width, in pixels, of the photo this entry is associated with.
4767          * <P>Type: NUMBER</P>
4768          */
4769         public static final String WIDTH = "width";
4770 
4771         /**
4772          * The size, in bytes, of the photo stored on disk.
4773          * <P>Type: NUMBER</P>
4774          */
4775         public static final String FILESIZE = "filesize";
4776     }
4777 
4778     /**
4779      * Columns in the Data table.
4780      *
4781      * @see ContactsContract.Data
4782      */
4783     protected interface DataColumns {
4784         /**
4785          * The package name to use when creating {@link Resources} objects for
4786          * this data row. This value is only designed for use when building user
4787          * interfaces, and should not be used to infer the owner.
4788          */
4789         public static final String RES_PACKAGE = "res_package";
4790 
4791         /**
4792          * The MIME type of the item represented by this row.
4793          */
4794         public static final String MIMETYPE = "mimetype";
4795 
4796         /**
4797          * Hash id on the data fields, used for backup and restore.
4798          *
4799          * @hide
4800          * @deprecated This column was never public since added. It will not be supported
4801          * as of Android version {@link android.os.Build.VERSION_CODES#R}.
4802          */
4803         @Deprecated
4804         public static final String HASH_ID = "hash_id";
4805 
4806         /**
4807          * A reference to the {@link RawContacts#_ID}
4808          * that this data belongs to.
4809          */
4810         public static final String RAW_CONTACT_ID = "raw_contact_id";
4811 
4812         /**
4813          * Whether this is the primary entry of its kind for the raw contact it belongs to.
4814          * <P>Type: INTEGER (if set, non-0 means true)</P>
4815          */
4816         public static final String IS_PRIMARY = "is_primary";
4817 
4818         /**
4819          * Whether this is the primary entry of its kind for the aggregate
4820          * contact it belongs to. Any data record that is "super primary" must
4821          * also be "primary".
4822          * <P>Type: INTEGER (if set, non-0 means true)</P>
4823          */
4824         public static final String IS_SUPER_PRIMARY = "is_super_primary";
4825 
4826         /**
4827          * The "read-only" flag: "0" by default, "1" if the row cannot be modified or
4828          * deleted except by a sync adapter.  See {@link ContactsContract#CALLER_IS_SYNCADAPTER}.
4829          * <P>Type: INTEGER</P>
4830          */
4831         public static final String IS_READ_ONLY = "is_read_only";
4832 
4833         /**
4834          * The version of this data record. This is a read-only value. The data column is
4835          * guaranteed to not change without the version going up. This value is monotonically
4836          * increasing.
4837          * <P>Type: INTEGER</P>
4838          */
4839         public static final String DATA_VERSION = "data_version";
4840 
4841         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4842         public static final String DATA1 = "data1";
4843         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4844         public static final String DATA2 = "data2";
4845         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4846         public static final String DATA3 = "data3";
4847         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4848         public static final String DATA4 = "data4";
4849         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4850         public static final String DATA5 = "data5";
4851         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4852         public static final String DATA6 = "data6";
4853         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4854         public static final String DATA7 = "data7";
4855         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4856         public static final String DATA8 = "data8";
4857         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4858         public static final String DATA9 = "data9";
4859         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4860         public static final String DATA10 = "data10";
4861         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4862         public static final String DATA11 = "data11";
4863         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4864         public static final String DATA12 = "data12";
4865         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4866         public static final String DATA13 = "data13";
4867         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
4868         public static final String DATA14 = "data14";
4869         /**
4870          * Generic data column, the meaning is {@link #MIMETYPE} specific. By convention,
4871          * this field is used to store BLOBs (binary data).
4872          */
4873         public static final String DATA15 = "data15";
4874 
4875         /** Generic column for use by sync adapters. */
4876         public static final String SYNC1 = "data_sync1";
4877         /** Generic column for use by sync adapters. */
4878         public static final String SYNC2 = "data_sync2";
4879         /** Generic column for use by sync adapters. */
4880         public static final String SYNC3 = "data_sync3";
4881         /** Generic column for use by sync adapters. */
4882         public static final String SYNC4 = "data_sync4";
4883 
4884         /**
4885          * Carrier presence information.
4886          * <P>
4887          * Type: INTEGER (A bitmask of CARRIER_PRESENCE_* fields)
4888          * </P>
4889          *
4890          * @deprecated The contacts database will only show presence
4891          * information on devices where
4892          * {@link android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL} is true,
4893          * otherwise use {@link android.telephony.ims.RcsUceAdapter}.
4894          */
4895         @Deprecated
4896         public static final String CARRIER_PRESENCE = "carrier_presence";
4897 
4898         /**
4899          * Indicates that the entry is Video Telephony (VT) capable on the
4900          * current carrier. An allowed bitmask of {@link #CARRIER_PRESENCE}.
4901          *
4902          * @deprecated Same as {@link DataColumns#CARRIER_PRESENCE}.
4903          *
4904          */
4905         @Deprecated
4906         public static final int CARRIER_PRESENCE_VT_CAPABLE = 0x01;
4907 
4908         /**
4909          * A reference to indicate whether phone account migration process is pending.
4910          *
4911          * Before Android 13, {@link PhoneAccountHandle#getId()} returns the ICCID for Telephony
4912          * PhoneAccountHandle. Starting from Android 13, {@link PhoneAccountHandle#getId()} returns
4913          * the Subscription ID for Telephony PhoneAccountHandle. A phone account migration process
4914          * is to ensure this PhoneAccountHandle migration process cross the Android versions in
4915          * the ContactsContract database.
4916          *
4917          * <p>Type: INTEGER</p>
4918          * @hide
4919          */
4920         String IS_PHONE_ACCOUNT_MIGRATION_PENDING = "is_preferred_phone_account_migration_pending";
4921 
4922         /**
4923          * The flattened {@link android.content.ComponentName} of a  {@link
4924          * android.telecom.PhoneAccountHandle} that is the preferred {@code PhoneAccountHandle} to
4925          * call the contact with.
4926          *
4927          * <p> On a multi-SIM device this field can be used in a {@link CommonDataKinds.Phone} row
4928          * to indicate the {@link PhoneAccountHandle} to call the number with, instead of using
4929          * {@link android.telecom.TelecomManager#getDefaultOutgoingPhoneAccount(String)} or asking
4930          * every time.
4931          *
4932          * <p>{@link android.telecom.TelecomManager#placeCall(Uri, android.os.Bundle)}
4933          * should be called with {@link android.telecom.TelecomManager#EXTRA_PHONE_ACCOUNT_HANDLE}
4934          * set to the {@link PhoneAccountHandle} using the {@link ComponentName} from this field.
4935          *
4936          * @see #PREFERRED_PHONE_ACCOUNT_ID
4937          * @see PhoneAccountHandle#getComponentName()
4938          * @see ComponentName#flattenToString()
4939          */
4940         String PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME = "preferred_phone_account_component_name";
4941 
4942         /**
4943          * The ID of a {@link
4944          * android.telecom.PhoneAccountHandle} that is the preferred {@code PhoneAccountHandle} to
4945          * call the contact with. Used by {@link CommonDataKinds.Phone}.
4946          *
4947          * <p> On a multi-SIM device this field can be used in a {@link CommonDataKinds.Phone} row
4948          * to indicate the {@link PhoneAccountHandle} to call the number with, instead of using
4949          * {@link android.telecom.TelecomManager#getDefaultOutgoingPhoneAccount(String)} or asking
4950          * every time.
4951          *
4952          * <p>{@link android.telecom.TelecomManager#placeCall(Uri, android.os.Bundle)}
4953          * should be called with {@link android.telecom.TelecomManager#EXTRA_PHONE_ACCOUNT_HANDLE}
4954          * set to the {@link PhoneAccountHandle} using the id from this field.
4955          *
4956          * @see #PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME
4957          * @see PhoneAccountHandle#getId()
4958          */
4959         String PREFERRED_PHONE_ACCOUNT_ID = "preferred_phone_account_id";
4960     }
4961 
4962     /**
4963      * Columns in the Data_Usage_Stat table
4964      */
4965     protected interface DataUsageStatColumns {
4966         /**
4967          * The last time (in milliseconds) this {@link Data} was used.
4968          * @deprecated Contacts affinity information is no longer supported as of
4969          * Android version {@link android.os.Build.VERSION_CODES#Q}.
4970          * This column always contains 0.
4971          *
4972          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
4973          * this field is obsolete, regardless of Android version. For more information, see the
4974          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
4975          * page.</p>
4976          */
4977         @Deprecated
4978         public static final String LAST_TIME_USED = "last_time_used";
4979 
4980         /**
4981          * The number of times the referenced {@link Data} has been used.
4982          * @deprecated Contacts affinity information is no longer supported as of
4983          * Android version {@link android.os.Build.VERSION_CODES#Q}.
4984          * This column always contains 0.
4985          *
4986          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
4987          * this field is obsolete, regardless of Android version. For more information, see the
4988          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
4989          * page.</p>
4990          */
4991         @Deprecated
4992         public static final String TIMES_USED = "times_used";
4993 
4994         /** @hide Raw value. */
4995         public static final String RAW_LAST_TIME_USED = HIDDEN_COLUMN_PREFIX + LAST_TIME_USED;
4996 
4997         /** @hide Raw value. */
4998         public static final String RAW_TIMES_USED = HIDDEN_COLUMN_PREFIX + TIMES_USED;
4999 
5000         /**
5001          * @hide
5002          * Low res version.  Same as {@link #LAST_TIME_USED} but use it in CP2 for clarification.
5003          */
5004         public static final String LR_LAST_TIME_USED = LAST_TIME_USED;
5005 
5006         /**
5007          * @hide
5008          * Low res version.  Same as {@link #TIMES_USED} but use it in CP2 for clarification.
5009          */
5010         public static final String LR_TIMES_USED = TIMES_USED;
5011     }
5012 
5013     /**
5014      * Combines all columns returned by {@link ContactsContract.Data} table queries.
5015      *
5016      * @see ContactsContract.Data
5017      */
5018     protected interface DataColumnsWithJoins extends BaseColumns, DataColumns, StatusColumns,
5019             RawContactsColumns, ContactsColumns, ContactNameColumns, ContactOptionsColumns,
5020             ContactStatusColumns, DataUsageStatColumns {
5021     }
5022 
5023     /**
5024      * <p>
5025      * Constants for the data table, which contains data points tied to a raw
5026      * contact.  Each row of the data table is typically used to store a single
5027      * piece of contact
5028      * information (such as a phone number) and its
5029      * associated metadata (such as whether it is a work or home number).
5030      * </p>
5031      * <h3>Data kinds</h3>
5032      * <p>
5033      * Data is a generic table that can hold any kind of contact data.
5034      * The kind of data stored in a given row is specified by the row's
5035      * {@link #MIMETYPE} value, which determines the meaning of the
5036      * generic columns {@link #DATA1} through
5037      * {@link #DATA15}.
5038      * For example, if the data kind is
5039      * {@link CommonDataKinds.Phone Phone.CONTENT_ITEM_TYPE}, then the column
5040      * {@link #DATA1} stores the
5041      * phone number, but if the data kind is
5042      * {@link CommonDataKinds.Email Email.CONTENT_ITEM_TYPE}, then {@link #DATA1}
5043      * stores the email address.
5044      * Sync adapters and applications can introduce their own data kinds.
5045      * </p>
5046      * <p>
5047      * ContactsContract defines a small number of pre-defined data kinds, e.g.
5048      * {@link CommonDataKinds.Phone}, {@link CommonDataKinds.Email} etc. As a
5049      * convenience, these classes define data kind specific aliases for DATA1 etc.
5050      * For example, {@link CommonDataKinds.Phone Phone.NUMBER} is the same as
5051      * {@link ContactsContract.Data Data.DATA1}.
5052      * </p>
5053      * <p>
5054      * {@link #DATA1} is an indexed column and should be used for the data element that is
5055      * expected to be most frequently used in query selections. For example, in the
5056      * case of a row representing email addresses {@link #DATA1} should probably
5057      * be used for the email address itself, while {@link #DATA2} etc can be
5058      * used for auxiliary information like type of email address.
5059      * <p>
5060      * <p>
5061      * By convention, {@link #DATA15} is used for storing BLOBs (binary data).
5062      * </p>
5063      * <p>
5064      * The sync adapter for a given account type must correctly handle every data type
5065      * used in the corresponding raw contacts.  Otherwise it could result in lost or
5066      * corrupted data.
5067      * </p>
5068      * <p>
5069      * Similarly, you should refrain from introducing new kinds of data for an other
5070      * party's account types. For example, if you add a data row for
5071      * "favorite song" to a raw contact owned by a Google account, it will not
5072      * get synced to the server, because the Google sync adapter does not know
5073      * how to handle this data kind. Thus new data kinds are typically
5074      * introduced along with new account types, i.e. new sync adapters.
5075      * </p>
5076      * <h3>Batch operations</h3>
5077      * <p>
5078      * Data rows can be inserted/updated/deleted using the traditional
5079      * {@link ContentResolver#insert}, {@link ContentResolver#update} and
5080      * {@link ContentResolver#delete} methods, however the newer mechanism based
5081      * on a batch of {@link ContentProviderOperation} will prove to be a better
5082      * choice in almost all cases. All operations in a batch are executed in a
5083      * single transaction, which ensures that the phone-side and server-side
5084      * state of a raw contact are always consistent. Also, the batch-based
5085      * approach is far more efficient: not only are the database operations
5086      * faster when executed in a single transaction, but also sending a batch of
5087      * commands to the content provider saves a lot of time on context switching
5088      * between your process and the process in which the content provider runs.
5089      * </p>
5090      * <p>
5091      * The flip side of using batched operations is that a large batch may lock
5092      * up the database for a long time preventing other applications from
5093      * accessing data and potentially causing ANRs ("Application Not Responding"
5094      * dialogs.)
5095      * </p>
5096      * <p>
5097      * To avoid such lockups of the database, make sure to insert "yield points"
5098      * in the batch. A yield point indicates to the content provider that before
5099      * executing the next operation it can commit the changes that have already
5100      * been made, yield to other requests, open another transaction and continue
5101      * processing operations. A yield point will not automatically commit the
5102      * transaction, but only if there is another request waiting on the
5103      * database. Normally a sync adapter should insert a yield point at the
5104      * beginning of each raw contact operation sequence in the batch. See
5105      * {@link ContentProviderOperation.Builder#withYieldAllowed(boolean)}.
5106      * </p>
5107      * <h3>Operations</h3>
5108      * <dl>
5109      * <dt><b>Insert</b></dt>
5110      * <dd>
5111      * <p>
5112      * An individual data row can be inserted using the traditional
5113      * {@link ContentResolver#insert(Uri, ContentValues)} method. Multiple rows
5114      * should always be inserted as a batch.
5115      * </p>
5116      * <p>
5117      * An example of a traditional insert:
5118      * <pre>
5119      * ContentValues values = new ContentValues();
5120      * values.put(Data.RAW_CONTACT_ID, rawContactId);
5121      * values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
5122      * values.put(Phone.NUMBER, "1-800-GOOG-411");
5123      * values.put(Phone.TYPE, Phone.TYPE_CUSTOM);
5124      * values.put(Phone.LABEL, "free directory assistance");
5125      * Uri dataUri = getContentResolver().insert(Data.CONTENT_URI, values);
5126      * </pre>
5127      * <p>
5128      * The same done using ContentProviderOperations:
5129      * <pre>
5130      * ArrayList&lt;ContentProviderOperation&gt; ops =
5131      *          new ArrayList&lt;ContentProviderOperation&gt;();
5132      *
5133      * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
5134      *          .withValue(Data.RAW_CONTACT_ID, rawContactId)
5135      *          .withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
5136      *          .withValue(Phone.NUMBER, "1-800-GOOG-411")
5137      *          .withValue(Phone.TYPE, Phone.TYPE_CUSTOM)
5138      *          .withValue(Phone.LABEL, "free directory assistance")
5139      *          .build());
5140      * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
5141      * </pre>
5142      * </p>
5143      * <dt><b>Update</b></dt>
5144      * <dd>
5145      * <p>
5146      * Just as with insert, update can be done incrementally or as a batch,
5147      * the batch mode being the preferred method:
5148      * <pre>
5149      * ArrayList&lt;ContentProviderOperation&gt; ops =
5150      *          new ArrayList&lt;ContentProviderOperation&gt;();
5151      *
5152      * ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)
5153      *          .withSelection(Data._ID + "=?", new String[]{String.valueOf(dataId)})
5154      *          .withValue(Email.DATA, "somebody@android.com")
5155      *          .build());
5156      * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
5157      * </pre>
5158      * </p>
5159      * </dd>
5160      * <dt><b>Delete</b></dt>
5161      * <dd>
5162      * <p>
5163      * Just as with insert and update, deletion can be done either using the
5164      * {@link ContentResolver#delete} method or using a ContentProviderOperation:
5165      * <pre>
5166      * ArrayList&lt;ContentProviderOperation&gt; ops =
5167      *          new ArrayList&lt;ContentProviderOperation&gt;();
5168      *
5169      * ops.add(ContentProviderOperation.newDelete(Data.CONTENT_URI)
5170      *          .withSelection(Data._ID + "=?", new String[]{String.valueOf(dataId)})
5171      *          .build());
5172      * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
5173      * </pre>
5174      * </p>
5175      * </dd>
5176      * <dt><b>Query</b></dt>
5177      * <dd>
5178      * <p>
5179      * <dl>
5180      * <dt>Finding all Data of a given type for a given contact</dt>
5181      * <dd>
5182      * <pre>
5183      * Cursor c = getContentResolver().query(Data.CONTENT_URI,
5184      *          new String[] {Data._ID, Phone.NUMBER, Phone.TYPE, Phone.LABEL},
5185      *          Data.CONTACT_ID + &quot;=?&quot; + " AND "
5186      *                  + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'",
5187      *          new String[] {String.valueOf(contactId)}, null);
5188      * </pre>
5189      * </p>
5190      * <p>
5191      * </dd>
5192      * <dt>Finding all Data of a given type for a given raw contact</dt>
5193      * <dd>
5194      * <pre>
5195      * Cursor c = getContentResolver().query(Data.CONTENT_URI,
5196      *          new String[] {Data._ID, Phone.NUMBER, Phone.TYPE, Phone.LABEL},
5197      *          Data.RAW_CONTACT_ID + &quot;=?&quot; + " AND "
5198      *                  + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'",
5199      *          new String[] {String.valueOf(rawContactId)}, null);
5200      * </pre>
5201      * </dd>
5202      * <dt>Finding all Data for a given raw contact</dt>
5203      * <dd>
5204      * Most sync adapters will want to read all data rows for a raw contact
5205      * along with the raw contact itself.  For that you should use the
5206      * {@link RawContactsEntity}. See also {@link RawContacts}.
5207      * </dd>
5208      * </dl>
5209      * </p>
5210      * </dd>
5211      * </dl>
5212      * <h2>Columns</h2>
5213      * <p>
5214      * Many columns are available via a {@link Data#CONTENT_URI} query.  For best performance you
5215      * should explicitly specify a projection to only those columns that you need.
5216      * </p>
5217      * <table class="jd-sumtable">
5218      * <tr>
5219      * <th colspan='4'>Data</th>
5220      * </tr>
5221      * <tr>
5222      * <td style="width: 7em;">long</td>
5223      * <td style="width: 20em;">{@link #_ID}</td>
5224      * <td style="width: 5em;">read-only</td>
5225      * <td>Row ID. Sync adapter should try to preserve row IDs during updates. In other words,
5226      * it would be a bad idea to delete and reinsert a data row. A sync adapter should
5227      * always do an update instead.</td>
5228      * </tr>
5229      * <tr>
5230      * <td>String</td>
5231      * <td>{@link #MIMETYPE}</td>
5232      * <td>read/write-once</td>
5233      * <td>
5234      * <p>The MIME type of the item represented by this row. Examples of common
5235      * MIME types are:
5236      * <ul>
5237      * <li>{@link CommonDataKinds.StructuredName StructuredName.CONTENT_ITEM_TYPE}</li>
5238      * <li>{@link CommonDataKinds.Phone Phone.CONTENT_ITEM_TYPE}</li>
5239      * <li>{@link CommonDataKinds.Email Email.CONTENT_ITEM_TYPE}</li>
5240      * <li>{@link CommonDataKinds.Photo Photo.CONTENT_ITEM_TYPE}</li>
5241      * <li>{@link CommonDataKinds.Organization Organization.CONTENT_ITEM_TYPE}</li>
5242      * <li>{@link CommonDataKinds.Im Im.CONTENT_ITEM_TYPE}</li>
5243      * <li>{@link CommonDataKinds.Nickname Nickname.CONTENT_ITEM_TYPE}</li>
5244      * <li>{@link CommonDataKinds.Note Note.CONTENT_ITEM_TYPE}</li>
5245      * <li>{@link CommonDataKinds.StructuredPostal StructuredPostal.CONTENT_ITEM_TYPE}</li>
5246      * <li>{@link CommonDataKinds.GroupMembership GroupMembership.CONTENT_ITEM_TYPE}</li>
5247      * <li>{@link CommonDataKinds.Website Website.CONTENT_ITEM_TYPE}</li>
5248      * <li>{@link CommonDataKinds.Event Event.CONTENT_ITEM_TYPE}</li>
5249      * <li>{@link CommonDataKinds.Relation Relation.CONTENT_ITEM_TYPE}</li>
5250      * <li>{@link CommonDataKinds.SipAddress SipAddress.CONTENT_ITEM_TYPE}</li>
5251      * </ul>
5252      * </p>
5253      * </td>
5254      * </tr>
5255      * <tr>
5256      * <td>long</td>
5257      * <td>{@link #RAW_CONTACT_ID}</td>
5258      * <td>read/write-once</td>
5259      * <td>The id of the row in the {@link RawContacts} table that this data belongs to.</td>
5260      * </tr>
5261      * <tr>
5262      * <td>int</td>
5263      * <td>{@link #IS_PRIMARY}</td>
5264      * <td>read/write</td>
5265      * <td>Whether this is the primary entry of its kind for the raw contact it belongs to.
5266      * "1" if true, "0" if false.
5267      * </td>
5268      * </tr>
5269      * <tr>
5270      * <td>int</td>
5271      * <td>{@link #IS_SUPER_PRIMARY}</td>
5272      * <td>read/write</td>
5273      * <td>Whether this is the primary entry of its kind for the aggregate
5274      * contact it belongs to. Any data record that is "super primary" must
5275      * also be "primary".  For example, the super-primary entry may be
5276      * interpreted as the default contact value of its kind (for example,
5277      * the default phone number to use for the contact).</td>
5278      * </tr>
5279      * <tr>
5280      * <td>int</td>
5281      * <td>{@link #DATA_VERSION}</td>
5282      * <td>read-only</td>
5283      * <td>The version of this data record. Whenever the data row changes
5284      * the version goes up. This value is monotonically increasing.</td>
5285      * </tr>
5286      * <tr>
5287      * <td>Any type</td>
5288      * <td>
5289      * {@link #DATA1}<br>
5290      * {@link #DATA2}<br>
5291      * {@link #DATA3}<br>
5292      * {@link #DATA4}<br>
5293      * {@link #DATA5}<br>
5294      * {@link #DATA6}<br>
5295      * {@link #DATA7}<br>
5296      * {@link #DATA8}<br>
5297      * {@link #DATA9}<br>
5298      * {@link #DATA10}<br>
5299      * {@link #DATA11}<br>
5300      * {@link #DATA12}<br>
5301      * {@link #DATA13}<br>
5302      * {@link #DATA14}<br>
5303      * {@link #DATA15}
5304      * </td>
5305      * <td>read/write</td>
5306      * <td>
5307      * <p>
5308      * Generic data columns.  The meaning of each column is determined by the
5309      * {@link #MIMETYPE}.  By convention, {@link #DATA15} is used for storing
5310      * BLOBs (binary data).
5311      * </p>
5312      * <p>
5313      * Data columns whose meaning is not explicitly defined for a given MIMETYPE
5314      * should not be used.  There is no guarantee that any sync adapter will
5315      * preserve them.  Sync adapters themselves should not use such columns either,
5316      * but should instead use {@link #SYNC1}-{@link #SYNC4}.
5317      * </p>
5318      * </td>
5319      * </tr>
5320      * <tr>
5321      * <td>Any type</td>
5322      * <td>
5323      * {@link #SYNC1}<br>
5324      * {@link #SYNC2}<br>
5325      * {@link #SYNC3}<br>
5326      * {@link #SYNC4}
5327      * </td>
5328      * <td>read/write</td>
5329      * <td>Generic columns for use by sync adapters. For example, a Photo row
5330      * may store the image URL in SYNC1, a status (not loaded, loading, loaded, error)
5331      * in SYNC2, server-side version number in SYNC3 and error code in SYNC4.</td>
5332      * </tr>
5333      * </table>
5334      *
5335      * <p>
5336      * Some columns from the most recent associated status update are also available
5337      * through an implicit join.
5338      * </p>
5339      * <table class="jd-sumtable">
5340      * <tr>
5341      * <th colspan='4'>Join with {@link StatusUpdates}</th>
5342      * </tr>
5343      * <tr>
5344      * <td style="width: 7em;">int</td>
5345      * <td style="width: 20em;">{@link #PRESENCE}</td>
5346      * <td style="width: 5em;">read-only</td>
5347      * <td>IM presence status linked to this data row. Compare with
5348      * {@link #CONTACT_PRESENCE}, which contains the contact's presence across
5349      * all IM rows. See {@link StatusUpdates} for individual status definitions.
5350      * The provider may choose not to store this value
5351      * in persistent storage. The expectation is that presence status will be
5352      * updated on a regular basis.
5353      * </td>
5354      * </tr>
5355      * <tr>
5356      * <td>String</td>
5357      * <td>{@link #STATUS}</td>
5358      * <td>read-only</td>
5359      * <td>Latest status update linked with this data row.</td>
5360      * </tr>
5361      * <tr>
5362      * <td>long</td>
5363      * <td>{@link #STATUS_TIMESTAMP}</td>
5364      * <td>read-only</td>
5365      * <td>The absolute time in milliseconds when the latest status was
5366      * inserted/updated for this data row.</td>
5367      * </tr>
5368      * <tr>
5369      * <td>String</td>
5370      * <td>{@link #STATUS_RES_PACKAGE}</td>
5371      * <td>read-only</td>
5372      * <td>The package containing resources for this status: label and icon.</td>
5373      * </tr>
5374      * <tr>
5375      * <td>long</td>
5376      * <td>{@link #STATUS_LABEL}</td>
5377      * <td>read-only</td>
5378      * <td>The resource ID of the label describing the source of status update linked
5379      * to this data row. This resource is scoped by the {@link #STATUS_RES_PACKAGE}.</td>
5380      * </tr>
5381      * <tr>
5382      * <td>long</td>
5383      * <td>{@link #STATUS_ICON}</td>
5384      * <td>read-only</td>
5385      * <td>The resource ID of the icon for the source of the status update linked
5386      * to this data row. This resource is scoped by the {@link #STATUS_RES_PACKAGE}.</td>
5387      * </tr>
5388      * </table>
5389      *
5390      * <p>
5391      * Some columns from the associated raw contact are also available through an
5392      * implicit join.  The other columns are excluded as uninteresting in this
5393      * context.
5394      * </p>
5395      *
5396      * <table class="jd-sumtable">
5397      * <tr>
5398      * <th colspan='4'>Join with {@link ContactsContract.RawContacts}</th>
5399      * </tr>
5400      * <tr>
5401      * <td style="width: 7em;">long</td>
5402      * <td style="width: 20em;">{@link #CONTACT_ID}</td>
5403      * <td style="width: 5em;">read-only</td>
5404      * <td>The id of the row in the {@link Contacts} table that this data belongs
5405      * to.</td>
5406      * </tr>
5407      * <tr>
5408      * <td>int</td>
5409      * <td>{@link #AGGREGATION_MODE}</td>
5410      * <td>read-only</td>
5411      * <td>See {@link RawContacts}.</td>
5412      * </tr>
5413      * <tr>
5414      * <td>int</td>
5415      * <td>{@link #DELETED}</td>
5416      * <td>read-only</td>
5417      * <td>See {@link RawContacts}.</td>
5418      * </tr>
5419      * </table>
5420      *
5421      * <p>
5422      * The ID column for the associated aggregated contact table
5423      * {@link ContactsContract.Contacts} is available
5424      * via the implicit join to the {@link RawContacts} table, see above.
5425      * The remaining columns from this table are also
5426      * available, through an implicit join.  This
5427      * facilitates lookup by
5428      * the value of a single data element, such as the email address.
5429      * </p>
5430      *
5431      * <table class="jd-sumtable">
5432      * <tr>
5433      * <th colspan='4'>Join with {@link ContactsContract.Contacts}</th>
5434      * </tr>
5435      * <tr>
5436      * <td style="width: 7em;">String</td>
5437      * <td style="width: 20em;">{@link #LOOKUP_KEY}</td>
5438      * <td style="width: 5em;">read-only</td>
5439      * <td>See {@link ContactsContract.Contacts}</td>
5440      * </tr>
5441      * <tr>
5442      * <td>String</td>
5443      * <td>{@link #DISPLAY_NAME}</td>
5444      * <td>read-only</td>
5445      * <td>See {@link ContactsContract.Contacts}</td>
5446      * </tr>
5447      * <tr>
5448      * <td>long</td>
5449      * <td>{@link #PHOTO_ID}</td>
5450      * <td>read-only</td>
5451      * <td>See {@link ContactsContract.Contacts}.</td>
5452      * </tr>
5453      * <tr>
5454      * <td>int</td>
5455      * <td>{@link #IN_VISIBLE_GROUP}</td>
5456      * <td>read-only</td>
5457      * <td>See {@link ContactsContract.Contacts}.</td>
5458      * </tr>
5459      * <tr>
5460      * <td>int</td>
5461      * <td>{@link #HAS_PHONE_NUMBER}</td>
5462      * <td>read-only</td>
5463      * <td>See {@link ContactsContract.Contacts}.</td>
5464      * </tr>
5465      * <tr>
5466      * <td>int</td>
5467      * <td>{@link #STARRED}</td>
5468      * <td>read-only</td>
5469      * <td>See {@link ContactsContract.Contacts}.</td>
5470      * </tr>
5471      * <tr>
5472      * <td>String</td>
5473      * <td>{@link #CUSTOM_RINGTONE}</td>
5474      * <td>read-only</td>
5475      * <td>See {@link ContactsContract.Contacts}.</td>
5476      * </tr>
5477      * <tr>
5478      * <td>int</td>
5479      * <td>{@link #SEND_TO_VOICEMAIL}</td>
5480      * <td>read-only</td>
5481      * <td>See {@link ContactsContract.Contacts}.</td>
5482      * </tr>
5483      * <tr>
5484      * <td>int</td>
5485      * <td>{@link #CONTACT_PRESENCE}</td>
5486      * <td>read-only</td>
5487      * <td>See {@link ContactsContract.Contacts}.</td>
5488      * </tr>
5489      * <tr>
5490      * <td>String</td>
5491      * <td>{@link #CONTACT_STATUS}</td>
5492      * <td>read-only</td>
5493      * <td>See {@link ContactsContract.Contacts}.</td>
5494      * </tr>
5495      * <tr>
5496      * <td>long</td>
5497      * <td>{@link #CONTACT_STATUS_TIMESTAMP}</td>
5498      * <td>read-only</td>
5499      * <td>See {@link ContactsContract.Contacts}.</td>
5500      * </tr>
5501      * <tr>
5502      * <td>String</td>
5503      * <td>{@link #CONTACT_STATUS_RES_PACKAGE}</td>
5504      * <td>read-only</td>
5505      * <td>See {@link ContactsContract.Contacts}.</td>
5506      * </tr>
5507      * <tr>
5508      * <td>long</td>
5509      * <td>{@link #CONTACT_STATUS_LABEL}</td>
5510      * <td>read-only</td>
5511      * <td>See {@link ContactsContract.Contacts}.</td>
5512      * </tr>
5513      * <tr>
5514      * <td>long</td>
5515      * <td>{@link #CONTACT_STATUS_ICON}</td>
5516      * <td>read-only</td>
5517      * <td>See {@link ContactsContract.Contacts}.</td>
5518      * </tr>
5519      * </table>
5520      */
5521     public final static class Data implements DataColumnsWithJoins, ContactCounts {
5522         /**
5523          * This utility class cannot be instantiated
5524          */
Data()5525         private Data() {}
5526 
5527         /**
5528          * The content:// style URI for this table, which requests a directory
5529          * of data rows matching the selection criteria.
5530          */
5531         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "data");
5532 
5533         /**
5534         * The content:// style URI for this table in managed profile, which requests a directory
5535         * of data rows matching the selection criteria.
5536         *
5537         * @hide
5538         */
5539         static final Uri ENTERPRISE_CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
5540                 "data_enterprise");
5541 
5542         /**
5543          * A boolean parameter for {@link Data#CONTENT_URI}.
5544          * This specifies whether or not the returned data items should be filtered to show
5545          * data items belonging to visible contacts only.
5546          */
5547         public static final String VISIBLE_CONTACTS_ONLY = "visible_contacts_only";
5548 
5549         /**
5550          * The MIME type of the results from {@link #CONTENT_URI}.
5551          */
5552         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/data";
5553 
5554         /**
5555          * <p>
5556          * Build a {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}
5557          * style {@link Uri} for the parent {@link android.provider.ContactsContract.Contacts}
5558          * entry of the given {@link ContactsContract.Data} entry.
5559          * </p>
5560          * <p>
5561          * Returns the Uri for the contact in the first entry returned by
5562          * {@link ContentResolver#query(Uri, String[], String, String[], String)}
5563          * for the provided {@code dataUri}.  If the query returns null or empty
5564          * results, silently returns null.
5565          * </p>
5566          */
getContactLookupUri(ContentResolver resolver, Uri dataUri)5567         public static Uri getContactLookupUri(ContentResolver resolver, Uri dataUri) {
5568             final Cursor cursor = resolver.query(dataUri, new String[] {
5569                     RawContacts.CONTACT_ID, Contacts.LOOKUP_KEY
5570             }, null, null, null);
5571 
5572             Uri lookupUri = null;
5573             try {
5574                 if (cursor != null && cursor.moveToFirst()) {
5575                     final long contactId = cursor.getLong(0);
5576                     final String lookupKey = cursor.getString(1);
5577                     return Contacts.getLookupUri(contactId, lookupKey);
5578                 }
5579             } finally {
5580                 if (cursor != null) cursor.close();
5581             }
5582             return lookupUri;
5583         }
5584     }
5585 
5586     /**
5587      * <p>
5588      * Constants for the raw contacts entities table, which can be thought of as
5589      * an outer join of the raw_contacts table with the data table.  It is a strictly
5590      * read-only table.
5591      * </p>
5592      * <p>
5593      * If a raw contact has data rows, the RawContactsEntity cursor will contain
5594      * a one row for each data row. If the raw contact has no data rows, the
5595      * cursor will still contain one row with the raw contact-level information
5596      * and nulls for data columns.
5597      *
5598      * <pre>
5599      * Uri entityUri = ContentUris.withAppendedId(RawContactsEntity.CONTENT_URI, rawContactId);
5600      * Cursor c = getContentResolver().query(entityUri,
5601      *          new String[]{
5602      *              RawContactsEntity.SOURCE_ID,
5603      *              RawContactsEntity.DATA_ID,
5604      *              RawContactsEntity.MIMETYPE,
5605      *              RawContactsEntity.DATA1
5606      *          }, null, null, null);
5607      * try {
5608      *     while (c.moveToNext()) {
5609      *         String sourceId = c.getString(0);
5610      *         if (!c.isNull(1)) {
5611      *             String mimeType = c.getString(2);
5612      *             String data = c.getString(3);
5613      *             ...
5614      *         }
5615      *     }
5616      * } finally {
5617      *     c.close();
5618      * }
5619      * </pre>
5620      *
5621      * <h3>Columns</h3>
5622      * RawContactsEntity has a combination of RawContact and Data columns.
5623      *
5624      * <table class="jd-sumtable">
5625      * <tr>
5626      * <th colspan='4'>RawContacts</th>
5627      * </tr>
5628      * <tr>
5629      * <td style="width: 7em;">long</td>
5630      * <td style="width: 20em;">{@link #_ID}</td>
5631      * <td style="width: 5em;">read-only</td>
5632      * <td>Raw contact row ID. See {@link RawContacts}.</td>
5633      * </tr>
5634      * <tr>
5635      * <td>long</td>
5636      * <td>{@link #CONTACT_ID}</td>
5637      * <td>read-only</td>
5638      * <td>See {@link RawContacts}.</td>
5639      * </tr>
5640      * <tr>
5641      * <td>int</td>
5642      * <td>{@link #AGGREGATION_MODE}</td>
5643      * <td>read-only</td>
5644      * <td>See {@link RawContacts}.</td>
5645      * </tr>
5646      * <tr>
5647      * <td>int</td>
5648      * <td>{@link #DELETED}</td>
5649      * <td>read-only</td>
5650      * <td>See {@link RawContacts}.</td>
5651      * </tr>
5652      * </table>
5653      *
5654      * <table class="jd-sumtable">
5655      * <tr>
5656      * <th colspan='4'>Data</th>
5657      * </tr>
5658      * <tr>
5659      * <td style="width: 7em;">long</td>
5660      * <td style="width: 20em;">{@link #DATA_ID}</td>
5661      * <td style="width: 5em;">read-only</td>
5662      * <td>Data row ID. It will be null if the raw contact has no data rows.</td>
5663      * </tr>
5664      * <tr>
5665      * <td>String</td>
5666      * <td>{@link #MIMETYPE}</td>
5667      * <td>read-only</td>
5668      * <td>See {@link ContactsContract.Data}.</td>
5669      * </tr>
5670      * <tr>
5671      * <td>int</td>
5672      * <td>{@link #IS_PRIMARY}</td>
5673      * <td>read-only</td>
5674      * <td>See {@link ContactsContract.Data}.</td>
5675      * </tr>
5676      * <tr>
5677      * <td>int</td>
5678      * <td>{@link #IS_SUPER_PRIMARY}</td>
5679      * <td>read-only</td>
5680      * <td>See {@link ContactsContract.Data}.</td>
5681      * </tr>
5682      * <tr>
5683      * <td>int</td>
5684      * <td>{@link #DATA_VERSION}</td>
5685      * <td>read-only</td>
5686      * <td>See {@link ContactsContract.Data}.</td>
5687      * </tr>
5688      * <tr>
5689      * <td>Any type</td>
5690      * <td>
5691      * {@link #DATA1}<br>
5692      * {@link #DATA2}<br>
5693      * {@link #DATA3}<br>
5694      * {@link #DATA4}<br>
5695      * {@link #DATA5}<br>
5696      * {@link #DATA6}<br>
5697      * {@link #DATA7}<br>
5698      * {@link #DATA8}<br>
5699      * {@link #DATA9}<br>
5700      * {@link #DATA10}<br>
5701      * {@link #DATA11}<br>
5702      * {@link #DATA12}<br>
5703      * {@link #DATA13}<br>
5704      * {@link #DATA14}<br>
5705      * {@link #DATA15}
5706      * </td>
5707      * <td>read-only</td>
5708      * <td>See {@link ContactsContract.Data}.</td>
5709      * </tr>
5710      * <tr>
5711      * <td>Any type</td>
5712      * <td>
5713      * {@link #SYNC1}<br>
5714      * {@link #SYNC2}<br>
5715      * {@link #SYNC3}<br>
5716      * {@link #SYNC4}
5717      * </td>
5718      * <td>read-only</td>
5719      * <td>See {@link ContactsContract.Data}.</td>
5720      * </tr>
5721      * </table>
5722      */
5723     public final static class RawContactsEntity
5724             implements BaseColumns, DataColumns, RawContactsColumns {
5725         private static final String TAG = "ContactsContract.RawContactsEntity";
5726 
5727         /**
5728          * This utility class cannot be instantiated
5729          */
RawContactsEntity()5730         private RawContactsEntity() {}
5731 
5732         /**
5733          * The content:// style URI for this table
5734          */
5735         public static final Uri CONTENT_URI =
5736                 Uri.withAppendedPath(AUTHORITY_URI, "raw_contact_entities");
5737 
5738         /**
5739         * The content:// style URI for this table in the managed profile
5740         *
5741         * @hide
5742         */
5743         @TestApi
5744         public static final Uri CORP_CONTENT_URI =
5745                 Uri.withAppendedPath(AUTHORITY_URI, "raw_contact_entities_corp");
5746 
5747         /**
5748          * The content:// style URI for this table, specific to the user's profile.
5749          */
5750         public static final Uri PROFILE_CONTENT_URI =
5751                 Uri.withAppendedPath(Profile.CONTENT_URI, "raw_contact_entities");
5752 
5753         /**
5754          * The MIME type of {@link #CONTENT_URI} providing a directory of raw contact entities.
5755          */
5756         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact_entity";
5757 
5758         /**
5759          * If {@link #FOR_EXPORT_ONLY} is explicitly set to "1", returned Cursor toward
5760          * Data.CONTENT_URI contains only exportable data.
5761          *
5762          * This flag is useful (currently) only for vCard exporter in Contacts app, which
5763          * needs to exclude "un-exportable" data from available data to export, while
5764          * Contacts app itself has priviledge to access all data including "un-expotable"
5765          * ones and providers return all of them regardless of the callers' intention.
5766          * <P>Type: INTEGER</p>
5767          *
5768          * @hide Maybe available only in Eclair and not really ready for public use.
5769          * TODO: remove, or implement this feature completely. As of now (Eclair),
5770          * we only use this flag in queryEntities(), not query().
5771          */
5772         public static final String FOR_EXPORT_ONLY = "for_export_only";
5773 
5774         /**
5775          * The ID of the data column. The value will be null if this raw contact has no data rows.
5776          * <P>Type: INTEGER</P>
5777          */
5778         public static final String DATA_ID = "data_id";
5779 
5780         /**
5781          * Query raw contacts entity by a contact ID, which can potentially be a managed profile
5782          * contact ID.
5783          * <p>
5784          * @param contentResolver The content resolver to query
5785          * @param contactId Contact ID, which can potentially be a managed profile contact ID.
5786          * @return A map from a mimetype to a list of the entity content values.
5787          *
5788          * {@hide}
5789          */
5790         @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
5791         @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
queryRawContactEntity( @onNull ContentResolver contentResolver, long contactId)5792         public static @NonNull Map<String, List<ContentValues>> queryRawContactEntity(
5793                 @NonNull ContentResolver contentResolver, long contactId) {
5794             Uri uri = RawContactsEntity.CONTENT_URI;
5795             long realContactId = contactId;
5796 
5797             if (Contacts.isEnterpriseContactId(contactId)) {
5798                 uri = RawContactsEntity.CORP_CONTENT_URI;
5799                 realContactId = contactId - Contacts.ENTERPRISE_CONTACT_ID_BASE;
5800             }
5801             final Map<String, List<ContentValues>> contentValuesListMap =
5802                     new HashMap<String, List<ContentValues>>();
5803             // The resolver may return the entity iterator with no data. It is possible.
5804             // e.g. If all the data in the contact of the given contact id are not exportable ones,
5805             //      they are hidden from the view of this method, though contact id itself exists.
5806             EntityIterator entityIterator = null;
5807             try {
5808                 final String selection = Data.CONTACT_ID + "=?";
5809                 final String[] selectionArgs = new String[] {String.valueOf(realContactId)};
5810 
5811                 entityIterator = RawContacts.newEntityIterator(contentResolver.query(
5812                             uri, null, selection, selectionArgs, null));
5813 
5814                 if (entityIterator == null) {
5815                     Log.e(TAG, "EntityIterator is null");
5816                     return contentValuesListMap;
5817                 }
5818 
5819                 if (!entityIterator.hasNext()) {
5820                     Log.w(TAG, "Data does not exist. contactId: " + realContactId);
5821                     return contentValuesListMap;
5822                 }
5823 
5824                 while (entityIterator.hasNext()) {
5825                     Entity entity = entityIterator.next();
5826                     for (NamedContentValues namedContentValues : entity.getSubValues()) {
5827                         ContentValues contentValues = namedContentValues.values;
5828                         String key = contentValues.getAsString(Data.MIMETYPE);
5829                         if (key != null) {
5830                             List<ContentValues> contentValuesList = contentValuesListMap.get(key);
5831                             if (contentValuesList == null) {
5832                                 contentValuesList = new ArrayList<ContentValues>();
5833                                 contentValuesListMap.put(key, contentValuesList);
5834                             }
5835                             contentValuesList.add(contentValues);
5836                         }
5837                     }
5838                 }
5839             } finally {
5840                 if (entityIterator != null) {
5841                     entityIterator.close();
5842                 }
5843             }
5844             return contentValuesListMap;
5845         }
5846     }
5847 
5848     /**
5849      * @see PhoneLookup
5850      */
5851     protected interface PhoneLookupColumns {
5852         /**
5853          *  The ID of the data row.
5854          *  <P>Type: INTEGER</P>
5855          */
5856         public static final String DATA_ID = "data_id";
5857         /**
5858          * A reference to the {@link ContactsContract.Contacts#_ID} that this
5859          * data belongs to.
5860          * <P>Type: INTEGER</P>
5861          */
5862         public static final String CONTACT_ID = "contact_id";
5863         /**
5864          * The phone number as the user entered it.
5865          * <P>Type: TEXT</P>
5866          */
5867         public static final String NUMBER = "number";
5868 
5869         /**
5870          * The type of phone number, for example Home or Work.
5871          * <P>Type: INTEGER</P>
5872          */
5873         public static final String TYPE = "type";
5874 
5875         /**
5876          * The user defined label for the phone number.
5877          * <P>Type: TEXT</P>
5878          */
5879         public static final String LABEL = "label";
5880 
5881         /**
5882          * The phone number's E164 representation.
5883          * <P>Type: TEXT</P>
5884          */
5885         public static final String NORMALIZED_NUMBER = "normalized_number";
5886     }
5887 
5888     /**
5889      * A table that represents the result of looking up a phone number, for
5890      * example for caller ID. To perform a lookup you must append the number you
5891      * want to find to {@link #CONTENT_FILTER_URI}.  This query is highly
5892      * optimized.
5893      * <pre>
5894      * Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
5895      * resolver.query(uri, new String[]{PhoneLookup.DISPLAY_NAME,...
5896      * </pre>
5897      *
5898      * <h3>Columns</h3>
5899      *
5900      * <table class="jd-sumtable">
5901      * <tr>
5902      * <th colspan='4'>PhoneLookup</th>
5903      * </tr>
5904      * <tr>
5905      * <td>String</td>
5906      * <td>{@link #NUMBER}</td>
5907      * <td>read-only</td>
5908      * <td>Phone number.</td>
5909      * </tr>
5910      * <tr>
5911      * <td>String</td>
5912      * <td>{@link #TYPE}</td>
5913      * <td>read-only</td>
5914      * <td>Phone number type. See {@link CommonDataKinds.Phone}.</td>
5915      * </tr>
5916      * <tr>
5917      * <td>String</td>
5918      * <td>{@link #LABEL}</td>
5919      * <td>read-only</td>
5920      * <td>Custom label for the phone number. See {@link CommonDataKinds.Phone}.</td>
5921      * </tr>
5922      * </table>
5923      * <p>
5924      * Columns from the Contacts table are also available through a join.
5925      * </p>
5926      * <table class="jd-sumtable">
5927      * <tr>
5928      * <th colspan='4'>Join with {@link Contacts}</th>
5929      * </tr>
5930      * <tr>
5931      * <td>long</td>
5932      * <td>{@link #_ID}</td>
5933      * <td>read-only</td>
5934      * <td>Contact ID.</td>
5935      * </tr>
5936      * <tr>
5937      * <td>long</td>
5938      * <td>{@link #CONTACT_ID}</td>
5939      * <td>read-only</td>
5940      * <td>Contact ID.</td>
5941      * </tr>
5942      * <tr>
5943      * <td>long</td>
5944      * <td>{@link #DATA_ID}</td>
5945      * <td>read-only</td>
5946      * <td>Data ID.</td>
5947      * </tr>
5948      * <tr>
5949      * <td>String</td>
5950      * <td>{@link #LOOKUP_KEY}</td>
5951      * <td>read-only</td>
5952      * <td>See {@link ContactsContract.Contacts}</td>
5953      * </tr>
5954      * <tr>
5955      * <td>String</td>
5956      * <td>{@link #DISPLAY_NAME}</td>
5957      * <td>read-only</td>
5958      * <td>See {@link ContactsContract.Contacts}</td>
5959      * </tr>
5960      * <tr>
5961      * <td>long</td>
5962      * <td>{@link #PHOTO_ID}</td>
5963      * <td>read-only</td>
5964      * <td>See {@link ContactsContract.Contacts}.</td>
5965      * </tr>
5966      * <tr>
5967      * <td>int</td>
5968      * <td>{@link #IN_VISIBLE_GROUP}</td>
5969      * <td>read-only</td>
5970      * <td>See {@link ContactsContract.Contacts}.</td>
5971      * </tr>
5972      * <tr>
5973      * <td>int</td>
5974      * <td>{@link #HAS_PHONE_NUMBER}</td>
5975      * <td>read-only</td>
5976      * <td>See {@link ContactsContract.Contacts}.</td>
5977      * </tr>
5978      * <tr>
5979      * <td>int</td>
5980      * <td>{@link #STARRED}</td>
5981      * <td>read-only</td>
5982      * <td>See {@link ContactsContract.Contacts}.</td>
5983      * </tr>
5984      * <tr>
5985      * <td>String</td>
5986      * <td>{@link #CUSTOM_RINGTONE}</td>
5987      * <td>read-only</td>
5988      * <td>See {@link ContactsContract.Contacts}.</td>
5989      * </tr>
5990      * <tr>
5991      * <td>int</td>
5992      * <td>{@link #SEND_TO_VOICEMAIL}</td>
5993      * <td>read-only</td>
5994      * <td>See {@link ContactsContract.Contacts}.</td>
5995      * </tr>
5996      * </table>
5997      */
5998     public static final class PhoneLookup implements BaseColumns, PhoneLookupColumns,
5999             ContactsColumns, ContactOptionsColumns, ContactNameColumns {
6000         /**
6001          * This utility class cannot be instantiated
6002          */
PhoneLookup()6003         private PhoneLookup() {}
6004 
6005         /**
6006          * The content:// style URI for this table.
6007          *
6008          * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store, this
6009          * field doesn't sort results based on contacts frequency. For more information, see the
6010          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
6011          * page.
6012          *
6013          * Append the phone number you want to lookup
6014          * to this URI and query it to perform a lookup. For example:
6015          * <pre>
6016          * Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
6017          *         Uri.encode(phoneNumber));
6018          * </pre>
6019          */
6020         public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(AUTHORITY_URI,
6021                 "phone_lookup");
6022 
6023         /**
6024          * URI used for looking up contacts by phone number on the contact databases of both the
6025          * calling user and the managed profile that is linked to it.
6026          * <p>
6027          * It supports the same semantics as {@link #CONTENT_FILTER_URI} and returns the same
6028          * columns.<br>
6029          * If the device has no managed profile that is linked to the calling user, it behaves in
6030          * the exact same way as {@link #CONTENT_FILTER_URI}.<br>
6031          * If there is a managed profile linked to the calling user, it first queries the calling
6032          * user's contact database, and only if no matching contacts are found there it then queries
6033          * the managed profile database.
6034          * <p class="caution">
6035          * <b>Caution: </b>If you publish your app to the Google Play Store, this field doesn't sort
6036          * results based on contacts frequency. For more information, see the
6037          * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
6038          * page.
6039          * <p>
6040          * If a result is from the managed profile, the following changes are made to the data:
6041          * <ul>
6042          *     <li>{@link #PHOTO_THUMBNAIL_URI} and {@link #PHOTO_URI} will be rewritten to special
6043          *     URIs. Use {@link ContentResolver#openAssetFileDescriptor} or its siblings to
6044          *     load pictures from them.
6045          *     <li>{@link #PHOTO_ID} and {@link #PHOTO_FILE_ID} will be set to null. Don't use them.
6046          *     <li>{@link #CONTACT_ID} and {@link #LOOKUP_KEY} will be replaced with artificial
6047          *     values. These values will be consistent across multiple queries, but do not use them
6048          *     in places that do not explicitly say they accept them. If they are used in the
6049          *     {@code selection} param in {@link android.content.ContentProvider#query}, the result
6050          *     is undefined.
6051          *     <li>In order to tell whether a contact is from the managed profile, use
6052          *     {@link ContactsContract.Contacts#isEnterpriseContactId(long)}.
6053          * <p>
6054          * A contact lookup URL built by
6055          * {@link ContactsContract.Contacts#getLookupUri(long, String)}
6056          * with a {@link #CONTACT_ID} and a {@link #LOOKUP_KEY} returned by this API can be passed
6057          * to {@link ContactsContract.QuickContact#showQuickContact} even if a contact is from the
6058          * managed profile.
6059          * <pre>
6060          * Uri lookupUri = Uri.withAppendedPath(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI,
6061          *         Uri.encode(phoneNumber));
6062          */
6063         public static final Uri ENTERPRISE_CONTENT_FILTER_URI = Uri.withAppendedPath(AUTHORITY_URI,
6064                 "phone_lookup_enterprise");
6065 
6066         /**
6067          * The MIME type of {@link #CONTENT_FILTER_URI} providing a directory of phone lookup rows.
6068          *
6069          * @hide
6070          */
6071         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone_lookup";
6072 
6073         /**
6074          * If this boolean parameter is set to true, then the appended query is treated as a
6075          * SIP address and the lookup will be performed against SIP addresses in the user's
6076          * contacts.
6077          */
6078         public static final String QUERY_PARAMETER_SIP_ADDRESS = "sip";
6079     }
6080 
6081     /**
6082      * Additional data mixed in with {@link StatusColumns} to link
6083      * back to specific {@link ContactsContract.Data#_ID} entries.
6084      *
6085      * @see StatusUpdates
6086      */
6087     protected interface PresenceColumns {
6088 
6089         /**
6090          * Reference to the {@link Data#_ID} entry that owns this presence.
6091          * <P>Type: INTEGER</P>
6092          */
6093         public static final String DATA_ID = "presence_data_id";
6094 
6095         /**
6096          * See {@link CommonDataKinds.Im} for a list of defined protocol constants.
6097          * <p>Type: NUMBER</p>
6098          */
6099         public static final String PROTOCOL = "protocol";
6100 
6101         /**
6102          * Name of the custom protocol.  Should be supplied along with the {@link #PROTOCOL} value
6103          * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}.  Should be null or
6104          * omitted if {@link #PROTOCOL} value is not
6105          * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}.
6106          *
6107          * <p>Type: NUMBER</p>
6108          */
6109         public static final String CUSTOM_PROTOCOL = "custom_protocol";
6110 
6111         /**
6112          * The IM handle the presence item is for. The handle is scoped to
6113          * {@link #PROTOCOL}.
6114          * <P>Type: TEXT</P>
6115          */
6116         public static final String IM_HANDLE = "im_handle";
6117 
6118         /**
6119          * The IM account for the local user that the presence data came from.
6120          * <P>Type: TEXT</P>
6121          */
6122         public static final String IM_ACCOUNT = "im_account";
6123     }
6124 
6125     /**
6126      * <p>
6127      * A status update is linked to a {@link ContactsContract.Data} row and captures
6128      * the user's latest status update via the corresponding source, e.g.
6129      * "Having lunch" via "Google Talk".
6130      * </p>
6131      * <p>
6132      * There are two ways a status update can be inserted: by explicitly linking
6133      * it to a Data row using {@link #DATA_ID} or indirectly linking it to a data row
6134      * using a combination of {@link #PROTOCOL} (or {@link #CUSTOM_PROTOCOL}) and
6135      * {@link #IM_HANDLE}.  There is no difference between insert and update, you can use
6136      * either.
6137      * </p>
6138      * <p>
6139      * Inserting or updating a status update for the user's profile requires either using
6140      * the {@link #DATA_ID} to identify the data row to attach the update to, or
6141      * {@link StatusUpdates#PROFILE_CONTENT_URI} to ensure that the change is scoped to the
6142      * profile.
6143      * </p>
6144      * <p>
6145      * You cannot use {@link ContentResolver#update} to change a status, but
6146      * {@link ContentResolver#insert} will replace the latests status if it already
6147      * exists.
6148      * </p>
6149      * <p>
6150      * Use {@link ContentResolver#bulkInsert(Uri, ContentValues[])} to insert/update statuses
6151      * for multiple contacts at once.
6152      * </p>
6153      *
6154      * <h3>Columns</h3>
6155      * <table class="jd-sumtable">
6156      * <tr>
6157      * <th colspan='4'>StatusUpdates</th>
6158      * </tr>
6159      * <tr>
6160      * <td>long</td>
6161      * <td>{@link #DATA_ID}</td>
6162      * <td>read/write</td>
6163      * <td>Reference to the {@link Data#_ID} entry that owns this presence. If this
6164      * field is <i>not</i> specified, the provider will attempt to find a data row
6165      * that matches the {@link #PROTOCOL} (or {@link #CUSTOM_PROTOCOL}) and
6166      * {@link #IM_HANDLE} columns.
6167      * </td>
6168      * </tr>
6169      * <tr>
6170      * <td>long</td>
6171      * <td>{@link #PROTOCOL}</td>
6172      * <td>read/write</td>
6173      * <td>See {@link CommonDataKinds.Im} for a list of defined protocol constants.</td>
6174      * </tr>
6175      * <tr>
6176      * <td>String</td>
6177      * <td>{@link #CUSTOM_PROTOCOL}</td>
6178      * <td>read/write</td>
6179      * <td>Name of the custom protocol.  Should be supplied along with the {@link #PROTOCOL} value
6180      * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}.  Should be null or
6181      * omitted if {@link #PROTOCOL} value is not
6182      * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}.</td>
6183      * </tr>
6184      * <tr>
6185      * <td>String</td>
6186      * <td>{@link #IM_HANDLE}</td>
6187      * <td>read/write</td>
6188      * <td> The IM handle the presence item is for. The handle is scoped to
6189      * {@link #PROTOCOL}.</td>
6190      * </tr>
6191      * <tr>
6192      * <td>String</td>
6193      * <td>{@link #IM_ACCOUNT}</td>
6194      * <td>read/write</td>
6195      * <td>The IM account for the local user that the presence data came from.</td>
6196      * </tr>
6197      * <tr>
6198      * <td>int</td>
6199      * <td>{@link #PRESENCE}</td>
6200      * <td>read/write</td>
6201      * <td>Contact IM presence status. The allowed values are:
6202      * <p>
6203      * <ul>
6204      * <li>{@link #OFFLINE}</li>
6205      * <li>{@link #INVISIBLE}</li>
6206      * <li>{@link #AWAY}</li>
6207      * <li>{@link #IDLE}</li>
6208      * <li>{@link #DO_NOT_DISTURB}</li>
6209      * <li>{@link #AVAILABLE}</li>
6210      * </ul>
6211      * </p>
6212      * <p>
6213      * Since presence status is inherently volatile, the content provider
6214      * may choose not to store this field in long-term storage.
6215      * </p>
6216      * </td>
6217      * </tr>
6218      * <tr>
6219      * <td>int</td>
6220      * <td>{@link #CHAT_CAPABILITY}</td>
6221      * <td>read/write</td>
6222      * <td>Contact IM chat compatibility value. The allowed values combinations of the following
6223      * flags. If None of these flags is set, the device can only do text messaging.
6224      * <p>
6225      * <ul>
6226      * <li>{@link #CAPABILITY_HAS_VIDEO}</li>
6227      * <li>{@link #CAPABILITY_HAS_VOICE}</li>
6228      * <li>{@link #CAPABILITY_HAS_CAMERA}</li>
6229      * </ul>
6230      * </p>
6231      * <p>
6232      * Since chat compatibility is inherently volatile as the contact's availability moves from
6233      * one device to another, the content provider may choose not to store this field in long-term
6234      * storage.
6235      * </p>
6236      * </td>
6237      * </tr>
6238      * <tr>
6239      * <td>String</td>
6240      * <td>{@link #STATUS}</td>
6241      * <td>read/write</td>
6242      * <td>Contact's latest status update, e.g. "having toast for breakfast"</td>
6243      * </tr>
6244      * <tr>
6245      * <td>long</td>
6246      * <td>{@link #STATUS_TIMESTAMP}</td>
6247      * <td>read/write</td>
6248      * <td>The absolute time in milliseconds when the status was
6249      * entered by the user. If this value is not provided, the provider will follow
6250      * this logic: if there was no prior status update, the value will be left as null.
6251      * If there was a prior status update, the provider will default this field
6252      * to the current time.</td>
6253      * </tr>
6254      * <tr>
6255      * <td>String</td>
6256      * <td>{@link #STATUS_RES_PACKAGE}</td>
6257      * <td>read/write</td>
6258      * <td> The package containing resources for this status: label and icon.</td>
6259      * </tr>
6260      * <tr>
6261      * <td>long</td>
6262      * <td>{@link #STATUS_LABEL}</td>
6263      * <td>read/write</td>
6264      * <td>The resource ID of the label describing the source of contact status,
6265      * e.g. "Google Talk". This resource is scoped by the
6266      * {@link #STATUS_RES_PACKAGE}.</td>
6267      * </tr>
6268      * <tr>
6269      * <td>long</td>
6270      * <td>{@link #STATUS_ICON}</td>
6271      * <td>read/write</td>
6272      * <td>The resource ID of the icon for the source of contact status. This
6273      * resource is scoped by the {@link #STATUS_RES_PACKAGE}.</td>
6274      * </tr>
6275      * </table>
6276      */
6277     public static class StatusUpdates implements StatusColumns, PresenceColumns {
6278 
6279         /**
6280          * This utility class cannot be instantiated
6281          */
StatusUpdates()6282         private StatusUpdates() {}
6283 
6284         /**
6285          * The content:// style URI for this table
6286          */
6287         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "status_updates");
6288 
6289         /**
6290          * The content:// style URI for this table, specific to the user's profile.
6291          */
6292         public static final Uri PROFILE_CONTENT_URI =
6293                 Uri.withAppendedPath(Profile.CONTENT_URI, "status_updates");
6294 
6295         /**
6296          * Gets the resource ID for the proper presence icon.
6297          *
6298          * @param status the status to get the icon for
6299          * @return the resource ID for the proper presence icon
6300          */
getPresenceIconResourceId(int status)6301         public static final int getPresenceIconResourceId(int status) {
6302             switch (status) {
6303                 case AVAILABLE:
6304                     return android.R.drawable.presence_online;
6305                 case IDLE:
6306                 case AWAY:
6307                     return android.R.drawable.presence_away;
6308                 case DO_NOT_DISTURB:
6309                     return android.R.drawable.presence_busy;
6310                 case INVISIBLE:
6311                     return android.R.drawable.presence_invisible;
6312                 case OFFLINE:
6313                 default:
6314                     return android.R.drawable.presence_offline;
6315             }
6316         }
6317 
6318         /**
6319          * Returns the precedence of the status code the higher number being the higher precedence.
6320          *
6321          * @param status The status code.
6322          * @return An integer representing the precedence, 0 being the lowest.
6323          */
getPresencePrecedence(int status)6324         public static final int getPresencePrecedence(int status) {
6325             // Keep this function here incase we want to enforce a different precedence than the
6326             // natural order of the status constants.
6327             return status;
6328         }
6329 
6330         /**
6331          * The MIME type of {@link #CONTENT_URI} providing a directory of
6332          * status update details.
6333          */
6334         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/status-update";
6335 
6336         /**
6337          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
6338          * status update detail.
6339          */
6340         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/status-update";
6341     }
6342 
6343     /**
6344      * @deprecated This old name was never meant to be made public. Do not use.
6345      */
6346     @Deprecated
6347     public static final class Presence extends StatusUpdates {
6348 
6349     }
6350 
6351     /**
6352      * Additional column returned by
6353      * {@link ContactsContract.Contacts#CONTENT_FILTER_URI Contacts.CONTENT_FILTER_URI} explaining
6354      * why the filter matched the contact. This column will contain extracts from the contact's
6355      * constituent {@link Data Data} items, formatted in a way that indicates the section of the
6356      * snippet that matched the filter.
6357      *
6358      * <p>
6359      * The following example searches for all contacts that match the query "presi" and requests
6360      * the snippet column as well.
6361      * <pre>
6362      * Builder builder = Contacts.CONTENT_FILTER_URI.buildUpon();
6363      * builder.appendPath("presi");
6364      * // Defer snippeting to the client side if possible, for performance reasons.
6365      * builder.appendQueryParameter(SearchSnippets.DEFERRED_SNIPPETING_KEY,"1");
6366      *
6367      * Cursor cursor = getContentResolver().query(builder.build());
6368      *
6369      * Bundle extras = cursor.getExtras();
6370      * if (extras.getBoolean(ContactsContract.DEFERRED_SNIPPETING)) {
6371      *     // Do our own snippet formatting.
6372      *     // For a contact with the email address (president@organization.com), the snippet
6373      *     // column will contain the string "president@organization.com".
6374      * } else {
6375      *     // The snippet has already been pre-formatted, we can display it as is.
6376      *     // For a contact with the email address (president@organization.com), the snippet
6377      *     // column will contain the string "[presi]dent@organization.com".
6378      * }
6379      * </pre>
6380      * </p>
6381      */
6382     public static class SearchSnippets {
6383 
6384         /**
6385          * The search snippet constructed by SQLite snippeting functionality.
6386          * <p>
6387          * The snippet may contain (parts of) several data elements belonging to the contact,
6388          * with the matching parts optionally surrounded by special characters that indicate the
6389          * start and end of matching text.
6390          *
6391          * For example, if a contact has an address "123 Main Street", using a filter "mai" would
6392          * return the formatted snippet "123 [Mai]n street".
6393          *
6394          * @see <a href="http://www.sqlite.org/fts3.html#snippet">
6395          *         http://www.sqlite.org/fts3.html#snippet</a>
6396          */
6397         public static final String SNIPPET = "snippet";
6398 
6399         /**
6400          * Comma-separated parameters for the generation of the snippet:
6401          * <ul>
6402          * <li>The "start match" text. Default is '['</li>
6403          * <li>The "end match" text. Default is ']'</li>
6404          * <li>The "ellipsis" text. Default is "..."</li>
6405          * <li>Maximum number of tokens to include in the snippet. Can be either
6406          * a positive or a negative number: A positive number indicates how many
6407          * tokens can be returned in total. A negative number indicates how many
6408          * tokens can be returned per occurrence of the search terms.</li>
6409          * </ul>
6410          *
6411          * @hide
6412          */
6413         public static final String SNIPPET_ARGS_PARAM_KEY = "snippet_args";
6414 
6415         /**
6416          * The key to ask the provider to defer the formatting of the snippet to the client if
6417          * possible, for performance reasons.
6418          * A value of 1 indicates true, 0 indicates false. False is the default.
6419          * When a cursor is returned to the client, it should check for an extra with the name
6420          * {@link ContactsContract#DEFERRED_SNIPPETING} in the cursor. If it exists, the client
6421          * should do its own formatting of the snippet. If it doesn't exist, the snippet column
6422          * in the cursor should already contain a formatted snippet.
6423          */
6424         public static final String DEFERRED_SNIPPETING_KEY = "deferred_snippeting";
6425     }
6426 
6427     /**
6428      * Container for definitions of common data types stored in the {@link ContactsContract.Data}
6429      * table.
6430      */
6431     public static final class CommonDataKinds {
6432         /**
6433          * This utility class cannot be instantiated
6434          */
CommonDataKinds()6435         private CommonDataKinds() {}
6436 
6437         /**
6438          * The {@link Data#RES_PACKAGE} value for common data that should be
6439          * shown using a default style.
6440          *
6441          * @hide RES_PACKAGE is hidden
6442          */
6443         public static final String PACKAGE_COMMON = "common";
6444 
6445         /**
6446          * The base types that all "Typed" data kinds support.
6447          */
6448         public interface BaseTypes {
6449             /**
6450              * A custom type. The custom label should be supplied by user.
6451              */
6452             public static int TYPE_CUSTOM = 0;
6453         }
6454 
6455         /**
6456          * Columns common across the specific types.
6457          */
6458         protected interface CommonColumns extends BaseTypes {
6459             /**
6460              * The data for the contact method.
6461              * <P>Type: TEXT</P>
6462              */
6463             public static final String DATA = DataColumns.DATA1;
6464 
6465             /**
6466              * The type of data, for example Home or Work.
6467              * <P>Type: INTEGER</P>
6468              */
6469             public static final String TYPE = DataColumns.DATA2;
6470 
6471             /**
6472              * The user defined label for the the contact method.
6473              * <P>Type: TEXT</P>
6474              */
6475             public static final String LABEL = DataColumns.DATA3;
6476         }
6477 
6478         /**
6479          * A data kind representing the contact's proper name. You can use all
6480          * columns defined for {@link ContactsContract.Data} as well as the following aliases.
6481          *
6482          * <h2>Column aliases</h2>
6483          * <table class="jd-sumtable">
6484          * <tr>
6485          * <th>Type</th><th>Alias</th><th colspan='2'>Data column</th>
6486          * </tr>
6487          * <tr>
6488          * <td>String</td>
6489          * <td>{@link #DISPLAY_NAME}</td>
6490          * <td>{@link #DATA1}</td>
6491          * <td></td>
6492          * </tr>
6493          * <tr>
6494          * <td>String</td>
6495          * <td>{@link #GIVEN_NAME}</td>
6496          * <td>{@link #DATA2}</td>
6497          * <td></td>
6498          * </tr>
6499          * <tr>
6500          * <td>String</td>
6501          * <td>{@link #FAMILY_NAME}</td>
6502          * <td>{@link #DATA3}</td>
6503          * <td></td>
6504          * </tr>
6505          * <tr>
6506          * <td>String</td>
6507          * <td>{@link #PREFIX}</td>
6508          * <td>{@link #DATA4}</td>
6509          * <td>Common prefixes in English names are "Mr", "Ms", "Dr" etc.</td>
6510          * </tr>
6511          * <tr>
6512          * <td>String</td>
6513          * <td>{@link #MIDDLE_NAME}</td>
6514          * <td>{@link #DATA5}</td>
6515          * <td></td>
6516          * </tr>
6517          * <tr>
6518          * <td>String</td>
6519          * <td>{@link #SUFFIX}</td>
6520          * <td>{@link #DATA6}</td>
6521          * <td>Common suffixes in English names are "Sr", "Jr", "III" etc.</td>
6522          * </tr>
6523          * <tr>
6524          * <td>String</td>
6525          * <td>{@link #PHONETIC_GIVEN_NAME}</td>
6526          * <td>{@link #DATA7}</td>
6527          * <td>Used for phonetic spelling of the name, e.g. Pinyin, Katakana, Hiragana</td>
6528          * </tr>
6529          * <tr>
6530          * <td>String</td>
6531          * <td>{@link #PHONETIC_MIDDLE_NAME}</td>
6532          * <td>{@link #DATA8}</td>
6533          * <td></td>
6534          * </tr>
6535          * <tr>
6536          * <td>String</td>
6537          * <td>{@link #PHONETIC_FAMILY_NAME}</td>
6538          * <td>{@link #DATA9}</td>
6539          * <td></td>
6540          * </tr>
6541          * </table>
6542          */
6543         public static final class StructuredName implements DataColumnsWithJoins, ContactCounts {
6544             /**
6545              * This utility class cannot be instantiated
6546              */
StructuredName()6547             private StructuredName() {}
6548 
6549             /** MIME type used when storing this in data table. */
6550             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/name";
6551 
6552             /**
6553              * The name that should be used to display the contact.
6554              * <i>Unstructured component of the name should be consistent with
6555              * its structured representation.</i>
6556              * <p>
6557              * Type: TEXT
6558              */
6559             public static final String DISPLAY_NAME = DATA1;
6560 
6561             /**
6562              * The given name for the contact.
6563              * <P>Type: TEXT</P>
6564              */
6565             public static final String GIVEN_NAME = DATA2;
6566 
6567             /**
6568              * The family name for the contact.
6569              * <P>Type: TEXT</P>
6570              */
6571             public static final String FAMILY_NAME = DATA3;
6572 
6573             /**
6574              * The contact's honorific prefix, e.g. "Sir"
6575              * <P>Type: TEXT</P>
6576              */
6577             public static final String PREFIX = DATA4;
6578 
6579             /**
6580              * The contact's middle name
6581              * <P>Type: TEXT</P>
6582              */
6583             public static final String MIDDLE_NAME = DATA5;
6584 
6585             /**
6586              * The contact's honorific suffix, e.g. "Jr"
6587              */
6588             public static final String SUFFIX = DATA6;
6589 
6590             /**
6591              * The phonetic version of the given name for the contact.
6592              * <P>Type: TEXT</P>
6593              */
6594             public static final String PHONETIC_GIVEN_NAME = DATA7;
6595 
6596             /**
6597              * The phonetic version of the additional name for the contact.
6598              * <P>Type: TEXT</P>
6599              */
6600             public static final String PHONETIC_MIDDLE_NAME = DATA8;
6601 
6602             /**
6603              * The phonetic version of the family name for the contact.
6604              * <P>Type: TEXT</P>
6605              */
6606             public static final String PHONETIC_FAMILY_NAME = DATA9;
6607 
6608             /**
6609              * The style used for combining given/middle/family name into a full name.
6610              * See {@link ContactsContract.FullNameStyle}.
6611              */
6612             public static final String FULL_NAME_STYLE = DATA10;
6613 
6614             /**
6615              * The alphabet used for capturing the phonetic name.
6616              * See ContactsContract.PhoneticNameStyle.
6617              */
6618             public static final String PHONETIC_NAME_STYLE = DATA11;
6619         }
6620 
6621         /**
6622          * <p>A data kind representing the contact's nickname. For example, for
6623          * Bob Parr ("Mr. Incredible"):
6624          * <pre>
6625          * ArrayList&lt;ContentProviderOperation&gt; ops =
6626          *          new ArrayList&lt;ContentProviderOperation&gt;();
6627          *
6628          * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
6629          *          .withValue(Data.RAW_CONTACT_ID, rawContactId)
6630          *          .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
6631          *          .withValue(StructuredName.DISPLAY_NAME, &quot;Bob Parr&quot;)
6632          *          .build());
6633          *
6634          * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
6635          *          .withValue(Data.RAW_CONTACT_ID, rawContactId)
6636          *          .withValue(Data.MIMETYPE, Nickname.CONTENT_ITEM_TYPE)
6637          *          .withValue(Nickname.NAME, "Mr. Incredible")
6638          *          .withValue(Nickname.TYPE, Nickname.TYPE_CUSTOM)
6639          *          .withValue(Nickname.LABEL, "Superhero")
6640          *          .build());
6641          *
6642          * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
6643          * </pre>
6644          * </p>
6645          * <p>
6646          * You can use all columns defined for {@link ContactsContract.Data} as well as the
6647          * following aliases.
6648          * </p>
6649          *
6650          * <h2>Column aliases</h2>
6651          * <table class="jd-sumtable">
6652          * <tr>
6653          * <th>Type</th><th>Alias</th><th colspan='2'>Data column</th>
6654          * </tr>
6655          * <tr>
6656          * <td>String</td>
6657          * <td>{@link #NAME}</td>
6658          * <td>{@link #DATA1}</td>
6659          * <td></td>
6660          * </tr>
6661          * <tr>
6662          * <td>int</td>
6663          * <td>{@link #TYPE}</td>
6664          * <td>{@link #DATA2}</td>
6665          * <td>
6666          * Allowed values are:
6667          * <p>
6668          * <ul>
6669          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
6670          * <li>{@link #TYPE_DEFAULT}</li>
6671          * <li>{@link #TYPE_OTHER_NAME}</li>
6672          * <li>{@link #TYPE_MAIDEN_NAME}</li>
6673          * <li>{@link #TYPE_SHORT_NAME}</li>
6674          * <li>{@link #TYPE_INITIALS}</li>
6675          * </ul>
6676          * </p>
6677          * </td>
6678          * </tr>
6679          * <tr>
6680          * <td>String</td>
6681          * <td>{@link #LABEL}</td>
6682          * <td>{@link #DATA3}</td>
6683          * <td></td>
6684          * </tr>
6685          * </table>
6686          */
6687         public static final class Nickname implements DataColumnsWithJoins, CommonColumns,
6688                 ContactCounts{
6689             /**
6690              * This utility class cannot be instantiated
6691              */
Nickname()6692             private Nickname() {}
6693 
6694             /** MIME type used when storing this in data table. */
6695             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/nickname";
6696 
6697             public static final int TYPE_DEFAULT = 1;
6698             public static final int TYPE_OTHER_NAME = 2;
6699             public static final int TYPE_MAIDEN_NAME = 3;
6700             /** @deprecated Use TYPE_MAIDEN_NAME instead. */
6701             @Deprecated
6702             public static final int TYPE_MAINDEN_NAME = 3;
6703             public static final int TYPE_SHORT_NAME = 4;
6704             public static final int TYPE_INITIALS = 5;
6705 
6706             /**
6707              * The name itself
6708              */
6709             public static final String NAME = DATA;
6710         }
6711 
6712         /**
6713          * <p>
6714          * A data kind representing a telephone number.
6715          * </p>
6716          * <p>
6717          * You can use all columns defined for {@link ContactsContract.Data} as
6718          * well as the following aliases.
6719          * </p>
6720          * <h2>Column aliases</h2>
6721          * <table class="jd-sumtable">
6722          * <tr>
6723          * <th>Type</th>
6724          * <th>Alias</th><th colspan='2'>Data column</th>
6725          * </tr>
6726          * <tr>
6727          * <td>String</td>
6728          * <td>{@link #NUMBER}</td>
6729          * <td>{@link #DATA1}</td>
6730          * <td></td>
6731          * </tr>
6732          * <tr>
6733          * <td>int</td>
6734          * <td>{@link #TYPE}</td>
6735          * <td>{@link #DATA2}</td>
6736          * <td>Allowed values are:
6737          * <p>
6738          * <ul>
6739          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
6740          * <li>{@link #TYPE_HOME}</li>
6741          * <li>{@link #TYPE_MOBILE}</li>
6742          * <li>{@link #TYPE_WORK}</li>
6743          * <li>{@link #TYPE_FAX_WORK}</li>
6744          * <li>{@link #TYPE_FAX_HOME}</li>
6745          * <li>{@link #TYPE_PAGER}</li>
6746          * <li>{@link #TYPE_OTHER}</li>
6747          * <li>{@link #TYPE_CALLBACK}</li>
6748          * <li>{@link #TYPE_CAR}</li>
6749          * <li>{@link #TYPE_COMPANY_MAIN}</li>
6750          * <li>{@link #TYPE_ISDN}</li>
6751          * <li>{@link #TYPE_MAIN}</li>
6752          * <li>{@link #TYPE_OTHER_FAX}</li>
6753          * <li>{@link #TYPE_RADIO}</li>
6754          * <li>{@link #TYPE_TELEX}</li>
6755          * <li>{@link #TYPE_TTY_TDD}</li>
6756          * <li>{@link #TYPE_WORK_MOBILE}</li>
6757          * <li>{@link #TYPE_WORK_PAGER}</li>
6758          * <li>{@link #TYPE_ASSISTANT}</li>
6759          * <li>{@link #TYPE_MMS}</li>
6760          * </ul>
6761          * </p>
6762          * </td>
6763          * </tr>
6764          * <tr>
6765          * <td>String</td>
6766          * <td>{@link #LABEL}</td>
6767          * <td>{@link #DATA3}</td>
6768          * <td></td>
6769          * </tr>
6770          * </table>
6771          */
6772         public static final class Phone implements DataColumnsWithJoins, CommonColumns,
6773                 ContactCounts {
6774             /**
6775              * This utility class cannot be instantiated
6776              */
Phone()6777             private Phone() {}
6778 
6779             /** MIME type used when storing this in data table. */
6780             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone_v2";
6781 
6782             /**
6783              * The MIME type of {@link #CONTENT_URI} providing a directory of
6784              * phones.
6785              */
6786             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone_v2";
6787 
6788             /**
6789              * The content:// style URI for all data records of the
6790              * {@link #CONTENT_ITEM_TYPE} MIME type, combined with the
6791              * associated raw contact and aggregate contact data.
6792              */
6793             public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
6794                     "phones");
6795 
6796             /**
6797              * URI used for getting all data records of the {@link #CONTENT_ITEM_TYPE} MIME type,
6798              * combined with the associated raw contact and aggregate contact data, from both the
6799              * calling user and the managed profile that is linked to it.
6800              * <p>
6801              * It supports the same semantics as {@link #CONTENT_URI} and returns the same
6802              * columns.<br>
6803              * If the device has no managed profile that is linked to the calling user, it behaves
6804              * in the exact same way as {@link #CONTENT_URI}.<br>
6805              * If there is a managed profile linked to the calling user, it will return merged
6806              * results from both.
6807              * <p>
6808              * If a result is from the managed profile, the following changes are made to the data:
6809              * <ul>
6810              *     <li>{@link #PHOTO_THUMBNAIL_URI} and {@link #PHOTO_URI} will be rewritten to
6811              *     special URIs. Use {@link ContentResolver#openAssetFileDescriptor} or its siblings
6812              *     to load pictures from them.
6813              *     <li>{@link #PHOTO_ID} and {@link #PHOTO_FILE_ID} will be set to null. Don't use
6814              *     them.
6815              *     <li>{@link #CONTACT_ID} and {@link #LOOKUP_KEY} will be replaced with artificial
6816              *     values. These values will be consistent across multiple queries, but do not use
6817              *     them in places that don't explicitly say they accept them. If they are used in
6818              *     the {@code selection} param in {@link android.content.ContentProvider#query}, the
6819              *     result is undefined.
6820              *     <li>In order to tell whether a contact is from the managed profile, use
6821              *     {@link ContactsContract.Contacts#isEnterpriseContactId(long)}.
6822              */
6823             public static final @NonNull Uri ENTERPRISE_CONTENT_URI =
6824                     Uri.withAppendedPath(Data.ENTERPRISE_CONTENT_URI, "phones");
6825 
6826             /**
6827              * <p>The content:// style URL for phone lookup using a filter. The filter returns
6828              * records of MIME type {@link #CONTENT_ITEM_TYPE}. The filter is applied
6829              * to display names as well as phone numbers. The filter argument should be passed
6830              * as an additional path segment after this URI.
6831              *
6832              * <p class="caution"><b>Caution: </b>This field doesn't sort results based on contacts
6833              * frequency. For more information, see the
6834              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
6835              * page.
6836              */
6837             public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(CONTENT_URI,
6838                     "filter");
6839 
6840             /**
6841              * <p>It supports the similar semantics as {@link #CONTENT_FILTER_URI} and returns the
6842              * same columns. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
6843              * parameters, otherwise it will throw IllegalArgumentException.
6844              *
6845              * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
6846              * this field doesn't sort results based on contacts frequency. For more information,
6847              * see the
6848              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
6849              * page.
6850              */
6851             public static final Uri ENTERPRISE_CONTENT_FILTER_URI = Uri.withAppendedPath(
6852                     CONTENT_URI, "filter_enterprise");
6853 
6854             /**
6855              * A boolean query parameter that can be used with {@link #CONTENT_FILTER_URI}.
6856              * If "1" or "true", display names are searched.  If "0" or "false", display names
6857              * are not searched.  Default is "1".
6858              */
6859             public static final String SEARCH_DISPLAY_NAME_KEY = "search_display_name";
6860 
6861             /**
6862              * A boolean query parameter that can be used with {@link #CONTENT_FILTER_URI}.
6863              * If "1" or "true", phone numbers are searched.  If "0" or "false", phone numbers
6864              * are not searched.  Default is "1".
6865              */
6866             public static final String SEARCH_PHONE_NUMBER_KEY = "search_phone_number";
6867 
6868             public static final int TYPE_HOME = 1;
6869             public static final int TYPE_MOBILE = 2;
6870             public static final int TYPE_WORK = 3;
6871             public static final int TYPE_FAX_WORK = 4;
6872             public static final int TYPE_FAX_HOME = 5;
6873             public static final int TYPE_PAGER = 6;
6874             public static final int TYPE_OTHER = 7;
6875             public static final int TYPE_CALLBACK = 8;
6876             public static final int TYPE_CAR = 9;
6877             public static final int TYPE_COMPANY_MAIN = 10;
6878             public static final int TYPE_ISDN = 11;
6879             public static final int TYPE_MAIN = 12;
6880             public static final int TYPE_OTHER_FAX = 13;
6881             public static final int TYPE_RADIO = 14;
6882             public static final int TYPE_TELEX = 15;
6883             public static final int TYPE_TTY_TDD = 16;
6884             public static final int TYPE_WORK_MOBILE = 17;
6885             public static final int TYPE_WORK_PAGER = 18;
6886             public static final int TYPE_ASSISTANT = 19;
6887             public static final int TYPE_MMS = 20;
6888 
6889             /**
6890              * The phone number as the user entered it.
6891              * <P>Type: TEXT</P>
6892              */
6893             public static final String NUMBER = DATA;
6894 
6895             /**
6896              * The phone number's E164 representation. This value can be omitted in which
6897              * case the provider will try to automatically infer it.  (It'll be left null if the
6898              * provider fails to infer.)
6899              * If present, {@link #NUMBER} has to be set as well (it will be ignored otherwise).
6900              * <P>Type: TEXT</P>
6901              */
6902             public static final String NORMALIZED_NUMBER = DATA4;
6903 
6904             /**
6905              * @deprecated use {@link #getTypeLabel(Resources, int, CharSequence)} instead.
6906              * @hide
6907              */
6908             @Deprecated
getDisplayLabel(Context context, int type, CharSequence label, CharSequence[] labelArray)6909             public static final CharSequence getDisplayLabel(Context context, int type,
6910                     CharSequence label, CharSequence[] labelArray) {
6911                 return getTypeLabel(context.getResources(), type, label);
6912             }
6913 
6914             /**
6915              * @deprecated use {@link #getTypeLabel(Resources, int, CharSequence)} instead.
6916              * @hide
6917              */
6918             @Deprecated
6919             @UnsupportedAppUsage
getDisplayLabel(Context context, int type, CharSequence label)6920             public static final CharSequence getDisplayLabel(Context context, int type,
6921                     CharSequence label) {
6922                 return getTypeLabel(context.getResources(), type, label);
6923             }
6924 
6925             /**
6926              * Return the string resource that best describes the given
6927              * {@link #TYPE}. Will always return a valid resource.
6928              */
getTypeLabelResource(int type)6929             public static final int getTypeLabelResource(int type) {
6930                 switch (type) {
6931                     case TYPE_HOME: return com.android.internal.R.string.phoneTypeHome;
6932                     case TYPE_MOBILE: return com.android.internal.R.string.phoneTypeMobile;
6933                     case TYPE_WORK: return com.android.internal.R.string.phoneTypeWork;
6934                     case TYPE_FAX_WORK: return com.android.internal.R.string.phoneTypeFaxWork;
6935                     case TYPE_FAX_HOME: return com.android.internal.R.string.phoneTypeFaxHome;
6936                     case TYPE_PAGER: return com.android.internal.R.string.phoneTypePager;
6937                     case TYPE_OTHER: return com.android.internal.R.string.phoneTypeOther;
6938                     case TYPE_CALLBACK: return com.android.internal.R.string.phoneTypeCallback;
6939                     case TYPE_CAR: return com.android.internal.R.string.phoneTypeCar;
6940                     case TYPE_COMPANY_MAIN: return com.android.internal.R.string.phoneTypeCompanyMain;
6941                     case TYPE_ISDN: return com.android.internal.R.string.phoneTypeIsdn;
6942                     case TYPE_MAIN: return com.android.internal.R.string.phoneTypeMain;
6943                     case TYPE_OTHER_FAX: return com.android.internal.R.string.phoneTypeOtherFax;
6944                     case TYPE_RADIO: return com.android.internal.R.string.phoneTypeRadio;
6945                     case TYPE_TELEX: return com.android.internal.R.string.phoneTypeTelex;
6946                     case TYPE_TTY_TDD: return com.android.internal.R.string.phoneTypeTtyTdd;
6947                     case TYPE_WORK_MOBILE: return com.android.internal.R.string.phoneTypeWorkMobile;
6948                     case TYPE_WORK_PAGER: return com.android.internal.R.string.phoneTypeWorkPager;
6949                     case TYPE_ASSISTANT: return com.android.internal.R.string.phoneTypeAssistant;
6950                     case TYPE_MMS: return com.android.internal.R.string.phoneTypeMms;
6951                     default: return com.android.internal.R.string.phoneTypeCustom;
6952                 }
6953             }
6954 
6955             /**
6956              * Return a {@link CharSequence} that best describes the given type,
6957              * possibly substituting the given {@link #LABEL} value
6958              * for {@link #TYPE_CUSTOM}.
6959              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)6960             public static final CharSequence getTypeLabel(Resources res, int type,
6961                     @Nullable CharSequence label) {
6962                 if ((type == TYPE_CUSTOM || type == TYPE_ASSISTANT) && !TextUtils.isEmpty(label)) {
6963                     return label;
6964                 } else {
6965                     final int labelRes = getTypeLabelResource(type);
6966                     return res.getText(labelRes);
6967                 }
6968             }
6969         }
6970 
6971         /**
6972          * <p>
6973          * A data kind representing an email address.
6974          * </p>
6975          * <p>
6976          * You can use all columns defined for {@link ContactsContract.Data} as
6977          * well as the following aliases.
6978          * </p>
6979          * <h2>Column aliases</h2>
6980          * <table class="jd-sumtable">
6981          * <tr>
6982          * <th>Type</th>
6983          * <th>Alias</th><th colspan='2'>Data column</th>
6984          * </tr>
6985          * <tr>
6986          * <td>String</td>
6987          * <td>{@link #ADDRESS}</td>
6988          * <td>{@link #DATA1}</td>
6989          * <td>Email address itself.</td>
6990          * </tr>
6991          * <tr>
6992          * <td>int</td>
6993          * <td>{@link #TYPE}</td>
6994          * <td>{@link #DATA2}</td>
6995          * <td>Allowed values are:
6996          * <p>
6997          * <ul>
6998          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
6999          * <li>{@link #TYPE_HOME}</li>
7000          * <li>{@link #TYPE_WORK}</li>
7001          * <li>{@link #TYPE_OTHER}</li>
7002          * <li>{@link #TYPE_MOBILE}</li>
7003          * </ul>
7004          * </p>
7005          * </td>
7006          * </tr>
7007          * <tr>
7008          * <td>String</td>
7009          * <td>{@link #LABEL}</td>
7010          * <td>{@link #DATA3}</td>
7011          * <td></td>
7012          * </tr>
7013          * </table>
7014          */
7015         public static final class Email implements DataColumnsWithJoins, CommonColumns,
7016                 ContactCounts {
7017             /*
7018              * This utility class cannot be instantiated
7019              */
Email()7020             private Email() {}
7021 
7022             /** MIME type used when storing this in data table. */
7023             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/email_v2";
7024 
7025             /**
7026              * The MIME type of {@link #CONTENT_URI} providing a directory of email addresses.
7027              */
7028             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/email_v2";
7029 
7030             /**
7031              * The content:// style URI for all data records of the
7032              * {@link #CONTENT_ITEM_TYPE} MIME type, combined with the
7033              * associated raw contact and aggregate contact data.
7034              */
7035             public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
7036                     "emails");
7037 
7038             /**
7039              * <p>
7040              * The content:// style URL for looking up data rows by email address. The
7041              * lookup argument, an email address, should be passed as an additional path segment
7042              * after this URI.
7043              * </p>
7044              * <p>Example:
7045              * <pre>
7046              * Uri uri = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(email));
7047              * Cursor c = getContentResolver().query(uri,
7048              *          new String[]{Email.CONTACT_ID, Email.DISPLAY_NAME, Email.DATA},
7049              *          null, null, null);
7050              * </pre>
7051              * </p>
7052              */
7053             public static final Uri CONTENT_LOOKUP_URI = Uri.withAppendedPath(CONTENT_URI,
7054                     "lookup");
7055 
7056             /**
7057              * URI used for looking up contacts by email on the contact databases of both the
7058              * calling user and the managed profile that is linked to it.
7059              * <p>
7060              * It supports the same semantics as {@link #CONTENT_LOOKUP_URI} and returns the same
7061              * columns.<br>
7062              * If the device has no managed profile that is linked to the calling user, it behaves
7063              * in the exact same way as {@link #CONTENT_LOOKUP_URI}.<br>
7064              * If there is a managed profile linked to the calling user, it first queries the
7065              * calling user's contact database, and only if no matching contacts are found there it
7066              * then queries the managed profile database.
7067              * <p class="caution">
7068              * If a result is from the managed profile, the following changes are made to the data:
7069              * <ul>
7070              *     <li>{@link #PHOTO_THUMBNAIL_URI} and {@link #PHOTO_URI} will be rewritten to
7071              *     specialURIs. Use {@link ContentResolver#openAssetFileDescriptor} or its siblings
7072              *     to load pictures from them.
7073              *     <li>{@link #PHOTO_ID} and {@link #PHOTO_FILE_ID} will be set to null. Don't use
7074              *     them.
7075              *     <li>{@link #CONTACT_ID} and {@link #LOOKUP_KEY} will be replaced with artificial
7076              *     values. These values will be consistent across multiple queries, but do not use
7077              *     them in places that do not explicitly say they accept them. If they are used in
7078              *     the {@code selection} param in {@link android.content.ContentProvider#query}, the
7079              *     result is undefined.
7080              *     <li>In order to tell whether a contact is from the managed profile, use
7081              *     {@link ContactsContract.Contacts#isEnterpriseContactId(long)}.
7082              * <p>
7083              * A contact lookup URL built by
7084              * {@link ContactsContract.Contacts#getLookupUri(long, String)}
7085              * with a {@link #CONTACT_ID} and a {@link #LOOKUP_KEY} returned by this API can be
7086              * passed to {@link ContactsContract.QuickContact#showQuickContact} even if a contact is
7087              * from the managed profile.
7088              * <pre>
7089              * Uri lookupUri = Uri.withAppendedPath(Email.ENTERPRISE_CONTENT_LOOKUP_URI,
7090              *         Uri.encode(email));
7091              */
7092             public static final Uri ENTERPRISE_CONTENT_LOOKUP_URI =
7093                     Uri.withAppendedPath(CONTENT_URI, "lookup_enterprise");
7094 
7095             /**
7096              * <p>The content:// style URL for email lookup using a filter. The filter returns
7097              * records of MIME type {@link #CONTENT_ITEM_TYPE}. The filter is applied
7098              * to display names as well as email addresses. The filter argument should be passed
7099              * as an additional path segment after this URI.
7100              * </p>
7101              *
7102              * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
7103              * this field doesn't sort results based on contacts frequency. For more information,
7104              * see the
7105              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
7106              * page.</p>
7107              *
7108              * <p>The query in the following example will return "Robert Parr (bob@incredibles.com)"
7109              * as well as "Bob Parr (incredible@android.com)".
7110              * <pre>
7111              * Uri uri = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode("bob"));
7112              * Cursor c = getContentResolver().query(uri,
7113              *          new String[]{Email.DISPLAY_NAME, Email.DATA},
7114              *          null, null, null);
7115              * </pre>
7116              * </p>
7117              */
7118             public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(CONTENT_URI,
7119                     "filter");
7120 
7121             /**
7122              * <p>It supports the similar semantics as {@link #CONTENT_FILTER_URI} and returns the
7123              * same columns. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
7124              * parameters, otherwise it will throw IllegalArgumentException. The passed directory
7125              * can belong either to the calling user or to a managed profile that is linked to it.
7126              * <p class="caution">
7127              * <b>Caution: </b>If you publish your app to the Google Play Store,
7128              * this field doesn't sort results based on contacts frequency. For more information,
7129              * see the
7130              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
7131              * page.
7132              */
7133             public static final Uri ENTERPRISE_CONTENT_FILTER_URI = Uri.withAppendedPath(
7134                     CONTENT_URI, "filter_enterprise");
7135 
7136             /**
7137              * The email address.
7138              * <P>Type: TEXT</P>
7139              */
7140             public static final String ADDRESS = DATA1;
7141 
7142             public static final int TYPE_HOME = 1;
7143             public static final int TYPE_WORK = 2;
7144             public static final int TYPE_OTHER = 3;
7145             public static final int TYPE_MOBILE = 4;
7146 
7147             /**
7148              * The display name for the email address
7149              * <P>Type: TEXT</P>
7150              */
7151             public static final String DISPLAY_NAME = DATA4;
7152 
7153             /**
7154              * Return the string resource that best describes the given
7155              * {@link #TYPE}. Will always return a valid resource.
7156              */
getTypeLabelResource(int type)7157             public static final int getTypeLabelResource(int type) {
7158                 switch (type) {
7159                     case TYPE_HOME: return com.android.internal.R.string.emailTypeHome;
7160                     case TYPE_WORK: return com.android.internal.R.string.emailTypeWork;
7161                     case TYPE_OTHER: return com.android.internal.R.string.emailTypeOther;
7162                     case TYPE_MOBILE: return com.android.internal.R.string.emailTypeMobile;
7163                     default: return com.android.internal.R.string.emailTypeCustom;
7164                 }
7165             }
7166 
7167             /**
7168              * Return a {@link CharSequence} that best describes the given type,
7169              * possibly substituting the given {@link #LABEL} value
7170              * for {@link #TYPE_CUSTOM}.
7171              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)7172             public static final CharSequence getTypeLabel(Resources res, int type,
7173                     @Nullable CharSequence label) {
7174                 if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
7175                     return label;
7176                 } else {
7177                     final int labelRes = getTypeLabelResource(type);
7178                     return res.getText(labelRes);
7179                 }
7180             }
7181         }
7182 
7183         /**
7184          * <p>
7185          * A data kind representing a postal addresses.
7186          * </p>
7187          * <p>
7188          * You can use all columns defined for {@link ContactsContract.Data} as
7189          * well as the following aliases.
7190          * </p>
7191          * <h2>Column aliases</h2>
7192          * <table class="jd-sumtable">
7193          * <tr>
7194          * <th>Type</th>
7195          * <th>Alias</th><th colspan='2'>Data column</th>
7196          * </tr>
7197          * <tr>
7198          * <td>String</td>
7199          * <td>{@link #FORMATTED_ADDRESS}</td>
7200          * <td>{@link #DATA1}</td>
7201          * <td></td>
7202          * </tr>
7203          * <tr>
7204          * <td>int</td>
7205          * <td>{@link #TYPE}</td>
7206          * <td>{@link #DATA2}</td>
7207          * <td>Allowed values are:
7208          * <p>
7209          * <ul>
7210          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
7211          * <li>{@link #TYPE_HOME}</li>
7212          * <li>{@link #TYPE_WORK}</li>
7213          * <li>{@link #TYPE_OTHER}</li>
7214          * </ul>
7215          * </p>
7216          * </td>
7217          * </tr>
7218          * <tr>
7219          * <td>String</td>
7220          * <td>{@link #LABEL}</td>
7221          * <td>{@link #DATA3}</td>
7222          * <td></td>
7223          * </tr>
7224          * <tr>
7225          * <td>String</td>
7226          * <td>{@link #STREET}</td>
7227          * <td>{@link #DATA4}</td>
7228          * <td></td>
7229          * </tr>
7230          * <tr>
7231          * <td>String</td>
7232          * <td>{@link #POBOX}</td>
7233          * <td>{@link #DATA5}</td>
7234          * <td>Post Office Box number</td>
7235          * </tr>
7236          * <tr>
7237          * <td>String</td>
7238          * <td>{@link #NEIGHBORHOOD}</td>
7239          * <td>{@link #DATA6}</td>
7240          * <td></td>
7241          * </tr>
7242          * <tr>
7243          * <td>String</td>
7244          * <td>{@link #CITY}</td>
7245          * <td>{@link #DATA7}</td>
7246          * <td></td>
7247          * </tr>
7248          * <tr>
7249          * <td>String</td>
7250          * <td>{@link #REGION}</td>
7251          * <td>{@link #DATA8}</td>
7252          * <td></td>
7253          * </tr>
7254          * <tr>
7255          * <td>String</td>
7256          * <td>{@link #POSTCODE}</td>
7257          * <td>{@link #DATA9}</td>
7258          * <td></td>
7259          * </tr>
7260          * <tr>
7261          * <td>String</td>
7262          * <td>{@link #COUNTRY}</td>
7263          * <td>{@link #DATA10}</td>
7264          * <td></td>
7265          * </tr>
7266          * </table>
7267          */
7268         public static final class StructuredPostal implements DataColumnsWithJoins, CommonColumns,
7269                 ContactCounts {
7270             /**
7271              * This utility class cannot be instantiated
7272              */
StructuredPostal()7273             private StructuredPostal() {
7274             }
7275 
7276             /** MIME type used when storing this in data table. */
7277             public static final String CONTENT_ITEM_TYPE =
7278                     "vnd.android.cursor.item/postal-address_v2";
7279 
7280             /**
7281              * The MIME type of {@link #CONTENT_URI} providing a directory of
7282              * postal addresses.
7283              */
7284             public static final String CONTENT_TYPE = "vnd.android.cursor.dir/postal-address_v2";
7285 
7286             /**
7287              * The content:// style URI for all data records of the
7288              * {@link StructuredPostal#CONTENT_ITEM_TYPE} MIME type.
7289              */
7290             public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
7291                     "postals");
7292 
7293             public static final int TYPE_HOME = 1;
7294             public static final int TYPE_WORK = 2;
7295             public static final int TYPE_OTHER = 3;
7296 
7297             /**
7298              * The full, unstructured postal address. <i>This field must be
7299              * consistent with any structured data.</i>
7300              * <p>
7301              * Type: TEXT
7302              */
7303             public static final String FORMATTED_ADDRESS = DATA;
7304 
7305             /**
7306              * Can be street, avenue, road, etc. This element also includes the
7307              * house number and room/apartment/flat/floor number.
7308              * <p>
7309              * Type: TEXT
7310              */
7311             public static final String STREET = DATA4;
7312 
7313             /**
7314              * Covers actual P.O. boxes, drawers, locked bags, etc. This is
7315              * usually but not always mutually exclusive with street.
7316              * <p>
7317              * Type: TEXT
7318              */
7319             public static final String POBOX = DATA5;
7320 
7321             /**
7322              * This is used to disambiguate a street address when a city
7323              * contains more than one street with the same name, or to specify a
7324              * small place whose mail is routed through a larger postal town. In
7325              * China it could be a county or a minor city.
7326              * <p>
7327              * Type: TEXT
7328              */
7329             public static final String NEIGHBORHOOD = DATA6;
7330 
7331             /**
7332              * Can be city, village, town, borough, etc. This is the postal town
7333              * and not necessarily the place of residence or place of business.
7334              * <p>
7335              * Type: TEXT
7336              */
7337             public static final String CITY = DATA7;
7338 
7339             /**
7340              * A state, province, county (in Ireland), Land (in Germany),
7341              * departement (in France), etc.
7342              * <p>
7343              * Type: TEXT
7344              */
7345             public static final String REGION = DATA8;
7346 
7347             /**
7348              * Postal code. Usually country-wide, but sometimes specific to the
7349              * city (e.g. "2" in "Dublin 2, Ireland" addresses).
7350              * <p>
7351              * Type: TEXT
7352              */
7353             public static final String POSTCODE = DATA9;
7354 
7355             /**
7356              * The name or code of the country.
7357              * <p>
7358              * Type: TEXT
7359              */
7360             public static final String COUNTRY = DATA10;
7361 
7362             /**
7363              * Return the string resource that best describes the given
7364              * {@link #TYPE}. Will always return a valid resource.
7365              */
getTypeLabelResource(int type)7366             public static final int getTypeLabelResource(int type) {
7367                 switch (type) {
7368                     case TYPE_HOME: return com.android.internal.R.string.postalTypeHome;
7369                     case TYPE_WORK: return com.android.internal.R.string.postalTypeWork;
7370                     case TYPE_OTHER: return com.android.internal.R.string.postalTypeOther;
7371                     default: return com.android.internal.R.string.postalTypeCustom;
7372                 }
7373             }
7374 
7375             /**
7376              * Return a {@link CharSequence} that best describes the given type,
7377              * possibly substituting the given {@link #LABEL} value
7378              * for {@link #TYPE_CUSTOM}.
7379              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)7380             public static final CharSequence getTypeLabel(Resources res, int type,
7381                     @Nullable CharSequence label) {
7382                 if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
7383                     return label;
7384                 } else {
7385                     final int labelRes = getTypeLabelResource(type);
7386                     return res.getText(labelRes);
7387                 }
7388             }
7389         }
7390 
7391         /**
7392          * <p>
7393          * A data kind representing an IM address
7394          * </p>
7395          * <p>
7396          * You can use all columns defined for {@link ContactsContract.Data} as
7397          * well as the following aliases.
7398          * </p>
7399          * <h2>Column aliases</h2>
7400          * <table class="jd-sumtable">
7401          * <tr>
7402          * <th>Type</th>
7403          * <th>Alias</th><th colspan='2'>Data column</th>
7404          * </tr>
7405          * <tr>
7406          * <td>String</td>
7407          * <td>{@link #DATA}</td>
7408          * <td>{@link #DATA1}</td>
7409          * <td></td>
7410          * </tr>
7411          * <tr>
7412          * <td>int</td>
7413          * <td>{@link #TYPE}</td>
7414          * <td>{@link #DATA2}</td>
7415          * <td>Allowed values are:
7416          * <p>
7417          * <ul>
7418          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
7419          * <li>{@link #TYPE_HOME}</li>
7420          * <li>{@link #TYPE_WORK}</li>
7421          * <li>{@link #TYPE_OTHER}</li>
7422          * </ul>
7423          * </p>
7424          * </td>
7425          * </tr>
7426          * <tr>
7427          * <td>String</td>
7428          * <td>{@link #LABEL}</td>
7429          * <td>{@link #DATA3}</td>
7430          * <td></td>
7431          * </tr>
7432          * <tr>
7433          * <td>String</td>
7434          * <td>{@link #PROTOCOL}</td>
7435          * <td>{@link #DATA5}</td>
7436          * <td>
7437          * <p>
7438          * Allowed value: {@link #PROTOCOL_CUSTOM}. Also provide the actual protocol name
7439          * as {@link #CUSTOM_PROTOCOL}.
7440          * </p>
7441          * </td>
7442          * </tr>
7443          * <tr>
7444          * <td>String</td>
7445          * <td>{@link #CUSTOM_PROTOCOL}</td>
7446          * <td>{@link #DATA6}</td>
7447          * <td></td>
7448          * </tr>
7449          * </table>
7450          *
7451          * @deprecated This field may not be well supported by some contacts apps and is discouraged
7452          * to use.
7453          */
7454         @Deprecated
7455         public static final class Im implements DataColumnsWithJoins, CommonColumns, ContactCounts {
7456             /**
7457              * This utility class cannot be instantiated
7458              */
Im()7459             private Im() {}
7460 
7461             /** MIME type used when storing this in data table. */
7462             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im";
7463 
7464             public static final int TYPE_HOME = 1;
7465             public static final int TYPE_WORK = 2;
7466             public static final int TYPE_OTHER = 3;
7467 
7468             /**
7469              * This column should always be set to {@link #PROTOCOL_CUSTOM} and
7470              * the {@link #CUSTOM_PROTOCOL} should contain the name of the custom protocol.
7471              * The other predefined protocols are deprecated and should not be used.
7472              */
7473             public static final String PROTOCOL = DATA5;
7474 
7475             public static final String CUSTOM_PROTOCOL = DATA6;
7476 
7477             /*
7478              * The predefined IM protocol types.
7479              */
7480             public static final int PROTOCOL_CUSTOM = -1;
7481             /**
7482              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
7483              */
7484             @Deprecated
7485             public static final int PROTOCOL_AIM = 0;
7486             /**
7487              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
7488              */
7489             @Deprecated
7490             public static final int PROTOCOL_MSN = 1;
7491             /**
7492              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
7493              */
7494             @Deprecated
7495             public static final int PROTOCOL_YAHOO = 2;
7496             /**
7497              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
7498              */
7499             @Deprecated
7500             public static final int PROTOCOL_SKYPE = 3;
7501             /**
7502              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
7503              */
7504             @Deprecated
7505             public static final int PROTOCOL_QQ = 4;
7506             /**
7507              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
7508              */
7509             @Deprecated
7510             public static final int PROTOCOL_GOOGLE_TALK = 5;
7511             /**
7512              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
7513              */
7514             @Deprecated
7515             public static final int PROTOCOL_ICQ = 6;
7516             /**
7517              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
7518              */
7519             @Deprecated
7520             public static final int PROTOCOL_JABBER = 7;
7521             /**
7522              * @deprecated Use {@link #PROTOCOL_CUSTOM} with {@link #CUSTOM_PROTOCOL}.
7523              */
7524             @Deprecated
7525             public static final int PROTOCOL_NETMEETING = 8;
7526 
7527             /**
7528              * Return the string resource that best describes the given
7529              * {@link #TYPE}. Will always return a valid resource.
7530              */
getTypeLabelResource(int type)7531             public static final int getTypeLabelResource(int type) {
7532                 switch (type) {
7533                     case TYPE_HOME: return com.android.internal.R.string.imTypeHome;
7534                     case TYPE_WORK: return com.android.internal.R.string.imTypeWork;
7535                     case TYPE_OTHER: return com.android.internal.R.string.imTypeOther;
7536                     default: return com.android.internal.R.string.imTypeCustom;
7537                 }
7538             }
7539 
7540             /**
7541              * Return a {@link CharSequence} that best describes the given type,
7542              * possibly substituting the given {@link #LABEL} value
7543              * for {@link #TYPE_CUSTOM}.
7544              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)7545             public static final CharSequence getTypeLabel(Resources res, int type,
7546                     @Nullable CharSequence label) {
7547                 if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
7548                     return label;
7549                 } else {
7550                     final int labelRes = getTypeLabelResource(type);
7551                     return res.getText(labelRes);
7552                 }
7553             }
7554 
7555             /**
7556              * Return the string resource that best describes the given
7557              * {@link #PROTOCOL}. Will always return a valid resource.
7558              */
getProtocolLabelResource(int type)7559             public static final int getProtocolLabelResource(int type) {
7560                 switch (type) {
7561                     case PROTOCOL_AIM: return com.android.internal.R.string.imProtocolAim;
7562                     case PROTOCOL_MSN: return com.android.internal.R.string.imProtocolMsn;
7563                     case PROTOCOL_YAHOO: return com.android.internal.R.string.imProtocolYahoo;
7564                     case PROTOCOL_SKYPE: return com.android.internal.R.string.imProtocolSkype;
7565                     case PROTOCOL_QQ: return com.android.internal.R.string.imProtocolQq;
7566                     case PROTOCOL_GOOGLE_TALK: return com.android.internal.R.string.imProtocolGoogleTalk;
7567                     case PROTOCOL_ICQ: return com.android.internal.R.string.imProtocolIcq;
7568                     case PROTOCOL_JABBER: return com.android.internal.R.string.imProtocolJabber;
7569                     case PROTOCOL_NETMEETING: return com.android.internal.R.string.imProtocolNetMeeting;
7570                     default: return com.android.internal.R.string.imProtocolCustom;
7571                 }
7572             }
7573 
7574             /**
7575              * Return a {@link CharSequence} that best describes the given
7576              * protocol, possibly substituting the given
7577              * {@link #CUSTOM_PROTOCOL} value for {@link #PROTOCOL_CUSTOM}.
7578              */
getProtocolLabel(Resources res, int type, CharSequence label)7579             public static final CharSequence getProtocolLabel(Resources res, int type,
7580                     CharSequence label) {
7581                 if (type == PROTOCOL_CUSTOM && !TextUtils.isEmpty(label)) {
7582                     return label;
7583                 } else {
7584                     final int labelRes = getProtocolLabelResource(type);
7585                     return res.getText(labelRes);
7586                 }
7587             }
7588         }
7589 
7590         /**
7591          * <p>
7592          * A data kind representing an organization.
7593          * </p>
7594          * <p>
7595          * You can use all columns defined for {@link ContactsContract.Data} as
7596          * well as the following aliases.
7597          * </p>
7598          * <h2>Column aliases</h2>
7599          * <table class="jd-sumtable">
7600          * <tr>
7601          * <th>Type</th>
7602          * <th>Alias</th><th colspan='2'>Data column</th>
7603          * </tr>
7604          * <tr>
7605          * <td>String</td>
7606          * <td>{@link #COMPANY}</td>
7607          * <td>{@link #DATA1}</td>
7608          * <td></td>
7609          * </tr>
7610          * <tr>
7611          * <td>int</td>
7612          * <td>{@link #TYPE}</td>
7613          * <td>{@link #DATA2}</td>
7614          * <td>Allowed values are:
7615          * <p>
7616          * <ul>
7617          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
7618          * <li>{@link #TYPE_WORK}</li>
7619          * <li>{@link #TYPE_OTHER}</li>
7620          * </ul>
7621          * </p>
7622          * </td>
7623          * </tr>
7624          * <tr>
7625          * <td>String</td>
7626          * <td>{@link #LABEL}</td>
7627          * <td>{@link #DATA3}</td>
7628          * <td></td>
7629          * </tr>
7630          * <tr>
7631          * <td>String</td>
7632          * <td>{@link #TITLE}</td>
7633          * <td>{@link #DATA4}</td>
7634          * <td></td>
7635          * </tr>
7636          * <tr>
7637          * <td>String</td>
7638          * <td>{@link #DEPARTMENT}</td>
7639          * <td>{@link #DATA5}</td>
7640          * <td></td>
7641          * </tr>
7642          * <tr>
7643          * <td>String</td>
7644          * <td>{@link #JOB_DESCRIPTION}</td>
7645          * <td>{@link #DATA6}</td>
7646          * <td></td>
7647          * </tr>
7648          * <tr>
7649          * <td>String</td>
7650          * <td>{@link #SYMBOL}</td>
7651          * <td>{@link #DATA7}</td>
7652          * <td></td>
7653          * </tr>
7654          * <tr>
7655          * <td>String</td>
7656          * <td>{@link #PHONETIC_NAME}</td>
7657          * <td>{@link #DATA8}</td>
7658          * <td></td>
7659          * </tr>
7660          * <tr>
7661          * <td>String</td>
7662          * <td>{@link #OFFICE_LOCATION}</td>
7663          * <td>{@link #DATA9}</td>
7664          * <td></td>
7665          * </tr>
7666          * <tr>
7667          * <td>String</td>
7668          * <td>PHONETIC_NAME_STYLE</td>
7669          * <td>{@link #DATA10}</td>
7670          * <td></td>
7671          * </tr>
7672          * </table>
7673          */
7674         public static final class Organization implements DataColumnsWithJoins, CommonColumns,
7675                 ContactCounts {
7676             /**
7677              * This utility class cannot be instantiated
7678              */
Organization()7679             private Organization() {}
7680 
7681             /** MIME type used when storing this in data table. */
7682             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/organization";
7683 
7684             public static final int TYPE_WORK = 1;
7685             public static final int TYPE_OTHER = 2;
7686 
7687             /**
7688              * The company as the user entered it.
7689              * <P>Type: TEXT</P>
7690              */
7691             public static final String COMPANY = DATA;
7692 
7693             /**
7694              * The position title at this company as the user entered it.
7695              * <P>Type: TEXT</P>
7696              */
7697             public static final String TITLE = DATA4;
7698 
7699             /**
7700              * The department at this company as the user entered it.
7701              * <P>Type: TEXT</P>
7702              */
7703             public static final String DEPARTMENT = DATA5;
7704 
7705             /**
7706              * The job description at this company as the user entered it.
7707              * <P>Type: TEXT</P>
7708              */
7709             public static final String JOB_DESCRIPTION = DATA6;
7710 
7711             /**
7712              * The symbol of this company as the user entered it.
7713              * <P>Type: TEXT</P>
7714              */
7715             public static final String SYMBOL = DATA7;
7716 
7717             /**
7718              * The phonetic name of this company as the user entered it.
7719              * <P>Type: TEXT</P>
7720              */
7721             public static final String PHONETIC_NAME = DATA8;
7722 
7723             /**
7724              * The office location of this organization.
7725              * <P>Type: TEXT</P>
7726              */
7727             public static final String OFFICE_LOCATION = DATA9;
7728 
7729             /**
7730              * The alphabet used for capturing the phonetic name.
7731              * See {@link ContactsContract.PhoneticNameStyle}.
7732              */
7733             public static final String PHONETIC_NAME_STYLE = DATA10;
7734 
7735             /**
7736              * Return the string resource that best describes the given
7737              * {@link #TYPE}. Will always return a valid resource.
7738              */
getTypeLabelResource(int type)7739             public static final int getTypeLabelResource(int type) {
7740                 switch (type) {
7741                     case TYPE_WORK: return com.android.internal.R.string.orgTypeWork;
7742                     case TYPE_OTHER: return com.android.internal.R.string.orgTypeOther;
7743                     default: return com.android.internal.R.string.orgTypeCustom;
7744                 }
7745             }
7746 
7747             /**
7748              * Return a {@link CharSequence} that best describes the given type,
7749              * possibly substituting the given {@link #LABEL} value
7750              * for {@link #TYPE_CUSTOM}.
7751              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)7752             public static final CharSequence getTypeLabel(Resources res, int type,
7753                     @Nullable CharSequence label) {
7754                 if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
7755                     return label;
7756                 } else {
7757                     final int labelRes = getTypeLabelResource(type);
7758                     return res.getText(labelRes);
7759                 }
7760             }
7761         }
7762 
7763         /**
7764          * <p>
7765          * A data kind representing a relation.
7766          * </p>
7767          * <p>
7768          * You can use all columns defined for {@link ContactsContract.Data} as
7769          * well as the following aliases.
7770          * </p>
7771          * <h2>Column aliases</h2>
7772          * <table class="jd-sumtable">
7773          * <tr>
7774          * <th>Type</th>
7775          * <th>Alias</th><th colspan='2'>Data column</th>
7776          * </tr>
7777          * <tr>
7778          * <td>String</td>
7779          * <td>{@link #NAME}</td>
7780          * <td>{@link #DATA1}</td>
7781          * <td></td>
7782          * </tr>
7783          * <tr>
7784          * <td>int</td>
7785          * <td>{@link #TYPE}</td>
7786          * <td>{@link #DATA2}</td>
7787          * <td>Allowed values are:
7788          * <p>
7789          * <ul>
7790          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
7791          * <li>{@link #TYPE_ASSISTANT}</li>
7792          * <li>{@link #TYPE_BROTHER}</li>
7793          * <li>{@link #TYPE_CHILD}</li>
7794          * <li>{@link #TYPE_DOMESTIC_PARTNER}</li>
7795          * <li>{@link #TYPE_FATHER}</li>
7796          * <li>{@link #TYPE_FRIEND}</li>
7797          * <li>{@link #TYPE_MANAGER}</li>
7798          * <li>{@link #TYPE_MOTHER}</li>
7799          * <li>{@link #TYPE_PARENT}</li>
7800          * <li>{@link #TYPE_PARTNER}</li>
7801          * <li>{@link #TYPE_REFERRED_BY}</li>
7802          * <li>{@link #TYPE_RELATIVE}</li>
7803          * <li>{@link #TYPE_SISTER}</li>
7804          * <li>{@link #TYPE_SPOUSE}</li>
7805          * </ul>
7806          * </p>
7807          * </td>
7808          * </tr>
7809          * <tr>
7810          * <td>String</td>
7811          * <td>{@link #LABEL}</td>
7812          * <td>{@link #DATA3}</td>
7813          * <td></td>
7814          * </tr>
7815          * </table>
7816          */
7817         public static final class Relation implements DataColumnsWithJoins, CommonColumns,
7818                 ContactCounts {
7819             /**
7820              * This utility class cannot be instantiated
7821              */
Relation()7822             private Relation() {}
7823 
7824             /** MIME type used when storing this in data table. */
7825             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/relation";
7826 
7827             public static final int TYPE_ASSISTANT = 1;
7828             public static final int TYPE_BROTHER = 2;
7829             public static final int TYPE_CHILD = 3;
7830             public static final int TYPE_DOMESTIC_PARTNER = 4;
7831             public static final int TYPE_FATHER = 5;
7832             public static final int TYPE_FRIEND = 6;
7833             public static final int TYPE_MANAGER = 7;
7834             public static final int TYPE_MOTHER = 8;
7835             public static final int TYPE_PARENT = 9;
7836             public static final int TYPE_PARTNER = 10;
7837             public static final int TYPE_REFERRED_BY = 11;
7838             public static final int TYPE_RELATIVE = 12;
7839             public static final int TYPE_SISTER = 13;
7840             public static final int TYPE_SPOUSE = 14;
7841 
7842             /**
7843              * The name of the relative as the user entered it.
7844              * <P>Type: TEXT</P>
7845              */
7846             public static final String NAME = DATA;
7847 
7848             /**
7849              * Return the string resource that best describes the given
7850              * {@link #TYPE}. Will always return a valid resource.
7851              */
getTypeLabelResource(int type)7852             public static final int getTypeLabelResource(int type) {
7853                 switch (type) {
7854                     case TYPE_ASSISTANT: return com.android.internal.R.string.relationTypeAssistant;
7855                     case TYPE_BROTHER: return com.android.internal.R.string.relationTypeBrother;
7856                     case TYPE_CHILD: return com.android.internal.R.string.relationTypeChild;
7857                     case TYPE_DOMESTIC_PARTNER:
7858                             return com.android.internal.R.string.relationTypeDomesticPartner;
7859                     case TYPE_FATHER: return com.android.internal.R.string.relationTypeFather;
7860                     case TYPE_FRIEND: return com.android.internal.R.string.relationTypeFriend;
7861                     case TYPE_MANAGER: return com.android.internal.R.string.relationTypeManager;
7862                     case TYPE_MOTHER: return com.android.internal.R.string.relationTypeMother;
7863                     case TYPE_PARENT: return com.android.internal.R.string.relationTypeParent;
7864                     case TYPE_PARTNER: return com.android.internal.R.string.relationTypePartner;
7865                     case TYPE_REFERRED_BY:
7866                             return com.android.internal.R.string.relationTypeReferredBy;
7867                     case TYPE_RELATIVE: return com.android.internal.R.string.relationTypeRelative;
7868                     case TYPE_SISTER: return com.android.internal.R.string.relationTypeSister;
7869                     case TYPE_SPOUSE: return com.android.internal.R.string.relationTypeSpouse;
7870                     default: return com.android.internal.R.string.orgTypeCustom;
7871                 }
7872             }
7873 
7874             /**
7875              * Return a {@link CharSequence} that best describes the given type,
7876              * possibly substituting the given {@link #LABEL} value
7877              * for {@link #TYPE_CUSTOM}.
7878              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)7879             public static final CharSequence getTypeLabel(Resources res, int type,
7880                     @Nullable CharSequence label) {
7881                 if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
7882                     return label;
7883                 } else {
7884                     final int labelRes = getTypeLabelResource(type);
7885                     return res.getText(labelRes);
7886                 }
7887             }
7888         }
7889 
7890         /**
7891          * <p>
7892          * A data kind representing an event.
7893          * </p>
7894          * <p>
7895          * You can use all columns defined for {@link ContactsContract.Data} as
7896          * well as the following aliases.
7897          * </p>
7898          * <h2>Column aliases</h2>
7899          * <table class="jd-sumtable">
7900          * <tr>
7901          * <th>Type</th>
7902          * <th>Alias</th><th colspan='2'>Data column</th>
7903          * </tr>
7904          * <tr>
7905          * <td>String</td>
7906          * <td>{@link #START_DATE}</td>
7907          * <td>{@link #DATA1}</td>
7908          * <td></td>
7909          * </tr>
7910          * <tr>
7911          * <td>int</td>
7912          * <td>{@link #TYPE}</td>
7913          * <td>{@link #DATA2}</td>
7914          * <td>Allowed values are:
7915          * <p>
7916          * <ul>
7917          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
7918          * <li>{@link #TYPE_ANNIVERSARY}</li>
7919          * <li>{@link #TYPE_OTHER}</li>
7920          * <li>{@link #TYPE_BIRTHDAY}</li>
7921          * </ul>
7922          * </p>
7923          * </td>
7924          * </tr>
7925          * <tr>
7926          * <td>String</td>
7927          * <td>{@link #LABEL}</td>
7928          * <td>{@link #DATA3}</td>
7929          * <td></td>
7930          * </tr>
7931          * </table>
7932          */
7933         public static final class Event implements DataColumnsWithJoins, CommonColumns,
7934                 ContactCounts {
7935             /**
7936              * This utility class cannot be instantiated
7937              */
Event()7938             private Event() {}
7939 
7940             /** MIME type used when storing this in data table. */
7941             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_event";
7942 
7943             public static final int TYPE_ANNIVERSARY = 1;
7944             public static final int TYPE_OTHER = 2;
7945             public static final int TYPE_BIRTHDAY = 3;
7946 
7947             /**
7948              * The event start date as the user entered it.
7949              * <P>Type: TEXT</P>
7950              */
7951             public static final String START_DATE = DATA;
7952 
7953             /**
7954              * Return the string resource that best describes the given
7955              * {@link #TYPE}. Will always return a valid resource.
7956              */
getTypeResource(Integer type)7957             public static int getTypeResource(Integer type) {
7958                 if (type == null) {
7959                     return com.android.internal.R.string.eventTypeOther;
7960                 }
7961                 switch (type) {
7962                     case TYPE_ANNIVERSARY:
7963                         return com.android.internal.R.string.eventTypeAnniversary;
7964                     case TYPE_BIRTHDAY: return com.android.internal.R.string.eventTypeBirthday;
7965                     case TYPE_OTHER: return com.android.internal.R.string.eventTypeOther;
7966                     default: return com.android.internal.R.string.eventTypeCustom;
7967                 }
7968             }
7969 
7970             /**
7971              * Return a {@link CharSequence} that best describes the given type,
7972              * possibly substituting the given {@link #LABEL} value
7973              * for {@link #TYPE_CUSTOM}.
7974              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)7975             public static final CharSequence getTypeLabel(Resources res, int type,
7976                     @Nullable CharSequence label) {
7977                 if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
7978                     return label;
7979                 } else {
7980                     final int labelRes = getTypeResource(type);
7981                     return res.getText(labelRes);
7982                 }
7983             }
7984         }
7985 
7986         /**
7987          * <p>
7988          * A data kind representing a photo for the contact.
7989          * </p>
7990          * <p>
7991          * Some sync adapters will choose to download photos in a separate
7992          * pass. A common pattern is to use columns {@link ContactsContract.Data#SYNC1}
7993          * through {@link ContactsContract.Data#SYNC4} to store temporary
7994          * data, e.g. the image URL or ID, state of download, server-side version
7995          * of the image.  It is allowed for the {@link #PHOTO} to be null.
7996          * </p>
7997          * <p>
7998          * You can use all columns defined for {@link ContactsContract.Data} as
7999          * well as the following aliases.
8000          * </p>
8001          * <h2>Column aliases</h2>
8002          * <table class="jd-sumtable">
8003          * <tr>
8004          * <th>Type</th>
8005          * <th>Alias</th><th colspan='2'>Data column</th>
8006          * </tr>
8007          * <tr>
8008          * <td>NUMBER</td>
8009          * <td>{@link #PHOTO_FILE_ID}</td>
8010          * <td>{@link #DATA14}</td>
8011          * <td>ID of the hi-res photo file.</td>
8012          * </tr>
8013          * <tr>
8014          * <td>BLOB</td>
8015          * <td>{@link #PHOTO}</td>
8016          * <td>{@link #DATA15}</td>
8017          * <td>By convention, binary data is stored in DATA15.  The thumbnail of the
8018          * photo is stored in this column.</td>
8019          * </tr>
8020          * </table>
8021          */
8022         public static final class Photo implements DataColumnsWithJoins, ContactCounts {
8023             /**
8024              * This utility class cannot be instantiated
8025              */
Photo()8026             private Photo() {}
8027 
8028             /** MIME type used when storing this in data table. */
8029             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo";
8030 
8031             /**
8032              * Photo file ID for the display photo of the raw contact.
8033              * See {@link ContactsContract.DisplayPhoto}.
8034              * <p>
8035              * Type: NUMBER
8036              */
8037             public static final String PHOTO_FILE_ID = DATA14;
8038 
8039             /**
8040              * Thumbnail photo of the raw contact. This is the raw bytes of an image
8041              * that could be inflated using {@link android.graphics.BitmapFactory}.
8042              * <p>
8043              * Type: BLOB
8044              */
8045             public static final String PHOTO = DATA15;
8046         }
8047 
8048         /**
8049          * <p>
8050          * Notes about the contact.
8051          * </p>
8052          * <p>
8053          * You can use all columns defined for {@link ContactsContract.Data} as
8054          * well as the following aliases.
8055          * </p>
8056          * <h2>Column aliases</h2>
8057          * <table class="jd-sumtable">
8058          * <tr>
8059          * <th>Type</th>
8060          * <th>Alias</th><th colspan='2'>Data column</th>
8061          * </tr>
8062          * <tr>
8063          * <td>String</td>
8064          * <td>{@link #NOTE}</td>
8065          * <td>{@link #DATA1}</td>
8066          * <td></td>
8067          * </tr>
8068          * </table>
8069          */
8070         public static final class Note implements DataColumnsWithJoins, ContactCounts {
8071             /**
8072              * This utility class cannot be instantiated
8073              */
Note()8074             private Note() {}
8075 
8076             /** MIME type used when storing this in data table. */
8077             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/note";
8078 
8079             /**
8080              * The note text.
8081              * <P>Type: TEXT</P>
8082              */
8083             public static final String NOTE = DATA1;
8084         }
8085 
8086         /**
8087          * <p>
8088          * Group Membership.
8089          * </p>
8090          * <p>
8091          * You can use all columns defined for {@link ContactsContract.Data} as
8092          * well as the following aliases.
8093          * </p>
8094          * <h2>Column aliases</h2>
8095          * <table class="jd-sumtable">
8096          * <tr>
8097          * <th>Type</th>
8098          * <th>Alias</th><th colspan='2'>Data column</th>
8099          * </tr>
8100          * <tr>
8101          * <td>long</td>
8102          * <td>{@link #GROUP_ROW_ID}</td>
8103          * <td>{@link #DATA1}</td>
8104          * <td></td>
8105          * </tr>
8106          * <tr>
8107          * <td>String</td>
8108          * <td>{@link #GROUP_SOURCE_ID}</td>
8109          * <td>none</td>
8110          * <td>
8111          * <p>
8112          * The sourceid of the group that this group membership refers to.
8113          * Exactly one of this or {@link #GROUP_ROW_ID} must be set when
8114          * inserting a row.
8115          * </p>
8116          * <p>
8117          * If this field is specified, the provider will first try to
8118          * look up a group with this {@link Groups Groups.SOURCE_ID}.  If such a group
8119          * is found, it will use the corresponding row id.  If the group is not
8120          * found, it will create one.
8121          * </td>
8122          * </tr>
8123          * </table>
8124          */
8125         public static final class GroupMembership implements DataColumnsWithJoins, ContactCounts {
8126             /**
8127              * This utility class cannot be instantiated
8128              */
GroupMembership()8129             private GroupMembership() {}
8130 
8131             /** MIME type used when storing this in data table. */
8132             public static final String CONTENT_ITEM_TYPE =
8133                     "vnd.android.cursor.item/group_membership";
8134 
8135             /**
8136              * The row id of the group that this group membership refers to. Exactly one of
8137              * this or {@link #GROUP_SOURCE_ID} must be set when inserting a row.
8138              * <P>Type: INTEGER</P>
8139              */
8140             public static final String GROUP_ROW_ID = DATA1;
8141 
8142             /**
8143              * The sourceid of the group that this group membership refers to.  Exactly one of
8144              * this or {@link #GROUP_ROW_ID} must be set when inserting a row.
8145              * <P>Type: TEXT</P>
8146              */
8147             public static final String GROUP_SOURCE_ID = "group_sourceid";
8148         }
8149 
8150         /**
8151          * <p>
8152          * A data kind representing a website related to the contact.
8153          * </p>
8154          * <p>
8155          * You can use all columns defined for {@link ContactsContract.Data} as
8156          * well as the following aliases.
8157          * </p>
8158          * <h2>Column aliases</h2>
8159          * <table class="jd-sumtable">
8160          * <tr>
8161          * <th>Type</th>
8162          * <th>Alias</th><th colspan='2'>Data column</th>
8163          * </tr>
8164          * <tr>
8165          * <td>String</td>
8166          * <td>{@link #URL}</td>
8167          * <td>{@link #DATA1}</td>
8168          * <td></td>
8169          * </tr>
8170          * <tr>
8171          * <td>int</td>
8172          * <td>{@link #TYPE}</td>
8173          * <td>{@link #DATA2}</td>
8174          * <td>Allowed values are:
8175          * <p>
8176          * <ul>
8177          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
8178          * <li>{@link #TYPE_HOMEPAGE}</li>
8179          * <li>{@link #TYPE_BLOG}</li>
8180          * <li>{@link #TYPE_PROFILE}</li>
8181          * <li>{@link #TYPE_HOME}</li>
8182          * <li>{@link #TYPE_WORK}</li>
8183          * <li>{@link #TYPE_FTP}</li>
8184          * <li>{@link #TYPE_OTHER}</li>
8185          * </ul>
8186          * </p>
8187          * </td>
8188          * </tr>
8189          * <tr>
8190          * <td>String</td>
8191          * <td>{@link #LABEL}</td>
8192          * <td>{@link #DATA3}</td>
8193          * <td></td>
8194          * </tr>
8195          * </table>
8196          */
8197         public static final class Website implements DataColumnsWithJoins, CommonColumns,
8198                 ContactCounts {
8199             /**
8200              * This utility class cannot be instantiated
8201              */
Website()8202             private Website() {}
8203 
8204             /** MIME type used when storing this in data table. */
8205             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/website";
8206 
8207             public static final int TYPE_HOMEPAGE = 1;
8208             public static final int TYPE_BLOG = 2;
8209             public static final int TYPE_PROFILE = 3;
8210             public static final int TYPE_HOME = 4;
8211             public static final int TYPE_WORK = 5;
8212             public static final int TYPE_FTP = 6;
8213             public static final int TYPE_OTHER = 7;
8214 
8215             /**
8216              * The website URL string.
8217              * <P>Type: TEXT</P>
8218              */
8219             public static final String URL = DATA;
8220         }
8221 
8222         /**
8223          * <p>
8224          * A data kind representing a SIP address for the contact.
8225          * </p>
8226          * <p>
8227          * You can use all columns defined for {@link ContactsContract.Data} as
8228          * well as the following aliases.
8229          * </p>
8230          * <h2>Column aliases</h2>
8231          * <table class="jd-sumtable">
8232          * <tr>
8233          * <th>Type</th>
8234          * <th>Alias</th><th colspan='2'>Data column</th>
8235          * </tr>
8236          * <tr>
8237          * <td>String</td>
8238          * <td>{@link #SIP_ADDRESS}</td>
8239          * <td>{@link #DATA1}</td>
8240          * <td></td>
8241          * </tr>
8242          * <tr>
8243          * <td>int</td>
8244          * <td>{@link #TYPE}</td>
8245          * <td>{@link #DATA2}</td>
8246          * <td>Allowed values are:
8247          * <p>
8248          * <ul>
8249          * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li>
8250          * <li>{@link #TYPE_HOME}</li>
8251          * <li>{@link #TYPE_WORK}</li>
8252          * <li>{@link #TYPE_OTHER}</li>
8253          * </ul>
8254          * </p>
8255          * </td>
8256          * </tr>
8257          * <tr>
8258          * <td>String</td>
8259          * <td>{@link #LABEL}</td>
8260          * <td>{@link #DATA3}</td>
8261          * <td></td>
8262          * </tr>
8263          * </table>
8264          *
8265          * @deprecated This field may not be well supported by some contacts apps and is discouraged
8266          * to use.
8267          */
8268         @Deprecated
8269         public static final class SipAddress implements DataColumnsWithJoins, CommonColumns,
8270                 ContactCounts {
8271             /**
8272              * This utility class cannot be instantiated
8273              */
SipAddress()8274             private SipAddress() {}
8275 
8276             /** MIME type used when storing this in data table. */
8277             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sip_address";
8278 
8279             public static final int TYPE_HOME = 1;
8280             public static final int TYPE_WORK = 2;
8281             public static final int TYPE_OTHER = 3;
8282 
8283             /**
8284              * The SIP address.
8285              * <P>Type: TEXT</P>
8286              */
8287             public static final String SIP_ADDRESS = DATA1;
8288             // ...and TYPE and LABEL come from the CommonColumns interface.
8289 
8290             /**
8291              * Return the string resource that best describes the given
8292              * {@link #TYPE}. Will always return a valid resource.
8293              */
getTypeLabelResource(int type)8294             public static final int getTypeLabelResource(int type) {
8295                 switch (type) {
8296                     case TYPE_HOME: return com.android.internal.R.string.sipAddressTypeHome;
8297                     case TYPE_WORK: return com.android.internal.R.string.sipAddressTypeWork;
8298                     case TYPE_OTHER: return com.android.internal.R.string.sipAddressTypeOther;
8299                     default: return com.android.internal.R.string.sipAddressTypeCustom;
8300                 }
8301             }
8302 
8303             /**
8304              * Return a {@link CharSequence} that best describes the given type,
8305              * possibly substituting the given {@link #LABEL} value
8306              * for {@link #TYPE_CUSTOM}.
8307              */
getTypeLabel(Resources res, int type, @Nullable CharSequence label)8308             public static final CharSequence getTypeLabel(Resources res, int type,
8309                     @Nullable CharSequence label) {
8310                 if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
8311                     return label;
8312                 } else {
8313                     final int labelRes = getTypeLabelResource(type);
8314                     return res.getText(labelRes);
8315                 }
8316             }
8317         }
8318 
8319         /**
8320          * A data kind representing an Identity related to the contact.
8321          * <p>
8322          * This can be used as a signal by the aggregator to combine raw contacts into
8323          * contacts, e.g. if two contacts have Identity rows with
8324          * the same NAMESPACE and IDENTITY values the aggregator can know that they refer
8325          * to the same person.
8326          * </p>
8327          */
8328         public static final class Identity implements DataColumnsWithJoins, ContactCounts {
8329             /**
8330              * This utility class cannot be instantiated
8331              */
Identity()8332             private Identity() {}
8333 
8334             /** MIME type used when storing this in data table. */
8335             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/identity";
8336 
8337             /**
8338              * The identity string.
8339              * <P>Type: TEXT</P>
8340              */
8341             public static final String IDENTITY = DataColumns.DATA1;
8342 
8343             /**
8344              * The namespace of the identity string, e.g. "com.google"
8345              * <P>Type: TEXT</P>
8346              */
8347             public static final String NAMESPACE = DataColumns.DATA2;
8348         }
8349 
8350         /**
8351          * <p>
8352          * Convenient functionalities for "callable" data. Note that, this is NOT a separate data
8353          * kind.
8354          * </p>
8355          * <p>
8356          * This URI allows the ContactsProvider to return a unified result for "callable" data
8357          * that users can use for calling purposes. {@link Phone} and {@link SipAddress} are the
8358          * current examples for "callable", but may be expanded to the other types.
8359          * </p>
8360          * <p>
8361          * Each returned row may have a different MIMETYPE and thus different interpretation for
8362          * each column. For example the meaning for {@link Phone}'s type is different than
8363          * {@link SipAddress}'s.
8364          * </p>
8365          */
8366         public static final class Callable implements DataColumnsWithJoins, CommonColumns,
8367                 ContactCounts {
8368             /**
8369              * Similar to {@link Phone#CONTENT_URI}, but returns callable data instead of only
8370              * phone numbers.
8371              */
8372             public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
8373                     "callables");
8374             /**
8375              * <p>Similar to {@link Phone#CONTENT_FILTER_URI}, but allows users to filter callable
8376              * data.
8377              *
8378              * <p class="caution"><b>Caution: </b>This field no longer sorts results based on
8379              * contacts frequency. For more information, see the
8380              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
8381              * page.
8382              */
8383             public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(CONTENT_URI,
8384                     "filter");
8385 
8386             /**
8387              * <p>Similar to {@link Phone#ENTERPRISE_CONTENT_FILTER_URI}, but allows users to filter
8388              * callable data. This URI requires {@link ContactsContract#DIRECTORY_PARAM_KEY} in
8389              * parameters, otherwise it will throw IllegalArgumentException.
8390              *
8391              * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
8392              * this field doesn't sort results based on contacts frequency. For more information,
8393              * see the
8394              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
8395              * page.</p>
8396              */
8397             public static final Uri ENTERPRISE_CONTENT_FILTER_URI = Uri.withAppendedPath(
8398                     CONTENT_URI, "filter_enterprise");
8399         }
8400 
8401         /**
8402          * A special class of data items, used to refer to types of data that can be used to attempt
8403          * to start communicating with a person ({@link Phone} and {@link Email}). Note that this
8404          * is NOT a separate data kind.
8405          *
8406          * This URI allows the ContactsProvider to return a unified result for data items that users
8407          * can use to initiate communications with another contact. {@link Phone} and {@link Email}
8408          * are the current data types in this category.
8409          */
8410         public static final class Contactables implements DataColumnsWithJoins, CommonColumns,
8411                 ContactCounts {
8412             /**
8413              * The content:// style URI for these data items, which requests a directory of data
8414              * rows matching the selection criteria.
8415              */
8416             public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
8417                     "contactables");
8418 
8419             /**
8420              * <p>The content:// style URI for these data items, which allows for a query parameter
8421              * to be appended onto the end to filter for data items matching the query.
8422              *
8423              * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
8424              * this field doesn't sort results based on contacts frequency. For more information,
8425              * see the
8426              * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
8427              * page.
8428              */
8429             public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(
8430                     Contactables.CONTENT_URI, "filter");
8431 
8432             /**
8433              * A boolean parameter for {@link Data#CONTENT_URI}.
8434              * This specifies whether or not the returned data items should be filtered to show
8435              * data items belonging to visible contacts only.
8436              */
8437             public static final String VISIBLE_CONTACTS_ONLY = "visible_contacts_only";
8438         }
8439     }
8440 
8441     /**
8442      * @see Groups
8443      */
8444     protected interface GroupsColumns {
8445         /**
8446          * The data set within the account that this group belongs to.  This allows
8447          * multiple sync adapters for the same account type to distinguish between
8448          * each others' group data.
8449          *
8450          * This is empty by default, and is completely optional.  It only needs to
8451          * be populated if multiple sync adapters are entering distinct group data
8452          * for the same account type and account name.
8453          * <P>Type: TEXT</P>
8454          */
8455         public static final String DATA_SET = "data_set";
8456 
8457         /**
8458          * A concatenation of the account type and data set (delimited by a forward
8459          * slash) - if the data set is empty, this will be the same as the account
8460          * type.  For applications that need to be aware of the data set, this can
8461          * be used instead of account type to distinguish sets of data.  This is
8462          * never intended to be used for specifying accounts.
8463          * @hide
8464          */
8465         public static final String ACCOUNT_TYPE_AND_DATA_SET = "account_type_and_data_set";
8466 
8467         /**
8468          * The display title of this group.
8469          * <p>
8470          * Type: TEXT
8471          */
8472         public static final String TITLE = "title";
8473 
8474         /**
8475          * The package name to use when creating {@link Resources} objects for
8476          * this group. This value is only designed for use when building user
8477          * interfaces, and should not be used to infer the owner.
8478          */
8479         public static final String RES_PACKAGE = "res_package";
8480 
8481         /**
8482          * The display title of this group to load as a resource from
8483          * {@link #RES_PACKAGE}, which may be localized.
8484          * <P>Type: TEXT</P>
8485          */
8486         public static final String TITLE_RES = "title_res";
8487 
8488         /**
8489          * Notes about the group.
8490          * <p>
8491          * Type: TEXT
8492          */
8493         public static final String NOTES = "notes";
8494 
8495         /**
8496          * The ID of this group if it is a System Group, i.e. a group that has a special meaning
8497          * to the sync adapter, null otherwise.
8498          * <P>Type: TEXT</P>
8499          */
8500         public static final String SYSTEM_ID = "system_id";
8501 
8502         /**
8503          * The total number of {@link Contacts} that have
8504          * {@link CommonDataKinds.GroupMembership} in this group. Read-only value that is only
8505          * present when querying {@link Groups#CONTENT_SUMMARY_URI}.
8506          * <p>
8507          * Type: INTEGER
8508          */
8509         public static final String SUMMARY_COUNT = "summ_count";
8510 
8511         /**
8512          * A boolean query parameter that can be used with {@link Groups#CONTENT_SUMMARY_URI}.
8513          * It will additionally return {@link #SUMMARY_GROUP_COUNT_PER_ACCOUNT}.
8514          *
8515          * @hide
8516          */
8517         public static final String PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT =
8518                 "return_group_count_per_account";
8519 
8520         /**
8521          * The total number of groups of the account that a group belongs to.
8522          * This column is available only when the parameter
8523          * {@link #PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT} is specified in
8524          * {@link Groups#CONTENT_SUMMARY_URI}.
8525          *
8526          * For example, when the account "A" has two groups "group1" and "group2", and the account
8527          * "B" has a group "group3", the rows for "group1" and "group2" return "2" and the row for
8528          * "group3" returns "1" for this column.
8529          *
8530          * Note: This counts only non-favorites, non-auto-add, and not deleted groups.
8531          *
8532          * Type: INTEGER
8533          * @hide
8534          */
8535         public static final String SUMMARY_GROUP_COUNT_PER_ACCOUNT = "group_count_per_account";
8536 
8537         /**
8538          * The total number of {@link Contacts} that have both
8539          * {@link CommonDataKinds.GroupMembership} in this group, and also have phone numbers.
8540          * Read-only value that is only present when querying
8541          * {@link Groups#CONTENT_SUMMARY_URI}.
8542          * <p>
8543          * Type: INTEGER
8544          */
8545         public static final String SUMMARY_WITH_PHONES = "summ_phones";
8546 
8547         /**
8548          * Flag indicating if the contacts belonging to this group should be
8549          * visible in any user interface.
8550          * <p>
8551          * Type: INTEGER (boolean)
8552          */
8553         public static final String GROUP_VISIBLE = "group_visible";
8554 
8555         /**
8556          * The "deleted" flag: "0" by default, "1" if the row has been marked
8557          * for deletion. When {@link android.content.ContentResolver#delete} is
8558          * called on a group, it is marked for deletion. The sync adaptor
8559          * deletes the group on the server and then calls ContactResolver.delete
8560          * once more, this time setting the the
8561          * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to
8562          * finalize the data removal.
8563          * <P>Type: INTEGER</P>
8564          */
8565         public static final String DELETED = "deleted";
8566 
8567         /**
8568          * Whether this group should be synced if the SYNC_EVERYTHING settings
8569          * is false for this group's account.
8570          * <p>
8571          * Type: INTEGER (boolean)
8572          */
8573         public static final String SHOULD_SYNC = "should_sync";
8574 
8575         /**
8576          * Any newly created contacts will automatically be added to groups that have this
8577          * flag set to true.
8578          * <p>
8579          * Type: INTEGER (boolean)
8580          */
8581         public static final String AUTO_ADD = "auto_add";
8582 
8583         /**
8584          * When a contacts is marked as a favorites it will be automatically added
8585          * to the groups that have this flag set, and when it is removed from favorites
8586          * it will be removed from these groups.
8587          * <p>
8588          * Type: INTEGER (boolean)
8589          */
8590         public static final String FAVORITES = "favorites";
8591 
8592         /**
8593          * The "read-only" flag: "0" by default, "1" if the row cannot be modified or
8594          * deleted except by a sync adapter.  See {@link ContactsContract#CALLER_IS_SYNCADAPTER}.
8595          * <P>Type: INTEGER</P>
8596          */
8597         public static final String GROUP_IS_READ_ONLY = "group_is_read_only";
8598     }
8599 
8600     /**
8601      * Constants for the groups table. Only per-account groups are supported.
8602      * <h2>Columns</h2>
8603      * <table class="jd-sumtable">
8604      * <tr>
8605      * <th colspan='4'>Groups</th>
8606      * </tr>
8607      * <tr>
8608      * <td>long</td>
8609      * <td>{@link #_ID}</td>
8610      * <td>read-only</td>
8611      * <td>Row ID. Sync adapter should try to preserve row IDs during updates.
8612      * In other words, it would be a really bad idea to delete and reinsert a
8613      * group. A sync adapter should always do an update instead.</td>
8614      * </tr>
8615      # <tr>
8616      * <td>String</td>
8617      * <td>{@link #DATA_SET}</td>
8618      * <td>read/write-once</td>
8619      * <td>
8620      * <p>
8621      * The data set within the account that this group belongs to.  This allows
8622      * multiple sync adapters for the same account type to distinguish between
8623      * each others' group data.  The combination of {@link #ACCOUNT_TYPE},
8624      * {@link #ACCOUNT_NAME}, and {@link #DATA_SET} identifies a set of data
8625      * that is associated with a single sync adapter.
8626      * </p>
8627      * <p>
8628      * This is empty by default, and is completely optional.  It only needs to
8629      * be populated if multiple sync adapters are entering distinct data for
8630      * the same account type and account name.
8631      * </p>
8632      * <p>
8633      * It should be set at the time the group is inserted and never changed
8634      * afterwards.
8635      * </p>
8636      * </td>
8637      * </tr>
8638      * <tr>
8639      * <td>String</td>
8640      * <td>{@link #TITLE}</td>
8641      * <td>read/write</td>
8642      * <td>The display title of this group.</td>
8643      * </tr>
8644      * <tr>
8645      * <td>String</td>
8646      * <td>{@link #NOTES}</td>
8647      * <td>read/write</td>
8648      * <td>Notes about the group.</td>
8649      * </tr>
8650      * <tr>
8651      * <td>String</td>
8652      * <td>{@link #SYSTEM_ID}</td>
8653      * <td>read/write</td>
8654      * <td>The ID of this group if it is a System Group, i.e. a group that has a
8655      * special meaning to the sync adapter, null otherwise.</td>
8656      * </tr>
8657      * <tr>
8658      * <td>int</td>
8659      * <td>{@link #SUMMARY_COUNT}</td>
8660      * <td>read-only</td>
8661      * <td>The total number of {@link Contacts} that have
8662      * {@link CommonDataKinds.GroupMembership} in this group. Read-only value
8663      * that is only present when querying {@link Groups#CONTENT_SUMMARY_URI}.</td>
8664      * </tr>
8665      * <tr>
8666      * <td>int</td>
8667      * <td>{@link #SUMMARY_WITH_PHONES}</td>
8668      * <td>read-only</td>
8669      * <td>The total number of {@link Contacts} that have both
8670      * {@link CommonDataKinds.GroupMembership} in this group, and also have
8671      * phone numbers. Read-only value that is only present when querying
8672      * {@link Groups#CONTENT_SUMMARY_URI}.</td>
8673      * </tr>
8674      * <tr>
8675      * <td>int</td>
8676      * <td>{@link #GROUP_VISIBLE}</td>
8677      * <td>read-only</td>
8678      * <td>Flag indicating if the contacts belonging to this group should be
8679      * visible in any user interface. Allowed values: 0 and 1.</td>
8680      * </tr>
8681      * <tr>
8682      * <td>int</td>
8683      * <td>{@link #DELETED}</td>
8684      * <td>read/write</td>
8685      * <td>The "deleted" flag: "0" by default, "1" if the row has been marked
8686      * for deletion. When {@link android.content.ContentResolver#delete} is
8687      * called on a group, it is marked for deletion. The sync adaptor deletes
8688      * the group on the server and then calls ContactResolver.delete once more,
8689      * this time setting the the {@link ContactsContract#CALLER_IS_SYNCADAPTER}
8690      * query parameter to finalize the data removal.</td>
8691      * </tr>
8692      * <tr>
8693      * <td>int</td>
8694      * <td>{@link #SHOULD_SYNC}</td>
8695      * <td>read/write</td>
8696      * <td>Whether this group should be synced if the SYNC_EVERYTHING settings
8697      * is false for this group's account.</td>
8698      * </tr>
8699      * </table>
8700      */
8701     public static final class Groups implements BaseColumns, GroupsColumns, SyncColumns {
8702         /**
8703          * This utility class cannot be instantiated
8704          */
Groups()8705         private Groups() {
8706         }
8707 
8708         /**
8709          * The content:// style URI for this table
8710          */
8711         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "groups");
8712 
8713         /**
8714          * The content:// style URI for this table joined with details data from
8715          * {@link ContactsContract.Data}.
8716          */
8717         public static final Uri CONTENT_SUMMARY_URI = Uri.withAppendedPath(AUTHORITY_URI,
8718                 "groups_summary");
8719 
8720         /**
8721          * The MIME type of a directory of groups.
8722          */
8723         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/group";
8724 
8725         /**
8726          * The MIME type of a single group.
8727          */
8728         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/group";
8729 
newEntityIterator(Cursor cursor)8730         public static EntityIterator newEntityIterator(Cursor cursor) {
8731             return new EntityIteratorImpl(cursor);
8732         }
8733 
8734         private static class EntityIteratorImpl extends CursorEntityIterator {
EntityIteratorImpl(Cursor cursor)8735             public EntityIteratorImpl(Cursor cursor) {
8736                 super(cursor);
8737             }
8738 
8739             @Override
getEntityAndIncrementCursor(Cursor cursor)8740             public Entity getEntityAndIncrementCursor(Cursor cursor) throws RemoteException {
8741                 // we expect the cursor is already at the row we need to read from
8742                 final ContentValues values = new ContentValues();
8743                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, _ID);
8744                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, ACCOUNT_NAME);
8745                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, ACCOUNT_TYPE);
8746                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, DIRTY);
8747                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, VERSION);
8748                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SOURCE_ID);
8749                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, RES_PACKAGE);
8750                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, TITLE);
8751                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, TITLE_RES);
8752                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, GROUP_VISIBLE);
8753                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYNC1);
8754                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYNC2);
8755                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYNC3);
8756                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYNC4);
8757                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SYSTEM_ID);
8758                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, values, DELETED);
8759                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, NOTES);
8760                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, SHOULD_SYNC);
8761                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, FAVORITES);
8762                 DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, values, AUTO_ADD);
8763                 cursor.moveToNext();
8764                 return new Entity(values);
8765             }
8766         }
8767     }
8768 
8769     /**
8770      * <p>
8771      * Constants for the contact aggregation exceptions table, which contains
8772      * aggregation rules overriding those used by automatic aggregation. This
8773      * type only supports query and update. Neither insert nor delete are
8774      * supported.
8775      * </p>
8776      * <h2>Columns</h2>
8777      * <table class="jd-sumtable">
8778      * <tr>
8779      * <th colspan='4'>AggregationExceptions</th>
8780      * </tr>
8781      * <tr>
8782      * <td>int</td>
8783      * <td>{@link #TYPE}</td>
8784      * <td>read/write</td>
8785      * <td>The type of exception: {@link #TYPE_KEEP_TOGETHER},
8786      * {@link #TYPE_KEEP_SEPARATE} or {@link #TYPE_AUTOMATIC}.</td>
8787      * </tr>
8788      * <tr>
8789      * <td>long</td>
8790      * <td>{@link #RAW_CONTACT_ID1}</td>
8791      * <td>read/write</td>
8792      * <td>A reference to the {@link RawContacts#_ID} of the raw contact that
8793      * the rule applies to.</td>
8794      * </tr>
8795      * <tr>
8796      * <td>long</td>
8797      * <td>{@link #RAW_CONTACT_ID2}</td>
8798      * <td>read/write</td>
8799      * <td>A reference to the other {@link RawContacts#_ID} of the raw contact
8800      * that the rule applies to.</td>
8801      * </tr>
8802      * </table>
8803      */
8804     public static final class AggregationExceptions implements BaseColumns {
8805         /**
8806          * This utility class cannot be instantiated
8807          */
AggregationExceptions()8808         private AggregationExceptions() {}
8809 
8810         /**
8811          * The content:// style URI for this table
8812          */
8813         public static final Uri CONTENT_URI =
8814                 Uri.withAppendedPath(AUTHORITY_URI, "aggregation_exceptions");
8815 
8816         /**
8817          * The MIME type of {@link #CONTENT_URI} providing a directory of data.
8818          */
8819         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/aggregation_exception";
8820 
8821         /**
8822          * The MIME type of a {@link #CONTENT_URI} subdirectory of an aggregation exception
8823          */
8824         public static final String CONTENT_ITEM_TYPE =
8825                 "vnd.android.cursor.item/aggregation_exception";
8826 
8827         /**
8828          * The type of exception: {@link #TYPE_KEEP_TOGETHER}, {@link #TYPE_KEEP_SEPARATE} or
8829          * {@link #TYPE_AUTOMATIC}.
8830          *
8831          * <P>Type: INTEGER</P>
8832          */
8833         public static final String TYPE = "type";
8834 
8835         /**
8836          * Allows the provider to automatically decide whether the specified raw contacts should
8837          * be included in the same aggregate contact or not.
8838          */
8839         public static final int TYPE_AUTOMATIC = 0;
8840 
8841         /**
8842          * Makes sure that the specified raw contacts are included in the same
8843          * aggregate contact.
8844          */
8845         public static final int TYPE_KEEP_TOGETHER = 1;
8846 
8847         /**
8848          * Makes sure that the specified raw contacts are NOT included in the same
8849          * aggregate contact.
8850          */
8851         public static final int TYPE_KEEP_SEPARATE = 2;
8852 
8853         /**
8854          * A reference to the {@link RawContacts#_ID} of the raw contact that the rule applies to.
8855          */
8856         public static final String RAW_CONTACT_ID1 = "raw_contact_id1";
8857 
8858         /**
8859          * A reference to the other {@link RawContacts#_ID} of the raw contact that the rule
8860          * applies to.
8861          */
8862         public static final String RAW_CONTACT_ID2 = "raw_contact_id2";
8863     }
8864 
8865     /**
8866      * Class containing utility methods around determine what accounts in the ContactsProvider are
8867      * related to the SIM cards in the device.
8868      * <p>
8869      * Apps interested in managing contacts from SIM cards can query the ContactsProvider using
8870      * {@link #getSimAccounts(ContentResolver)} to get all accounts that relate to SIM cards. They
8871      * can also register a receiver for the {@link #ACTION_SIM_ACCOUNTS_CHANGED} broadcast to be
8872      * notified when these accounts change.
8873      */
8874     public static final class SimContacts {
8875         /**
8876          * This utility class cannot be instantiated
8877          */
SimContacts()8878         private SimContacts() {
8879         }
8880 
8881         /**
8882          * The method to invoke in order to add a new SIM account for a newly inserted SIM card.
8883          *
8884          * @hide
8885          */
8886         public static final String ADD_SIM_ACCOUNT_METHOD = "addSimAccount";
8887 
8888         /**
8889          * The method to invoke in order to remove a SIM account once the corresponding SIM card is
8890          * ejected.
8891          *
8892          * @hide
8893          */
8894         public static final String REMOVE_SIM_ACCOUNT_METHOD = "removeSimAccount";
8895 
8896         /**
8897          * The method to invoke in order to query all SIM accounts.
8898          *
8899          * @hide
8900          */
8901         public static final String QUERY_SIM_ACCOUNTS_METHOD = "querySimAccounts";
8902 
8903         /**
8904          * Key to add in the outgoing Bundle for the SIM slot.
8905          *
8906          * @hide
8907          */
8908         public static final String KEY_SIM_SLOT_INDEX = "key_sim_slot_index";
8909 
8910         /**
8911          * Key to add in the outgoing Bundle for the SIM account's EF type.
8912          * See {@link SimAccount#mEfType} for more information.
8913          *
8914          * @hide
8915          */
8916         public static final String KEY_SIM_EF_TYPE = "key_sim_ef_type";
8917 
8918         /**
8919          * Key to add in the outgoing Bundle for the account name.
8920          *
8921          * @hide
8922          */
8923         public static final String KEY_ACCOUNT_NAME = "key_sim_account_name";
8924 
8925         /**
8926          * Key to add in the outgoing Bundle for the account type.
8927          *
8928          * @hide
8929          */
8930         public static final String KEY_ACCOUNT_TYPE = "key_sim_account_type";
8931 
8932         /**
8933          * Key in the incoming Bundle for the all the SIM accounts.
8934          *
8935          * @hide
8936          */
8937         public static final String KEY_SIM_ACCOUNTS = "key_sim_accounts";
8938 
8939         /**
8940          * Broadcast Action: SIM accounts have changed, call
8941          * {@link #getSimAccounts(ContentResolver)} to get the latest.
8942          */
8943         @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
8944         public static final String ACTION_SIM_ACCOUNTS_CHANGED =
8945                 "android.provider.action.SIM_ACCOUNTS_CHANGED";
8946 
8947         /**
8948          * Adds a new SIM account that maps to the corresponding SIM slot.
8949          *
8950          * @param accountName     accountName value for the account
8951          * @param accountType     accountType value for the account
8952          * @param contentResolver to perform the operation on.
8953          * @param simSlotIndex    the SIM slot index of this new account.
8954          * @param efType          the EF type of this new account.
8955          * @hide
8956          */
8957         @SystemApi
8958         @RequiresPermission("android.contacts.permission.MANAGE_SIM_ACCOUNTS")
addSimAccount(@onNull ContentResolver contentResolver, @NonNull String accountName, @NonNull String accountType, int simSlotIndex, int efType)8959         public static void addSimAccount(@NonNull ContentResolver contentResolver,
8960                 @NonNull String accountName,
8961                 @NonNull String accountType,
8962                 int simSlotIndex,
8963                 int efType) {
8964             if (simSlotIndex < 0) {
8965                 throw new IllegalArgumentException("Sim slot is negative");
8966             }
8967             if (!SimAccount.getValidEfTypes().contains(efType)) {
8968                 throw new IllegalArgumentException("Invalid EF type");
8969             }
8970             if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
8971                 throw new IllegalArgumentException("Account name or type is empty");
8972             }
8973 
8974             Bundle extras = new Bundle();
8975             extras.putInt(KEY_SIM_SLOT_INDEX, simSlotIndex);
8976             extras.putInt(KEY_SIM_EF_TYPE, efType);
8977             extras.putString(KEY_ACCOUNT_NAME, accountName);
8978             extras.putString(KEY_ACCOUNT_TYPE, accountType);
8979 
8980             nullSafeCall(contentResolver, ContactsContract.AUTHORITY_URI,
8981                     ContactsContract.SimContacts.ADD_SIM_ACCOUNT_METHOD,
8982                     null, extras);
8983         }
8984 
8985         /**
8986          * Removes all SIM accounts that map to the corresponding SIM slot.
8987          *
8988          * @param contentResolver to perform the operation on.
8989          * @param simSlotIndex    the SIM slot index of the accounts to remove.
8990          * @hide
8991          */
8992         @SystemApi
8993         @RequiresPermission("android.contacts.permission.MANAGE_SIM_ACCOUNTS")
removeSimAccounts(@onNull ContentResolver contentResolver, int simSlotIndex)8994         public static void removeSimAccounts(@NonNull ContentResolver contentResolver,
8995                 int simSlotIndex) {
8996             if (simSlotIndex < 0) {
8997                 throw new IllegalArgumentException("Sim slot is negative");
8998             }
8999 
9000             Bundle extras = new Bundle();
9001             extras.putInt(KEY_SIM_SLOT_INDEX, simSlotIndex);
9002 
9003             nullSafeCall(contentResolver, ContactsContract.AUTHORITY_URI,
9004                     ContactsContract.SimContacts.REMOVE_SIM_ACCOUNT_METHOD,
9005                     null, extras);
9006         }
9007 
9008         /**
9009          * Returns all known SIM accounts. May be empty but never null.
9010          *
9011          * @param contentResolver content resolver to query.
9012          */
getSimAccounts( @onNull ContentResolver contentResolver)9013         public static @NonNull List<SimAccount> getSimAccounts(
9014                 @NonNull ContentResolver contentResolver) {
9015             Bundle response = nullSafeCall(contentResolver, ContactsContract.AUTHORITY_URI,
9016                     ContactsContract.SimContacts.QUERY_SIM_ACCOUNTS_METHOD,
9017                     null, null);
9018             List<SimAccount> result = response.getParcelableArrayList(KEY_SIM_ACCOUNTS, android.provider.ContactsContract.SimAccount.class);
9019 
9020             if (result == null) {
9021                 result = new ArrayList<>();
9022             }
9023 
9024             return result;
9025         }
9026     }
9027 
9028     /**
9029      * A parcelable class encapsulating account data for contacts that originate from a SIM card.
9030      */
9031     public static final class SimAccount implements Parcelable {
9032         /** An invalid EF type identifier. */
9033         public static final int UNKNOWN_EF_TYPE = 0;
9034         /** EF type identifier for the ADN partition. */
9035         public static final int ADN_EF_TYPE = 1;
9036         /** EF type identifier for the FDN partition. */
9037         public static final int FDN_EF_TYPE = 2;
9038         /** EF type identifier for the SDN partition. */
9039         public static final int SDN_EF_TYPE = 3;
9040 
9041         /**
9042          * The account_name of this SIM account. See {@link RawContacts#ACCOUNT_NAME}.
9043          */
9044         private final String mAccountName;
9045 
9046         /**
9047          * The account_type of this SIM account. See {@link RawContacts#ACCOUNT_TYPE}.
9048          */
9049         private final String mAccountType;
9050 
9051         /**
9052          * The slot index of the SIM card this account maps to. See {@link
9053          * android.telephony.SubscriptionInfo#getSimSlotIndex()}.
9054          */
9055         private final int mSimSlotIndex;
9056 
9057         /**
9058          * The EF type of the contacts stored in this account. One of
9059          * {@link #ADN_EF_TYPE}, {@link #SDN_EF_TYPE} or {@link #FDN_EF_TYPE}.
9060          *
9061          * EF type is the Elementary File type of the partition these contacts come from within the
9062          * SIM card.
9063          *
9064          * ADN is the "abbreviated dialing numbers" or the user managed SIM contacts.
9065          *
9066          * SDN is the "service dialing numbers" which are usually preloaded onto the SIM by the
9067          * carrier.
9068          *
9069          * FDN is the "fixed dialing numbers" which are contacts which can only be dialed from that
9070          * SIM, used in cases such as parental control.
9071          */
9072         private final int mEfType;
9073 
9074         /**
9075          * @return A set containing all known EF type values
9076          * @hide
9077          */
getValidEfTypes()9078         public static @NonNull Set<Integer> getValidEfTypes() {
9079             return Sets.newArraySet(ADN_EF_TYPE, SDN_EF_TYPE, FDN_EF_TYPE);
9080         }
9081 
9082         /**
9083          * @hide
9084          */
SimAccount(@onNull String accountName, @NonNull String accountType, int simSlotIndex, int efType)9085         public SimAccount(@NonNull String accountName, @NonNull String accountType,
9086                 int simSlotIndex,
9087                 int efType) {
9088             this.mAccountName = accountName;
9089             this.mAccountType = accountType;
9090             this.mSimSlotIndex = simSlotIndex;
9091             this.mEfType = efType;
9092         }
9093 
9094         /**
9095          * @return The account_name of this SIM account. See {@link RawContacts#ACCOUNT_NAME}.
9096          */
getAccountName()9097         public @NonNull String getAccountName() {
9098             return mAccountName;
9099         }
9100 
9101         /**
9102          * @return The account_type of this SIM account. See {@link RawContacts#ACCOUNT_TYPE}.
9103          */
getAccountType()9104         public @NonNull String getAccountType() {
9105             return mAccountType;
9106         }
9107 
9108         /**
9109          * @return The slot index of the SIM card this account maps to. See
9110          * {@link android.telephony.SubscriptionInfo#getSimSlotIndex()}.
9111          */
getSimSlotIndex()9112         public int getSimSlotIndex() {
9113             return mSimSlotIndex;
9114         }
9115 
9116         /**
9117          * @return The EF type of the contacts stored in this account.
9118          */
getEfType()9119         public int getEfType() {
9120             return mEfType;
9121         }
9122 
9123         @Override
hashCode()9124         public int hashCode() {
9125             return Objects.hash(mAccountName, mAccountType, mSimSlotIndex, mEfType);
9126         }
9127 
9128         @Override
equals(Object obj)9129         public boolean equals(Object obj) {
9130             if (obj == null) return false;
9131             if (obj == this) return true;
9132 
9133             SimAccount toCompare;
9134             try {
9135                 toCompare = (SimAccount) obj;
9136             } catch (ClassCastException ex) {
9137                 return false;
9138             }
9139 
9140             return mSimSlotIndex == toCompare.mSimSlotIndex
9141                     && mEfType == toCompare.mEfType
9142                     && Objects.equals(mAccountName, toCompare.mAccountName)
9143                     && Objects.equals(mAccountType, toCompare.mAccountType);
9144         }
9145 
9146         @Override
writeToParcel(@onNull Parcel dest, int flags)9147         public void writeToParcel(@NonNull Parcel dest, int flags) {
9148             dest.writeString(mAccountName);
9149             dest.writeString(mAccountType);
9150             dest.writeInt(mSimSlotIndex);
9151             dest.writeInt(mEfType);
9152         }
9153 
9154         @Override
describeContents()9155         public int describeContents() {
9156             return 0;
9157         }
9158 
9159         public static final @NonNull Parcelable.Creator<SimAccount> CREATOR =
9160                 new Parcelable.Creator<SimAccount>() {
9161                     @Override
9162                     public SimAccount createFromParcel(Parcel source) {
9163                         String accountName = source.readString();
9164                         String accountType = source.readString();
9165                         int simSlot = source.readInt();
9166                         int efType = source.readInt();
9167                         SimAccount simAccount = new SimAccount(accountName, accountType, simSlot,
9168                                 efType);
9169                         return simAccount;
9170                     }
9171 
9172                     @Override
9173                     public SimAccount[] newArray(int size) {
9174                         return new SimAccount[size];
9175                     }
9176                 };
9177     }
9178 
9179     /**
9180      * @see Settings
9181      */
9182     protected interface SettingsColumns {
9183         /**
9184          * The name of the account instance to which this row belongs.
9185          * <P>Type: TEXT</P>
9186          */
9187         public static final String ACCOUNT_NAME = "account_name";
9188 
9189         /**
9190          * The type of account to which this row belongs, which when paired with
9191          * {@link #ACCOUNT_NAME} identifies a specific account.
9192          * <P>Type: TEXT</P>
9193          */
9194         public static final String ACCOUNT_TYPE = "account_type";
9195 
9196         /**
9197          * The data set within the account that this row belongs to.  This allows
9198          * multiple sync adapters for the same account type to distinguish between
9199          * each others' data.
9200          *
9201          * This is empty by default, and is completely optional.  It only needs to
9202          * be populated if multiple sync adapters are entering distinct data for
9203          * the same account type and account name.
9204          * <P>Type: TEXT</P>
9205          */
9206         public static final String DATA_SET = "data_set";
9207 
9208         /**
9209          * Depending on the mode defined by the sync-adapter, this flag controls
9210          * the top-level sync behavior for this data source.
9211          * <p>
9212          * Type: INTEGER (boolean)
9213          */
9214         public static final String SHOULD_SYNC = "should_sync";
9215 
9216         /**
9217          * Flag indicating if contacts without any {@link CommonDataKinds.GroupMembership}
9218          * entries should be visible in any user interface.
9219          * <p>
9220          * Type: INTEGER (boolean)
9221          */
9222         public static final String UNGROUPED_VISIBLE = "ungrouped_visible";
9223 
9224         /**
9225          * Read-only flag indicating if this {@link #SHOULD_SYNC} or any
9226          * {@link Groups#SHOULD_SYNC} under this account have been marked as
9227          * unsynced.
9228          */
9229         public static final String ANY_UNSYNCED = "any_unsynced";
9230 
9231         /**
9232          * Read-only count of {@link Contacts} from a specific source that have
9233          * no {@link CommonDataKinds.GroupMembership} entries.
9234          * <p>
9235          * Type: INTEGER
9236          */
9237         public static final String UNGROUPED_COUNT = "summ_count";
9238 
9239         /**
9240          * Read-only count of {@link Contacts} from a specific source that have
9241          * no {@link CommonDataKinds.GroupMembership} entries, and also have phone numbers.
9242          * <p>
9243          * Type: INTEGER
9244          */
9245         public static final String UNGROUPED_WITH_PHONES = "summ_phones";
9246 
9247         /**
9248          * Flag indicating if the account is the default account for new contacts. At most one
9249          * account has this flag set at a time. It can only be set to 1 on a row with null data set.
9250          * <p>
9251          * Type: INTEGER (boolean)
9252          * @hide
9253          */
9254         String IS_DEFAULT = "x_is_default";
9255     }
9256 
9257     /**
9258      * <p>
9259      * Contacts-specific settings for various {@link Account}'s.
9260      * </p>
9261      * <p>
9262      * A settings entry for an account is created automatically when a raw contact or group
9263      * is inserted that references it. Settings entries cannot be deleted as long as raw
9264      * contacts or groups continue to reference it; in order to delete a settings entry all
9265      * raw contacts and groups referencing the account must be deleted first.
9266      * </p>
9267      * <h2>Columns</h2>
9268      * <table class="jd-sumtable">
9269      * <tr>
9270      * <th colspan='4'>Settings</th>
9271      * </tr>
9272      * <tr>
9273      * <td>String</td>
9274      * <td>{@link #ACCOUNT_NAME}</td>
9275      * <td>read/write-once</td>
9276      * <td>The name of the account instance to which this row belongs.</td>
9277      * </tr>
9278      * <tr>
9279      * <td>String</td>
9280      * <td>{@link #ACCOUNT_TYPE}</td>
9281      * <td>read/write-once</td>
9282      * <td>The type of account to which this row belongs, which when paired with
9283      * {@link #ACCOUNT_NAME} identifies a specific account.</td>
9284      * </tr>
9285      * <tr>
9286      * <td>int</td>
9287      * <td>{@link #SHOULD_SYNC}</td>
9288      * <td>read/write</td>
9289      * <td>Depending on the mode defined by the sync-adapter, this flag controls
9290      * the top-level sync behavior for this data source.</td>
9291      * </tr>
9292      * <tr>
9293      * <td>int</td>
9294      * <td>{@link #UNGROUPED_VISIBLE}</td>
9295      * <td>read/write</td>
9296      * <td>Flag indicating if contacts without any
9297      * {@link CommonDataKinds.GroupMembership} entries should be visible in any
9298      * user interface.</td>
9299      * </tr>
9300      * <tr>
9301      * <td>int</td>
9302      * <td>{@link #ANY_UNSYNCED}</td>
9303      * <td>read-only</td>
9304      * <td>Read-only flag indicating if this {@link #SHOULD_SYNC} or any
9305      * {@link Groups#SHOULD_SYNC} under this account have been marked as
9306      * unsynced.</td>
9307      * </tr>
9308      * <tr>
9309      * <td>int</td>
9310      * <td>{@link #UNGROUPED_COUNT}</td>
9311      * <td>read-only</td>
9312      * <td>Read-only count of {@link Contacts} from a specific source that have
9313      * no {@link CommonDataKinds.GroupMembership} entries.</td>
9314      * </tr>
9315      * <tr>
9316      * <td>int</td>
9317      * <td>{@link #UNGROUPED_WITH_PHONES}</td>
9318      * <td>read-only</td>
9319      * <td>Read-only count of {@link Contacts} from a specific source that have
9320      * no {@link CommonDataKinds.GroupMembership} entries, and also have phone
9321      * numbers.</td>
9322      * </tr>
9323      * </table>
9324      */
9325     public static final class Settings implements SettingsColumns {
9326         /**
9327          * This utility class cannot be instantiated
9328          */
Settings()9329         private Settings() {
9330         }
9331 
9332         /**
9333          * The content:// style URI for this table
9334          */
9335         public static final Uri CONTENT_URI =
9336                 Uri.withAppendedPath(AUTHORITY_URI, "settings");
9337 
9338         /**
9339          * The MIME-type of {@link #CONTENT_URI} providing a directory of
9340          * settings.
9341          */
9342         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/setting";
9343 
9344         /**
9345          * The MIME-type of {@link #CONTENT_URI} providing a single setting.
9346          */
9347         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/setting";
9348 
9349         /**
9350          * Action used to launch the UI to set the default account for new contacts.
9351          */
9352         @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
9353         public static final String ACTION_SET_DEFAULT_ACCOUNT =
9354                 "android.provider.action.SET_DEFAULT_ACCOUNT";
9355 
9356         /**
9357          * The method to invoke in order to set the default account for new contacts.
9358          *
9359          * @hide
9360          */
9361         public static final String SET_DEFAULT_ACCOUNT_METHOD = "setDefaultAccount";
9362 
9363         /**
9364          * The method to invoke in order to query the default account for new contacts.
9365          *
9366          * @hide
9367          */
9368         public static final String QUERY_DEFAULT_ACCOUNT_METHOD = "queryDefaultAccount";
9369 
9370         /**
9371          * Key in the incoming Bundle for the default account.
9372          *
9373          * @hide
9374          */
9375         public static final String KEY_DEFAULT_ACCOUNT = "key_default_account";
9376 
9377         /**
9378          * Get the account that is set as the default account for new contacts, which should be
9379          * initially selected when creating a new contact on contact management apps.
9380          * If the setting has not been set by any app, it will return null. Once the setting
9381          * is set to non-null Account, it can still be set to null in the future.
9382          *
9383          * @param resolver the ContentResolver to query.
9384          * @return the default account for new contacts, or null if it's not set or set to NULL
9385          * account.
9386          *
9387          * @deprecated This API is only supported up to Android version
9388          *      * {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}. On later versions,
9389          * {@link ContactsContract.RawContacts.DefaultAccount#getDefaultAccountForNewContacts}
9390          * should be used.
9391          */
9392         @Deprecated
9393         @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
9394         @Nullable
getDefaultAccount(@onNull ContentResolver resolver)9395         public static Account getDefaultAccount(@NonNull ContentResolver resolver) {
9396             Bundle response = resolver.call(ContactsContract.AUTHORITY_URI,
9397                     QUERY_DEFAULT_ACCOUNT_METHOD, null, null);
9398             return response.getParcelable(KEY_DEFAULT_ACCOUNT, android.accounts.Account.class);
9399         }
9400 
9401         /**
9402          * Sets the account as the default account that should be initially selected
9403          * when creating a new contact on contact management apps. Apps can only set one of
9404          * the following accounts as the default account:
9405          * <ol>
9406          *   <li>null or custom local account
9407          *   <li>SIM account
9408          *   <li>AccountManager accounts
9409          * </ol>
9410          *
9411          * @param resolver the ContentResolver to query.
9412          * @param account the account to be set to default.
9413          * @hide
9414          *
9415          * @deprecated This API is only supported up to Android version
9416          *      * {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}. On later versions,
9417          * {@link ContactsContract.RawContacts.DefaultAccount#setDefaultAccountForNewContacts}
9418          * should be used.
9419          */
9420         @Deprecated
9421         @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
9422         @SystemApi
9423         @RequiresPermission(android.Manifest.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS)
setDefaultAccount(@onNull ContentResolver resolver, @Nullable Account account)9424         public static void setDefaultAccount(@NonNull ContentResolver resolver,
9425                 @Nullable Account account) {
9426             Bundle extras = new Bundle();
9427             if (account != null) {
9428                 extras.putString(ACCOUNT_NAME, account.name);
9429                 extras.putString(ACCOUNT_TYPE, account.type);
9430             }
9431 
9432             resolver.call(ContactsContract.AUTHORITY_URI, SET_DEFAULT_ACCOUNT_METHOD, null, extras);
9433         }
9434     }
9435 
9436     /**
9437      * API for inquiring about the general status of the provider.
9438      */
9439     public static final class ProviderStatus {
9440 
9441         /**
9442          * Not instantiable.
9443          */
ProviderStatus()9444         private ProviderStatus() {
9445         }
9446 
9447         /**
9448          * The content:// style URI for this table.  Requests to this URI can be
9449          * performed on the UI thread because they are always unblocking.
9450          */
9451         public static final Uri CONTENT_URI =
9452                 Uri.withAppendedPath(AUTHORITY_URI, "provider_status");
9453 
9454         /**
9455          * The MIME-type of {@link #CONTENT_URI} providing a directory of
9456          * settings.
9457          */
9458         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
9459 
9460         /**
9461          * An integer representing the current status of the provider.
9462          */
9463         public static final String STATUS = "status";
9464 
9465         /**
9466          * Default status of the provider.
9467          */
9468         public static final int STATUS_NORMAL = 0;
9469 
9470         /**
9471          * The provider won't respond to queries. It is in the middle of a long running task, such
9472          * as a database upgrade or locale change.
9473          */
9474         public static final int STATUS_BUSY = 1;
9475 
9476         /**
9477          * The status that indicates that there are no accounts and no contacts
9478          * on the device.
9479          */
9480         public static final int STATUS_EMPTY = 2;
9481 
9482         /**
9483          * Timestamp (milliseconds since epoch) of when the provider's database was created.
9484          *
9485          * <P>Type: long
9486          */
9487         public static final String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
9488     }
9489 
9490     /**
9491      * <p>
9492      * API allowing applications to send usage information for each {@link Data} row to the
9493      * Contacts Provider.  Applications can also clear all usage information.
9494      * </p>
9495      * <p class="caution"><b>Caution: </b>If you publish your app to the Google Play Store,
9496      * this field is obsolete, regardless of Android version. For more information, see the
9497      * <a href="/guide/topics/providers/contacts-provider#ObsoleteData">Contacts Provider</a>
9498      * page.</p>
9499      * <p>
9500      * With the feedback, Contacts Provider may return more contextually appropriate results for
9501      * Data listing, typically supplied with
9502      * {@link ContactsContract.Contacts#CONTENT_FILTER_URI},
9503      * {@link ContactsContract.CommonDataKinds.Email#CONTENT_FILTER_URI},
9504      * {@link ContactsContract.CommonDataKinds.Phone#CONTENT_FILTER_URI}, and users can benefit
9505      * from better ranked (sorted) lists in applications that show auto-complete list.
9506      * </p>
9507      * <p>
9508      * There is no guarantee for how this feedback is used, or even whether it is used at all.
9509      * The ranking algorithm will make best efforts to use the feedback data, but the exact
9510      * implementation, the storage data structures as well as the resulting sort order is device
9511      * and version specific and can change over time.
9512      * </p>
9513      * <p>
9514      * When updating usage information, users of this API need to use
9515      * {@link ContentResolver#update(Uri, ContentValues, String, String[])} with a Uri constructed
9516      * from {@link DataUsageFeedback#FEEDBACK_URI}. The Uri must contain one or more data id(s) as
9517      * its last path. They also need to append a query parameter to the Uri, to specify the type of
9518      * the communication, which enables the Contacts Provider to differentiate between kinds of
9519      * interactions using the same contact data field (for example a phone number can be used to
9520      * make phone calls or send SMS).
9521      * </p>
9522      * <p>
9523      * Selection and selectionArgs are ignored and must be set to null. To get data ids,
9524      * you may need to call {@link ContentResolver#query(Uri, String[], String, String[], String)}
9525      * toward {@link Data#CONTENT_URI}.
9526      * </p>
9527      * <p>
9528      * {@link ContentResolver#update(Uri, ContentValues, String, String[])} returns a positive
9529      * integer when successful, and returns 0 if no contact with that id was found.
9530      * </p>
9531      * <p>
9532      * Example:
9533      * <pre>
9534      * Uri uri = DataUsageFeedback.FEEDBACK_URI.buildUpon()
9535      *         .appendPath(TextUtils.join(",", dataIds))
9536      *         .appendQueryParameter(DataUsageFeedback.USAGE_TYPE,
9537      *                 DataUsageFeedback.USAGE_TYPE_CALL)
9538      *         .build();
9539      * boolean successful = resolver.update(uri, new ContentValues(), null, null) > 0;
9540      * </pre>
9541      * </p>
9542      * <p>
9543      * Applications can also clear all usage information with:
9544      * <pre>
9545      * boolean successful = resolver.delete(DataUsageFeedback.DELETE_USAGE_URI, null, null) > 0;
9546      * </pre>
9547      * </p>
9548      *
9549      * @deprecated Contacts affinity information is no longer supported as of
9550      * Android version {@link android.os.Build.VERSION_CODES#Q}.
9551      * Both update and delete calls are always ignored.
9552      */
9553     @Deprecated
9554     public static final class DataUsageFeedback {
9555 
9556         /**
9557          * The content:// style URI for sending usage feedback.
9558          * Must be used with {@link ContentResolver#update(Uri, ContentValues, String, String[])}.
9559          */
9560         public static final Uri FEEDBACK_URI =
9561                 Uri.withAppendedPath(Data.CONTENT_URI, "usagefeedback");
9562 
9563         /**
9564          * The content:// style URI for deleting all usage information.
9565          * Must be used with {@link ContentResolver#delete(Uri, String, String[])}.
9566          * The {@code where} and {@code selectionArgs} parameters are ignored.
9567          */
9568         public static final Uri DELETE_USAGE_URI =
9569                 Uri.withAppendedPath(Contacts.CONTENT_URI, "delete_usage");
9570 
9571         /**
9572          * <p>
9573          * Name for query parameter specifying the type of data usage.
9574          * </p>
9575          */
9576         public static final String USAGE_TYPE = "type";
9577 
9578         /**
9579          * <p>
9580          * Type of usage for voice interaction, which includes phone call, voice chat, and
9581          * video chat.
9582          * </p>
9583          */
9584         public static final String USAGE_TYPE_CALL = "call";
9585 
9586         /**
9587          * <p>
9588          * Type of usage for text interaction involving longer messages, which includes email.
9589          * </p>
9590          */
9591         public static final String USAGE_TYPE_LONG_TEXT = "long_text";
9592 
9593         /**
9594          * <p>
9595          * Type of usage for text interaction involving shorter messages, which includes SMS,
9596          * text chat with email addresses.
9597          * </p>
9598          */
9599         public static final String USAGE_TYPE_SHORT_TEXT = "short_text";
9600     }
9601 
9602     /**
9603      * <p>
9604      * Contact-specific information about whether or not a contact has been pinned by the user
9605      * at a particular position within the system contact application's user interface.
9606      * </p>
9607      *
9608      * <p>
9609      * This pinning information can be used by individual applications to customize how
9610      * they order particular pinned contacts. For example, a Dialer application could
9611      * use pinned information to order user-pinned contacts in a top row of favorites.
9612      * </p>
9613      *
9614      * <p>
9615      * It is possible for two or more contacts to occupy the same pinned position (due
9616      * to aggregation and sync), so this pinning information should be used on a best-effort
9617      * basis to order contacts in-application rather than an absolute guide on where a contact
9618      * should be positioned. Contacts returned by the ContactsProvider will not be ordered based
9619      * on this information, so it is up to the client application to reorder these contacts within
9620      * their own UI adhering to (or ignoring as appropriate) information stored in the pinned
9621      * column.
9622      * </p>
9623      *
9624      * <p>
9625      * By default, unpinned contacts will have a pinned position of
9626      * {@link PinnedPositions#UNPINNED}. Client-provided pinned positions can be positive
9627      * integers that are greater than 1.
9628      * </p>
9629      */
9630     public static final class PinnedPositions {
9631         /**
9632          * The method to invoke in order to undemote a formerly demoted contact. The contact id of
9633          * the contact must be provided as an argument. If the contact was not previously demoted,
9634          * nothing will be done.
9635          * @hide
9636          */
9637         @TestApi
9638         public static final String UNDEMOTE_METHOD = "undemote";
9639 
9640         /**
9641          * Undemotes a formerly demoted contact. If the contact was not previously demoted, nothing
9642          * will be done.
9643          *
9644          * @param contentResolver to perform the undemote operation on.
9645          * @param contactId the id of the contact to undemote.
9646          */
undemote(ContentResolver contentResolver, long contactId)9647         public static void undemote(ContentResolver contentResolver, long contactId) {
9648             nullSafeCall(contentResolver, ContactsContract.AUTHORITY_URI,
9649                     PinnedPositions.UNDEMOTE_METHOD,
9650                     String.valueOf(contactId), null);
9651         }
9652 
9653         /**
9654          * Pins a contact at a provided position, or unpins a contact.
9655          *
9656          * @param contentResolver to perform the pinning operation on.
9657          * @param pinnedPosition the position to pin the contact at. To unpin a contact, use
9658          *         {@link PinnedPositions#UNPINNED}.
9659          */
pin( ContentResolver contentResolver, long contactId, int pinnedPosition)9660         public static void pin(
9661                 ContentResolver contentResolver, long contactId, int pinnedPosition) {
9662             final Uri uri = Uri.withAppendedPath(Contacts.CONTENT_URI, String.valueOf(contactId));
9663             final ContentValues values = new ContentValues();
9664             values.put(Contacts.PINNED, pinnedPosition);
9665             contentResolver.update(uri, values, null, null);
9666         }
9667 
9668         /**
9669          * Default value for the pinned position of an unpinned contact.
9670          */
9671         public static final int UNPINNED = 0;
9672 
9673         /**
9674          * Value of pinned position for a contact that a user has indicated should be considered
9675          * of the lowest priority. It is up to the client application to determine how to present
9676          * such a contact - for example all the way at the bottom of a contact list, or simply
9677          * just hidden from view.
9678          */
9679         public static final int DEMOTED = -1;
9680     }
9681 
9682     /**
9683      * Helper methods to display QuickContact dialogs that display all the information belonging to
9684      * a specific {@link Contacts} entry.
9685      */
9686     public static final class QuickContact {
9687         /**
9688          * Action used to launch the system contacts application and bring up a QuickContact dialog
9689          * for the provided {@link Contacts} entry.
9690          */
9691         @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
9692         public static final String ACTION_QUICK_CONTACT =
9693                 "android.provider.action.QUICK_CONTACT";
9694 
9695         /**
9696          * Extra used to specify pivot dialog location in screen coordinates.
9697          * @deprecated Use {@link Intent#setSourceBounds(Rect)} instead.
9698          * @hide
9699          */
9700         @Deprecated
9701         public static final String EXTRA_TARGET_RECT = "android.provider.extra.TARGET_RECT";
9702 
9703         /**
9704          * Extra used to specify size of QuickContacts. Not all implementations of QuickContacts
9705          * will respect this extra's value.
9706          *
9707          * One of {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or {@link #MODE_LARGE}.
9708          */
9709         public static final String EXTRA_MODE = "android.provider.extra.MODE";
9710 
9711         /**
9712          * Extra used to specify which mimetype should be prioritized in the QuickContacts UI.
9713          * For example, passing the value {@link CommonDataKinds.Phone#CONTENT_ITEM_TYPE} can
9714          * cause phone numbers to be displayed more prominently in QuickContacts.
9715          */
9716         public static final String EXTRA_PRIORITIZED_MIMETYPE
9717                 = "android.provider.extra.PRIORITIZED_MIMETYPE";
9718 
9719         /**
9720          * Extra used to indicate a list of specific MIME-types to exclude and not display in the
9721          * QuickContacts dialog. Stored as a {@link String} array.
9722          */
9723         public static final String EXTRA_EXCLUDE_MIMES = "android.provider.extra.EXCLUDE_MIMES";
9724 
9725         /**
9726          * Small QuickContact mode, usually presented with minimal actions.
9727          */
9728         public static final int MODE_SMALL = 1;
9729 
9730         /**
9731          * Medium QuickContact mode, includes actions and light summary describing
9732          * the {@link Contacts} entry being shown. This may include social
9733          * status and presence details.
9734          */
9735         public static final int MODE_MEDIUM = 2;
9736 
9737         /**
9738          * Large QuickContact mode, includes actions and larger, card-like summary
9739          * of the {@link Contacts} entry being shown. This may include detailed
9740          * information, such as a photo.
9741          */
9742         public static final int MODE_LARGE = 3;
9743 
9744         /** @hide */
9745         public static final int MODE_DEFAULT = MODE_LARGE;
9746 
9747         /**
9748          * Constructs the QuickContacts intent with a view's rect.
9749          * @hide
9750          */
composeQuickContactsIntent(Context context, View target, Uri lookupUri, int mode, String[] excludeMimes)9751         public static Intent composeQuickContactsIntent(Context context, View target, Uri lookupUri,
9752                 int mode, String[] excludeMimes) {
9753             // Find location and bounds of target view, adjusting based on the
9754             // assumed local density.
9755             final float appScale = context.getResources().getCompatibilityInfo().applicationScale;
9756             final int[] pos = new int[2];
9757             target.getLocationOnScreen(pos);
9758 
9759             final Rect rect = new Rect();
9760             rect.left = (int) (pos[0] * appScale + 0.5f);
9761             rect.top = (int) (pos[1] * appScale + 0.5f);
9762             rect.right = (int) ((pos[0] + target.getWidth()) * appScale + 0.5f);
9763             rect.bottom = (int) ((pos[1] + target.getHeight()) * appScale + 0.5f);
9764 
9765             return composeQuickContactsIntent(context, rect, lookupUri, mode, excludeMimes);
9766         }
9767 
9768         /**
9769          * Constructs the QuickContacts intent.
9770          * @hide
9771          */
9772         @UnsupportedAppUsage
composeQuickContactsIntent(Context context, Rect target, Uri lookupUri, int mode, String[] excludeMimes)9773         public static Intent composeQuickContactsIntent(Context context, Rect target,
9774                 Uri lookupUri, int mode, String[] excludeMimes) {
9775             // When launching from an Activiy, we don't want to start a new task, but otherwise
9776             // we *must* start a new task.  (Otherwise startActivity() would crash.)
9777             Context actualContext = context;
9778             while ((actualContext instanceof ContextWrapper)
9779                     && !(actualContext instanceof Activity)) {
9780                 actualContext = ((ContextWrapper) actualContext).getBaseContext();
9781             }
9782             final int intentFlags = ((actualContext instanceof Activity)
9783                     ? 0 : Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
9784                     // Workaround for b/16898764. Declaring singleTop in manifest doesn't work.
9785                     | Intent.FLAG_ACTIVITY_SINGLE_TOP;
9786 
9787             // Launch pivot dialog through intent for now
9788             final Intent intent = new Intent(ACTION_QUICK_CONTACT).addFlags(intentFlags);
9789 
9790             // NOTE: This logic and rebuildManagedQuickContactsIntent() must be in sync.
9791             intent.setData(lookupUri);
9792             intent.setSourceBounds(target);
9793             intent.putExtra(EXTRA_MODE, mode);
9794             intent.putExtra(EXTRA_EXCLUDE_MIMES, excludeMimes);
9795             return intent;
9796         }
9797 
9798         /**
9799          * Constructs a QuickContacts intent based on an incoming intent for DevicePolicyManager
9800          * to strip off anything not necessary.
9801          *
9802          * @hide
9803          */
rebuildManagedQuickContactsIntent(String lookupKey, long contactId, boolean isContactIdIgnored, long directoryId, Intent originalIntent)9804         public static Intent rebuildManagedQuickContactsIntent(String lookupKey, long contactId,
9805                 boolean isContactIdIgnored, long directoryId, Intent originalIntent) {
9806             final Intent intent = new Intent(ACTION_QUICK_CONTACT);
9807             // Rebuild the URI from a lookup key and a contact ID.
9808             Uri uri = null;
9809             if (!TextUtils.isEmpty(lookupKey)) {
9810                 uri = isContactIdIgnored
9811                         ? Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey)
9812                         : Contacts.getLookupUri(contactId, lookupKey);
9813             }
9814             if (uri != null && directoryId != Directory.DEFAULT) {
9815                 uri = uri.buildUpon().appendQueryParameter(
9816                         ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build();
9817             }
9818             intent.setData(uri);
9819 
9820             // Copy flags and always set NEW_TASK because it won't have a parent activity.
9821             intent.setFlags(originalIntent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
9822 
9823             // Copy extras.
9824             intent.setSourceBounds(originalIntent.getSourceBounds());
9825             intent.putExtra(EXTRA_MODE, originalIntent.getIntExtra(EXTRA_MODE, MODE_DEFAULT));
9826             intent.putExtra(EXTRA_EXCLUDE_MIMES,
9827                     originalIntent.getStringArrayExtra(EXTRA_EXCLUDE_MIMES));
9828             return intent;
9829         }
9830 
9831 
9832         /**
9833          * Trigger a dialog that lists the various methods of interacting with
9834          * the requested {@link Contacts} entry. This may be based on available
9835          * {@link ContactsContract.Data} rows under that contact, and may also
9836          * include social status and presence details.
9837          *
9838          * @param context The parent {@link Context} that may be used as the
9839          *            parent for this dialog.
9840          * @param target Specific {@link View} from your layout that this dialog
9841          *            should be centered around. In particular, if the dialog
9842          *            has a "callout" arrow, it will be pointed and centered
9843          *            around this {@link View}.
9844          * @param lookupUri A {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
9845          *            {@link Uri} that describes a specific contact to feature
9846          *            in this dialog. A managed profile lookup uri is supported here,
9847          *            see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
9848          *            {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
9849          * @param mode Any of {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or
9850          *            {@link #MODE_LARGE}, indicating the desired dialog size,
9851          *            when supported.
9852          * @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
9853          *            to exclude when showing this dialog. For example, when
9854          *            already viewing the contact details card, this can be used
9855          *            to omit the details entry from the dialog.
9856          */
showQuickContact(Context context, View target, Uri lookupUri, int mode, String[] excludeMimes)9857         public static void showQuickContact(Context context, View target, Uri lookupUri, int mode,
9858                 String[] excludeMimes) {
9859             // Trigger with obtained rectangle
9860             Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode,
9861                     excludeMimes);
9862             ContactsInternal.startQuickContactWithErrorToast(context, intent);
9863         }
9864 
9865         /**
9866          * Trigger a dialog that lists the various methods of interacting with
9867          * the requested {@link Contacts} entry. This may be based on available
9868          * {@link ContactsContract.Data} rows under that contact, and may also
9869          * include social status and presence details.
9870          *
9871          * @param context The parent {@link Context} that may be used as the
9872          *            parent for this dialog.
9873          * @param target Specific {@link Rect} that this dialog should be
9874          *            centered around, in screen coordinates. In particular, if
9875          *            the dialog has a "callout" arrow, it will be pointed and
9876          *            centered around this {@link Rect}. If you are running at a
9877          *            non-native density, you need to manually adjust using
9878          *            {@link DisplayMetrics#density} before calling.
9879          * @param lookupUri A
9880          *            {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
9881          *            {@link Uri} that describes a specific contact to feature
9882          *            in this dialog. A managed profile lookup uri is supported here,
9883          *            see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
9884          *            {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
9885          * @param mode Any of {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or
9886          *            {@link #MODE_LARGE}, indicating the desired dialog size,
9887          *            when supported.
9888          * @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
9889          *            to exclude when showing this dialog. For example, when
9890          *            already viewing the contact details card, this can be used
9891          *            to omit the details entry from the dialog.
9892          */
showQuickContact(Context context, Rect target, Uri lookupUri, int mode, String[] excludeMimes)9893         public static void showQuickContact(Context context, Rect target, Uri lookupUri, int mode,
9894                 String[] excludeMimes) {
9895             Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode,
9896                     excludeMimes);
9897             ContactsInternal.startQuickContactWithErrorToast(context, intent);
9898         }
9899 
9900         /**
9901          * Trigger a dialog that lists the various methods of interacting with
9902          * the requested {@link Contacts} entry. This may be based on available
9903          * {@link ContactsContract.Data} rows under that contact, and may also
9904          * include social status and presence details.
9905          *
9906          * @param context The parent {@link Context} that may be used as the
9907          *            parent for this dialog.
9908          * @param target Specific {@link View} from your layout that this dialog
9909          *            should be centered around. In particular, if the dialog
9910          *            has a "callout" arrow, it will be pointed and centered
9911          *            around this {@link View}.
9912          * @param lookupUri A
9913          *            {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
9914          *            {@link Uri} that describes a specific contact to feature
9915          *            in this dialog. A managed profile lookup uri is supported here,
9916          *            see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
9917          *            {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
9918          * @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
9919          *            to exclude when showing this dialog. For example, when
9920          *            already viewing the contact details card, this can be used
9921          *            to omit the details entry from the dialog.
9922          * @param prioritizedMimeType This mimetype should be prioritized in the QuickContacts UI.
9923          *             For example, passing the value
9924          *             {@link CommonDataKinds.Phone#CONTENT_ITEM_TYPE} can cause phone numbers to be
9925          *             displayed more prominently in QuickContacts.
9926          */
showQuickContact(Context context, View target, Uri lookupUri, String[] excludeMimes, String prioritizedMimeType)9927         public static void showQuickContact(Context context, View target, Uri lookupUri,
9928                 String[] excludeMimes, String prioritizedMimeType) {
9929             // Use MODE_LARGE instead of accepting mode as a parameter. The different mode
9930             // values defined in ContactsContract only affect very old implementations
9931             // of QuickContacts.
9932             Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_DEFAULT,
9933                     excludeMimes);
9934             intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType);
9935             ContactsInternal.startQuickContactWithErrorToast(context, intent);
9936         }
9937 
9938         /**
9939          * Trigger a dialog that lists the various methods of interacting with
9940          * the requested {@link Contacts} entry. This may be based on available
9941          * {@link ContactsContract.Data} rows under that contact, and may also
9942          * include social status and presence details.
9943          *
9944          * @param context The parent {@link Context} that may be used as the
9945          *            parent for this dialog.
9946          * @param target Specific {@link Rect} that this dialog should be
9947          *            centered around, in screen coordinates. In particular, if
9948          *            the dialog has a "callout" arrow, it will be pointed and
9949          *            centered around this {@link Rect}. If you are running at a
9950          *            non-native density, you need to manually adjust using
9951          *            {@link DisplayMetrics#density} before calling.
9952          * @param lookupUri A
9953          *            {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
9954          *            {@link Uri} that describes a specific contact to feature
9955          *            in this dialog. A managed profile lookup uri is supported here,
9956          *            see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
9957          *            {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
9958          * @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
9959          *            to exclude when showing this dialog. For example, when
9960          *            already viewing the contact details card, this can be used
9961          *            to omit the details entry from the dialog.
9962          * @param prioritizedMimeType This mimetype should be prioritized in the QuickContacts UI.
9963          *             For example, passing the value
9964          *             {@link CommonDataKinds.Phone#CONTENT_ITEM_TYPE} can cause phone numbers to be
9965          *             displayed more prominently in QuickContacts.
9966          */
showQuickContact(Context context, Rect target, Uri lookupUri, String[] excludeMimes, String prioritizedMimeType)9967         public static void showQuickContact(Context context, Rect target, Uri lookupUri,
9968                 String[] excludeMimes, String prioritizedMimeType) {
9969             // Use MODE_LARGE instead of accepting mode as a parameter. The different mode
9970             // values defined in ContactsContract only affect very old implementations
9971             // of QuickContacts.
9972             Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_DEFAULT,
9973                     excludeMimes);
9974             intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType);
9975             ContactsInternal.startQuickContactWithErrorToast(context, intent);
9976         }
9977     }
9978 
9979     /**
9980      * Helper class for accessing full-size photos by photo file ID.
9981      * <p>
9982      * Usage example:
9983      * <dl>
9984      * <dt>Retrieving a full-size photo by photo file ID (see
9985      * {@link ContactsContract.ContactsColumns#PHOTO_FILE_ID})
9986      * </dt>
9987      * <dd>
9988      * <pre>
9989      * public InputStream openDisplayPhoto(long photoFileId) {
9990      *     Uri displayPhotoUri = ContentUris.withAppendedId(DisplayPhoto.CONTENT_URI, photoKey);
9991      *     try {
9992      *         AssetFileDescriptor fd = getContentResolver().openAssetFileDescriptor(
9993      *             displayPhotoUri, "r");
9994      *         return fd.createInputStream();
9995      *     } catch (IOException e) {
9996      *         return null;
9997      *     }
9998      * }
9999      * </pre>
10000      * </dd>
10001      * </dl>
10002      * </p>
10003      */
10004     public static final class DisplayPhoto {
10005         /**
10006          * no public constructor since this is a utility class
10007          */
DisplayPhoto()10008         private DisplayPhoto() {}
10009 
10010         /**
10011          * The content:// style URI for this class, which allows access to full-size photos,
10012          * given a key.
10013          */
10014         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "display_photo");
10015 
10016         /**
10017          * This URI allows the caller to query for the maximum dimensions of a display photo
10018          * or thumbnail.  Requests to this URI can be performed on the UI thread because
10019          * they are always unblocking.
10020          */
10021         public static final Uri CONTENT_MAX_DIMENSIONS_URI =
10022                 Uri.withAppendedPath(AUTHORITY_URI, "photo_dimensions");
10023 
10024         /**
10025          * Queries to {@link ContactsContract.DisplayPhoto#CONTENT_MAX_DIMENSIONS_URI} will
10026          * contain this column, populated with the maximum height and width (in pixels)
10027          * that will be stored for a display photo.  Larger photos will be down-sized to
10028          * fit within a square of this many pixels.
10029          */
10030         public static final String DISPLAY_MAX_DIM = "display_max_dim";
10031 
10032         /**
10033          * Queries to {@link ContactsContract.DisplayPhoto#CONTENT_MAX_DIMENSIONS_URI} will
10034          * contain this column, populated with the height and width (in pixels) for photo
10035          * thumbnails.
10036          */
10037         public static final String THUMBNAIL_MAX_DIM = "thumbnail_max_dim";
10038     }
10039 
10040     /**
10041      * Contains helper classes used to create or manage {@link android.content.Intent Intents}
10042      * that involve contacts.
10043      */
10044     public static final class Intents {
10045         /**
10046          * This is the intent that is fired when a search suggestion is clicked on.
10047          */
10048         public static final String SEARCH_SUGGESTION_CLICKED =
10049                 "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
10050 
10051         /**
10052          * This is the intent that is fired when a search suggestion for dialing a number
10053          * is clicked on.
10054          */
10055         public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED =
10056                 "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";
10057 
10058         /**
10059          * This is the intent that is fired when a search suggestion for creating a contact
10060          * is clicked on.
10061          */
10062         public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED =
10063                 "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
10064 
10065         /**
10066          * This is the intent that is fired when the contacts database is created. <p> The
10067          * READ_CONTACT permission is required to receive these broadcasts.
10068          *
10069          * <p>Because this is an implicit broadcast, apps targeting Android O will no longer
10070          * receive this broadcast via a manifest broadcast receiver.  (Broadcast receivers
10071          * registered at runtime with
10072          * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)} will still receive it.)
10073          * Instead, an app can use {@link ProviderStatus#DATABASE_CREATION_TIMESTAMP} to see if the
10074          * contacts database has been initialized when it starts.
10075          */
10076         public static final String CONTACTS_DATABASE_CREATED =
10077                 "android.provider.Contacts.DATABASE_CREATED";
10078 
10079         /**
10080          * Starts an Activity that lets the user pick a contact to attach an image to.
10081          * After picking the contact it launches the image cropper in face detection mode.
10082          */
10083         public static final String ATTACH_IMAGE =
10084                 "com.android.contacts.action.ATTACH_IMAGE";
10085 
10086         /**
10087          * This is the intent that is fired when the user clicks the "invite to the network" button
10088          * on a contact.  Only sent to an activity which is explicitly registered by a contact
10089          * provider which supports the "invite to the network" feature.
10090          * <p>
10091          * {@link Intent#getData()} contains the lookup URI for the contact.
10092          */
10093         public static final String INVITE_CONTACT =
10094                 "com.android.contacts.action.INVITE_CONTACT";
10095 
10096         /**
10097          * Takes as input a data URI with a mailto: or tel: scheme. If a single
10098          * contact exists with the given data it will be shown. If no contact
10099          * exists, a dialog will ask the user if they want to create a new
10100          * contact with the provided details filled in. If multiple contacts
10101          * share the data the user will be prompted to pick which contact they
10102          * want to view.
10103          * <p>
10104          * For <code>mailto:</code> URIs, the scheme specific portion must be a
10105          * raw email address, such as one built using
10106          * {@link Uri#fromParts(String, String, String)}.
10107          * <p>
10108          * For <code>tel:</code> URIs, the scheme specific portion is compared
10109          * to existing numbers using the standard caller ID lookup algorithm.
10110          * The number must be properly encoded, for example using
10111          * {@link Uri#fromParts(String, String, String)}.
10112          * <p>
10113          * Any extras from the {@link Insert} class will be passed along to the
10114          * create activity if there are no contacts to show.
10115          * <p>
10116          * Passing true for the {@link #EXTRA_FORCE_CREATE} extra will skip
10117          * prompting the user when the contact doesn't exist.
10118          */
10119         public static final String SHOW_OR_CREATE_CONTACT =
10120                 "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
10121 
10122         /**
10123          * Activity Action: Initiate a message to someone by voice. The message could be text,
10124          * audio, video or image(photo). This action supports messaging with a specific contact
10125          * regardless of the underlying messaging protocol used.
10126          * <p>
10127          * The action could be originated from the Voice Assistant as a voice interaction. In such
10128          * case, a receiving activity that supports {@link android.content.Intent#CATEGORY_VOICE}
10129          * could check return value of {@link android.app.Activity#isVoiceInteractionRoot} before
10130          * proceeding. By doing this check the activity verifies that the action indeed was
10131          * initiated by Voice Assistant and could send a message right away, without any further
10132          * input from the user. This allows for a smooth user experience when sending a message by
10133          * voice. Note: this activity must also support the {@link
10134          * android.content.Intent#CATEGORY_DEFAULT} so it can be found by {@link
10135          * android.service.voice.VoiceInteractionSession#startVoiceActivity}.
10136          * <p>
10137          * When the action was not initiated by Voice Assistant or when the receiving activity does
10138          * not support {@link android.content.Intent#CATEGORY_VOICE}, the activity must confirm
10139          * with the user before sending the message (because in this case it is unknown which app
10140          * sent the intent, it could be malicious).
10141          * <p>
10142          * To allow the Voice Assistant to help users with contacts disambiguation, the messaging
10143          * app may choose to integrate with the Contacts Provider. You will need to specify a new
10144          * MIME type in order to store your app’s unique contact IDs and optional human readable
10145          * labels in the Data table. The Voice Assistant needs to know this MIME type and {@link
10146          * RawContacts#ACCOUNT_TYPE} that you are using in order to provide the smooth contact
10147          * disambiguation user experience. The following convention should be met when performing
10148          * such integration:
10149          * <ul>
10150          * <li>This activity should have a string meta-data field associated with it, {@link
10151          * #METADATA_ACCOUNT_TYPE}, which defines {@link RawContacts#ACCOUNT_TYPE} for your Contacts
10152          * Provider implementation. The account type should be globally unique, for example you can
10153          * use your app package name as the account type.</li>
10154          * <li>This activity should have a string meta-data field associated with it, {@link
10155          * #METADATA_MIMETYPE}, which defines {@link DataColumns#MIMETYPE} for your Contacts
10156          * Provider implementation. For example, you can use
10157          * "vnd.android.cursor.item/vnd.{$app_package_name}.profile" as MIME type.</li>
10158          * <li>When filling Data table row for METADATA_MIMETYPE, column {@link DataColumns#DATA1}
10159          * should store the unique contact ID as understood by the app. This value will be used in
10160          * the {@link #EXTRA_RECIPIENT_CONTACT_CHAT_ID}.</li>
10161          * <li>Optionally, when filling Data table row for METADATA_MIMETYPE, column {@link
10162          * DataColumns#DATA3} could store a human readable label for the ID. For example it could be
10163          * phone number or human readable username/user_id like "a_super_cool_user_name". This label
10164          * may be shown below the Contact Name by the Voice Assistant as the user completes the
10165          * voice action. If DATA3 is empty, the ID in DATA1 may be shown instead.</li>
10166          * <li><em>Note: Do not use DATA3 to store the Contact Name. The Voice Assistant will
10167          * already get the Contact Name from the RawContact’s display_name.</em></li>
10168          * <li><em>Note: Some apps may choose to use phone number as the unique contact ID in DATA1.
10169          * If this applies to you and you’d like phone number to be shown below the Contact Name by
10170          * the Voice Assistant, then you may choose to leave DATA3 empty.</em></li>
10171          * <li><em>Note: If your app also uses DATA3 to display contact details in the Contacts App,
10172          * make sure it does not include prefix text such as "Message +<phone>" or "Free Message
10173          * +<phone>", etc. If you must show the prefix text in the Contacts App, please use a
10174          * different DATA# column, and update your contacts.xml to point to this new column. </em>
10175          * </li>
10176          * </ul>
10177          * If the app chooses not to integrate with the Contacts Provider (in particular, when
10178          * either METADATA_ACCOUNT_TYPE or METADATA_MIMETYPE field is missing), Voice Assistant
10179          * will use existing phone number entries as contact ID's for such app.
10180          * <p>
10181          * Input: {@link android.content.Intent#getType} is the MIME type of the data being sent.
10182          * The intent sender will always put the concrete mime type in the intent type, like
10183          * "text/plain" or "audio/wav" for example. If the MIME type is "text/plain", message to
10184          * sent will be provided via {@link android.content.Intent#EXTRA_TEXT} as a styled
10185          * CharSequence. Otherwise, the message content will be supplied through {@link
10186          * android.content.Intent#setClipData(ClipData)} as a content provider URI(s). In the latter
10187          * case, EXTRA_TEXT could still be supplied optionally; for example, for audio messages
10188          * ClipData will contain URI of a recording and EXTRA_TEXT could contain the text
10189          * transcription of this recording.
10190          * <p>
10191          * The message can have n recipients. The n-th recipient of the message will be provided as
10192          * n-th elements of {@link #EXTRA_RECIPIENT_CONTACT_URI}, {@link
10193          * #EXTRA_RECIPIENT_CONTACT_CHAT_ID} and {@link #EXTRA_RECIPIENT_CONTACT_NAME} (as a
10194          * consequence, EXTRA_RECIPIENT_CONTACT_URI, EXTRA_RECIPIENT_CONTACT_CHAT_ID and
10195          * EXTRA_RECIPIENT_CONTACT_NAME should all be of length n). If neither of these 3 elements
10196          * is provided (e.g. all 3 are null) for the recipient or if the information provided is
10197          * ambiguous then the activity should prompt the user for the recipient to send the message
10198          * to.
10199          * <p>
10200          * Output: nothing
10201          *
10202          * @see #EXTRA_RECIPIENT_CONTACT_URI
10203          * @see #EXTRA_RECIPIENT_CONTACT_CHAT_ID
10204          * @see #EXTRA_RECIPIENT_CONTACT_NAME
10205          * @see #METADATA_ACCOUNT_TYPE
10206          * @see #METADATA_MIMETYPE
10207          */
10208         @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
10209         public static final String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS =
10210                 "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
10211 
10212         /**
10213          * This extra specifies a content provider uri(s) for the contact(s) (if the contacts were
10214          * located in the Contacts Provider), used with {@link
10215          * #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS} to supply the recipient(s). The value of this
10216          * extra is a {@code String[]}. The number of elements in the array should be equal to
10217          * number of recipients (and consistent with {@link #EXTRA_RECIPIENT_CONTACT_CHAT_ID} and
10218          * {@link #EXTRA_RECIPIENT_CONTACT_NAME}). When the value of the element for the particular
10219          * recipient is absent, it will be set to null.
10220          * <p>
10221          * <em>Note: one contact may have multiple accounts (e.g. Chat IDs) on a specific messaging
10222          * platform, so this may be ambiguous. E.g., one contact “John Smith” could have two
10223          * accounts on the same messaging app.</em>
10224          * <p>
10225          * <em>Example value: {"content://com.android.contacts/contacts/16"}</em>
10226          */
10227         public static final String EXTRA_RECIPIENT_CONTACT_URI =
10228                 "android.provider.extra.RECIPIENT_CONTACT_URI";
10229 
10230         /**
10231          * This extra specifies a messaging app’s unique ID(s) for the contact(s), used with {@link
10232          * #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS} to supply the recipient(s). The value of this
10233          * extra is a {@code String[]}. The number of elements in the array should be equal to
10234          * number of recipients (and consistent with {@link #EXTRA_RECIPIENT_CONTACT_URI} and {@link
10235          * #EXTRA_RECIPIENT_CONTACT_NAME}). When the value of the element for the particular
10236          * recipient is absent, it will be set to null.
10237          * <p>
10238          * The value of the elements comes from the {@link DataColumns#DATA1} column in Contacts
10239          * Provider with {@link DataColumns#MIMETYPE} from {@link #METADATA_MIMETYPE} (if both
10240          * {@link #METADATA_ACCOUNT_TYPE} and {@link #METADATA_MIMETYPE} are specified by the app;
10241          * otherwise, the value will be a phone number), and should be the unambiguous contact
10242          * endpoint. This value is app-specific, it could be some proprietary ID or a phone number.
10243          */
10244         public static final String EXTRA_RECIPIENT_CONTACT_CHAT_ID =
10245                 "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
10246 
10247         /**
10248          * This extra specifies the contact name (full name from the Contacts Provider), used with
10249          * {@link #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS} to supply the recipient. The value of this
10250          * extra is a {@code String[]}. The number of elements in the array should be equal to
10251          * number of recipients (and consistent with {@link #EXTRA_RECIPIENT_CONTACT_URI} and {@link
10252          * #EXTRA_RECIPIENT_CONTACT_CHAT_ID}). When the value of the element for the particular
10253          * recipient is absent, it will be set to null.
10254          * <p>
10255          * The value of the elements comes from RawContact's display_name column.
10256          * <p>
10257          * <em>Example value: {"Jane Doe"}</em>
10258          */
10259         public static final String EXTRA_RECIPIENT_CONTACT_NAME =
10260                 "android.provider.extra.RECIPIENT_CONTACT_NAME";
10261 
10262         /**
10263          * A string associated with an {@link #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS} activity
10264          * describing {@link RawContacts#ACCOUNT_TYPE} for the corresponding Contacts Provider
10265          * implementation.
10266          */
10267         public static final String METADATA_ACCOUNT_TYPE = "android.provider.account_type";
10268 
10269         /**
10270          * A string associated with an {@link #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS} activity
10271          * describing {@link DataColumns#MIMETYPE} for the corresponding Contacts Provider
10272          * implementation.
10273          */
10274         public static final String METADATA_MIMETYPE = "android.provider.mimetype";
10275 
10276         /**
10277          * Starts an Activity that lets the user select the multiple phones from a
10278          * list of phone numbers which come from the contacts or
10279          * {@link #EXTRA_PHONE_URIS}.
10280          * <p>
10281          * The phone numbers being passed in through {@link #EXTRA_PHONE_URIS}
10282          * could belong to the contacts or not, and will be selected by default.
10283          * <p>
10284          * The user's selection will be returned from
10285          * {@link android.app.Activity#onActivityResult(int, int, android.content.Intent)}
10286          * if the resultCode is
10287          * {@link android.app.Activity#RESULT_OK}, the array of picked phone
10288          * numbers are in the Intent's
10289          * {@link #EXTRA_PHONE_URIS}; otherwise, the
10290          * {@link android.app.Activity#RESULT_CANCELED} is returned if the user
10291          * left the Activity without changing the selection.
10292          *
10293          * @hide
10294          */
10295         public static final String ACTION_GET_MULTIPLE_PHONES =
10296                 "com.android.contacts.action.GET_MULTIPLE_PHONES";
10297 
10298         /**
10299          * A broadcast action which is sent when any change has been made to the profile, such
10300          * as the profile name or the picture.  A receiver must have
10301          * the android.permission.READ_PROFILE permission.
10302          *
10303          * @hide
10304          */
10305         public static final String ACTION_PROFILE_CHANGED =
10306                 "android.provider.Contacts.PROFILE_CHANGED";
10307 
10308         /**
10309          * Used with {@link #SHOW_OR_CREATE_CONTACT} to force creating a new
10310          * contact if no matching contact found. Otherwise, default behavior is
10311          * to prompt user with dialog before creating.
10312          * <p>
10313          * Type: BOOLEAN
10314          */
10315         public static final String EXTRA_FORCE_CREATE =
10316                 "com.android.contacts.action.FORCE_CREATE";
10317 
10318         /**
10319          * Used with {@link #SHOW_OR_CREATE_CONTACT} to specify an exact
10320          * description to be shown when prompting user about creating a new
10321          * contact.
10322          * <p>
10323          * Type: STRING
10324          */
10325         public static final String EXTRA_CREATE_DESCRIPTION =
10326             "com.android.contacts.action.CREATE_DESCRIPTION";
10327 
10328         /**
10329          * Used with {@link #ACTION_GET_MULTIPLE_PHONES} as the input or output value.
10330          * <p>
10331          * The phone numbers want to be picked by default should be passed in as
10332          * input value. These phone numbers could belong to the contacts or not.
10333          * <p>
10334          * The phone numbers which were picked by the user are returned as output
10335          * value.
10336          * <p>
10337          * Type: array of URIs, the tel URI is used for the phone numbers which don't
10338          * belong to any contact, the content URI is used for phone id in contacts.
10339          *
10340          * @hide
10341          */
10342         public static final String EXTRA_PHONE_URIS =
10343             "com.android.contacts.extra.PHONE_URIS";
10344 
10345         /**
10346          * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to specify a
10347          * dialog location using screen coordinates. When not specified, the
10348          * dialog will be centered.
10349          *
10350          * @hide
10351          */
10352         @Deprecated
10353         public static final String EXTRA_TARGET_RECT = "target_rect";
10354 
10355         /**
10356          * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to specify a
10357          * desired dialog style, usually a variation on size. One of
10358          * {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or {@link #MODE_LARGE}.
10359          *
10360          * @hide
10361          */
10362         @Deprecated
10363         public static final String EXTRA_MODE = "mode";
10364 
10365         /**
10366          * Value for {@link #EXTRA_MODE} to show a small-sized dialog.
10367          *
10368          * @hide
10369          */
10370         @Deprecated
10371         public static final int MODE_SMALL = 1;
10372 
10373         /**
10374          * Value for {@link #EXTRA_MODE} to show a medium-sized dialog.
10375          *
10376          * @hide
10377          */
10378         @Deprecated
10379         public static final int MODE_MEDIUM = 2;
10380 
10381         /**
10382          * Value for {@link #EXTRA_MODE} to show a large-sized dialog.
10383          *
10384          * @hide
10385          */
10386         @Deprecated
10387         public static final int MODE_LARGE = 3;
10388 
10389         /**
10390          * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to indicate
10391          * a list of specific MIME-types to exclude and not display. Stored as a
10392          * {@link String} array.
10393          *
10394          * @hide
10395          */
10396         @Deprecated
10397         public static final String EXTRA_EXCLUDE_MIMES = "exclude_mimes";
10398 
10399         /**
10400          * Convenience class that contains string constants used
10401          * to create contact {@link android.content.Intent Intents}.
10402          */
10403         public static final class Insert {
10404             /** The action code to use when adding a contact */
10405             public static final String ACTION = Intent.ACTION_INSERT;
10406 
10407             /**
10408              * If present, forces a bypass of quick insert mode.
10409              */
10410             public static final String FULL_MODE = "full_mode";
10411 
10412             /**
10413              * The extra field for the contact name.
10414              * <P>Type: String</P>
10415              */
10416             public static final String NAME = "name";
10417 
10418             // TODO add structured name values here.
10419 
10420             /**
10421              * The extra field for the contact phonetic name.
10422              * <P>Type: String</P>
10423              */
10424             public static final String PHONETIC_NAME = "phonetic_name";
10425 
10426             /**
10427              * The extra field for the contact company.
10428              * <P>Type: String</P>
10429              */
10430             public static final String COMPANY = "company";
10431 
10432             /**
10433              * The extra field for the contact job title.
10434              * <P>Type: String</P>
10435              */
10436             public static final String JOB_TITLE = "job_title";
10437 
10438             /**
10439              * The extra field for the contact notes.
10440              * <P>Type: String</P>
10441              */
10442             public static final String NOTES = "notes";
10443 
10444             /**
10445              * The extra field for the contact phone number.
10446              * <P>Type: String</P>
10447              */
10448             public static final String PHONE = "phone";
10449 
10450             /**
10451              * The extra field for the contact phone number type.
10452              * <P>Type: Either an integer value from
10453              * {@link CommonDataKinds.Phone},
10454              *  or a string specifying a custom label.</P>
10455              */
10456             public static final String PHONE_TYPE = "phone_type";
10457 
10458             /**
10459              * The extra field for the phone isprimary flag.
10460              * <P>Type: boolean</P>
10461              */
10462             public static final String PHONE_ISPRIMARY = "phone_isprimary";
10463 
10464             /**
10465              * The extra field for an optional second contact phone number.
10466              * <P>Type: String</P>
10467              */
10468             public static final String SECONDARY_PHONE = "secondary_phone";
10469 
10470             /**
10471              * The extra field for an optional second contact phone number type.
10472              * <P>Type: Either an integer value from
10473              * {@link CommonDataKinds.Phone},
10474              *  or a string specifying a custom label.</P>
10475              */
10476             public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";
10477 
10478             /**
10479              * The extra field for an optional third contact phone number.
10480              * <P>Type: String</P>
10481              */
10482             public static final String TERTIARY_PHONE = "tertiary_phone";
10483 
10484             /**
10485              * The extra field for an optional third contact phone number type.
10486              * <P>Type: Either an integer value from
10487              * {@link CommonDataKinds.Phone},
10488              *  or a string specifying a custom label.</P>
10489              */
10490             public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
10491 
10492             /**
10493              * The extra field for the contact email address.
10494              * <P>Type: String</P>
10495              */
10496             public static final String EMAIL = "email";
10497 
10498             /**
10499              * The extra field for the contact email type.
10500              * <P>Type: Either an integer value from
10501              * {@link CommonDataKinds.Email}
10502              *  or a string specifying a custom label.</P>
10503              */
10504             public static final String EMAIL_TYPE = "email_type";
10505 
10506             /**
10507              * The extra field for the email isprimary flag.
10508              * <P>Type: boolean</P>
10509              */
10510             public static final String EMAIL_ISPRIMARY = "email_isprimary";
10511 
10512             /**
10513              * The extra field for an optional second contact email address.
10514              * <P>Type: String</P>
10515              */
10516             public static final String SECONDARY_EMAIL = "secondary_email";
10517 
10518             /**
10519              * The extra field for an optional second contact email type.
10520              * <P>Type: Either an integer value from
10521              * {@link CommonDataKinds.Email}
10522              *  or a string specifying a custom label.</P>
10523              */
10524             public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";
10525 
10526             /**
10527              * The extra field for an optional third contact email address.
10528              * <P>Type: String</P>
10529              */
10530             public static final String TERTIARY_EMAIL = "tertiary_email";
10531 
10532             /**
10533              * The extra field for an optional third contact email type.
10534              * <P>Type: Either an integer value from
10535              * {@link CommonDataKinds.Email}
10536              *  or a string specifying a custom label.</P>
10537              */
10538             public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
10539 
10540             /**
10541              * The extra field for the contact postal address.
10542              * <P>Type: String</P>
10543              */
10544             public static final String POSTAL = "postal";
10545 
10546             /**
10547              * The extra field for the contact postal address type.
10548              * <P>Type: Either an integer value from
10549              * {@link CommonDataKinds.StructuredPostal}
10550              *  or a string specifying a custom label.</P>
10551              */
10552             public static final String POSTAL_TYPE = "postal_type";
10553 
10554             /**
10555              * The extra field for the postal isprimary flag.
10556              * <P>Type: boolean</P>
10557              */
10558             public static final String POSTAL_ISPRIMARY = "postal_isprimary";
10559 
10560             /**
10561              * The extra field for an IM handle.
10562              * <P>Type: String</P>
10563              */
10564             public static final String IM_HANDLE = "im_handle";
10565 
10566             /**
10567              * The extra field for the IM protocol
10568              */
10569             public static final String IM_PROTOCOL = "im_protocol";
10570 
10571             /**
10572              * The extra field for the IM isprimary flag.
10573              * <P>Type: boolean</P>
10574              */
10575             public static final String IM_ISPRIMARY = "im_isprimary";
10576 
10577             /**
10578              * The extra field that allows the client to supply multiple rows of
10579              * arbitrary data for a single contact created using the {@link Intent#ACTION_INSERT}
10580              * or edited using {@link Intent#ACTION_EDIT}. It is an ArrayList of
10581              * {@link ContentValues}, one per data row. Supplying this extra is
10582              * similar to inserting multiple rows into the {@link Data} table,
10583              * except the user gets a chance to see and edit them before saving.
10584              * Each ContentValues object must have a value for {@link Data#MIMETYPE}.
10585              * If supplied values are not visible in the editor UI, they will be
10586              * dropped.  Duplicate data will dropped.  Some fields
10587              * like {@link CommonDataKinds.Email#TYPE Email.TYPE} may be automatically
10588              * adjusted to comply with the constraints of the specific account type.
10589              * For example, an Exchange contact can only have one phone numbers of type Home,
10590              * so the contact editor may choose a different type for this phone number to
10591              * avoid dropping the valueable part of the row, which is the phone number.
10592              * <p>
10593              * Example:
10594              * <pre>
10595              *  ArrayList&lt;ContentValues&gt; data = new ArrayList&lt;ContentValues&gt;();
10596              *
10597              *  ContentValues row1 = new ContentValues();
10598              *  row1.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
10599              *  row1.put(Organization.COMPANY, "Android");
10600              *  data.add(row1);
10601              *
10602              *  ContentValues row2 = new ContentValues();
10603              *  row2.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
10604              *  row2.put(Email.TYPE, Email.TYPE_CUSTOM);
10605              *  row2.put(Email.LABEL, "Green Bot");
10606              *  row2.put(Email.ADDRESS, "android@android.com");
10607              *  data.add(row2);
10608              *
10609              *  Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
10610              *  intent.putParcelableArrayListExtra(Insert.DATA, data);
10611              *
10612              *  startActivity(intent);
10613              * </pre>
10614              */
10615             public static final String DATA = "data";
10616 
10617             /**
10618              * Used to specify the account in which to create the new contact.
10619              * <p>
10620              * If this value is not provided, the user is presented with a disambiguation
10621              * dialog to chose an account
10622              * <p>
10623              * Type: {@link Account}
10624              */
10625             public static final String EXTRA_ACCOUNT = "android.provider.extra.ACCOUNT";
10626 
10627             /**
10628              * Used to specify the data set within the account in which to create the
10629              * new contact.
10630              * <p>
10631              * This value is optional - if it is not specified, the contact will be
10632              * created in the base account, with no data set.
10633              * <p>
10634              * Type: String
10635              */
10636             public static final String EXTRA_DATA_SET = "android.provider.extra.DATA_SET";
10637         }
10638     }
10639 
10640     /**
10641      * @hide
10642      * @deprecated These columns were never public since added. They will not be supported
10643      * as of Android version {@link android.os.Build.VERSION_CODES#R}.
10644      */
10645     @Deprecated
10646     @SystemApi
10647     protected interface MetadataSyncColumns {
10648 
10649         /**
10650          * The raw contact backup id.
10651          * A reference to the {@link ContactsContract.RawContacts#BACKUP_ID} that save the
10652          * persistent unique id for each raw contact within its source system.
10653          */
10654         public static final String RAW_CONTACT_BACKUP_ID = "raw_contact_backup_id";
10655 
10656         /**
10657          * The account type to which the raw_contact of this item is associated. See
10658          * {@link RawContacts#ACCOUNT_TYPE}
10659          */
10660         public static final String ACCOUNT_TYPE = "account_type";
10661 
10662         /**
10663          * The account name to which the raw_contact of this item is associated. See
10664          * {@link RawContacts#ACCOUNT_NAME}
10665          */
10666         public static final String ACCOUNT_NAME = "account_name";
10667 
10668         /**
10669          * The data set within the account that the raw_contact of this row belongs to. This allows
10670          * multiple sync adapters for the same account type to distinguish between
10671          * each others' data.
10672          * {@link RawContacts#DATA_SET}
10673          */
10674         public static final String DATA_SET = "data_set";
10675 
10676         /**
10677          * A text column contains the Json string got from People API. The Json string contains
10678          * all the metadata related to the raw contact, i.e., all the data fields and
10679          * aggregation exceptions.
10680          *
10681          * Here is an example of the Json string got from the actual schema.
10682          * <pre>
10683          *     {
10684          *       "unique_contact_id": {
10685          *         "account_type": "CUSTOM_ACCOUNT",
10686          *         "custom_account_type": "facebook",
10687          *         "account_name": "android-test",
10688          *         "contact_id": "1111111",
10689          *         "data_set": "FOCUS"
10690          *       },
10691          *       "contact_prefs": {
10692          *         "send_to_voicemail": true,
10693          *         "starred": false,
10694          *         "pinned": 2
10695          *       },
10696          *       "aggregation_data": [
10697          *         {
10698          *           "type": "TOGETHER",
10699          *           "contact_ids": [
10700          *             {
10701          *               "account_type": "GOOGLE_ACCOUNT",
10702          *               "account_name": "android-test2",
10703          *               "contact_id": "2222222",
10704          *               "data_set": "GOOGLE_PLUS"
10705          *             },
10706          *             {
10707          *               "account_type": "GOOGLE_ACCOUNT",
10708          *               "account_name": "android-test3",
10709          *               "contact_id": "3333333",
10710          *               "data_set": "CUSTOM",
10711          *               "custom_data_set": "custom type"
10712          *             }
10713          *           ]
10714          *         }
10715          *       ],
10716          *       "field_data": [
10717          *         {
10718          *           "field_data_id": "1001",
10719          *           "field_data_prefs": {
10720          *             "is_primary": true,
10721          *             "is_super_primary": true
10722          *           },
10723          *           "usage_stats": [
10724          *             {
10725          *               "usage_type": "CALL",
10726          *               "last_time_used": 10000001,
10727          *               "usage_count": 10
10728          *             }
10729          *           ]
10730          *         }
10731          *       ]
10732          *     }
10733          * </pre>
10734          */
10735         public static final String DATA = "data";
10736 
10737         /**
10738          * The "deleted" flag: "0" by default, "1" if the row has been marked
10739          * for deletion. When {@link android.content.ContentResolver#delete} is
10740          * called on a raw contact, updating MetadataSync table to set the flag of the raw contact
10741          * as "1", then metadata sync adapter deletes the raw contact metadata on the server.
10742          * <P>Type: INTEGER</P>
10743          */
10744         public static final String DELETED = "deleted";
10745     }
10746 
10747     /**
10748      * Constants for the metadata sync table. This table is used to cache the metadata_sync data
10749      * from server before it is merged into other CP2 tables.
10750      *
10751      * @hide
10752      * @deprecated These columns were never public since added. They will not be supported
10753      * as of Android version {@link android.os.Build.VERSION_CODES#R}.
10754      */
10755     @Deprecated
10756     @SystemApi
10757     public static final class MetadataSync implements BaseColumns, MetadataSyncColumns {
10758 
10759         /** The authority for the contacts metadata */
10760         public static final String METADATA_AUTHORITY = "com.android.contacts.metadata";
10761 
10762         /** A content:// style uri to the authority for the contacts metadata */
10763         public static final Uri METADATA_AUTHORITY_URI = Uri.parse(
10764                 "content://" + METADATA_AUTHORITY);
10765 
10766         /**
10767          * This utility class cannot be instantiated
10768          */
MetadataSync()10769         private MetadataSync() {
10770         }
10771 
10772         /**
10773          * The content:// style URI for this table.
10774          */
10775         public static final Uri CONTENT_URI = Uri.withAppendedPath(METADATA_AUTHORITY_URI,
10776                 "metadata_sync");
10777 
10778         /**
10779          * The MIME type of {@link #CONTENT_URI} providing a directory of contact metadata
10780          */
10781         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata";
10782 
10783         /**
10784          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single contact metadata.
10785          */
10786         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata";
10787     }
10788 
10789     /**
10790      * @hide
10791      * @deprecated These columns are no longer supported as of Android version
10792      * {@link android.os.Build.VERSION_CODES#R}.
10793      */
10794     @Deprecated
10795     @SystemApi
10796     protected interface MetadataSyncStateColumns {
10797 
10798         /**
10799          * A reference to the name of the account to which this state belongs
10800          * <P>Type: STRING</P>
10801          */
10802         public static final String ACCOUNT_TYPE = "account_type";
10803 
10804         /**
10805          * A reference to the type of the account to which this state belongs
10806          * <P>Type: STRING</P>
10807          */
10808         public static final String ACCOUNT_NAME = "account_name";
10809 
10810         /**
10811          * A reference to the data set within the account to which this state belongs
10812          * <P>Type: STRING</P>
10813          */
10814         public static final String DATA_SET = "data_set";
10815 
10816         /**
10817          * The sync state associated with this account.
10818          * <P>Type: Blob</P>
10819          */
10820         public static final String STATE = "state";
10821     }
10822 
10823     /**
10824      * Constants for the metadata_sync_state table. This table is used to store the metadata
10825      * sync state for a set of accounts.
10826      *
10827      * @hide
10828      * @deprecated These columns are no longer supported as of Android version
10829      * {@link android.os.Build.VERSION_CODES#R}.
10830      */
10831     @Deprecated
10832     @SystemApi
10833     public static final class MetadataSyncState implements BaseColumns, MetadataSyncStateColumns {
10834 
10835         /**
10836          * This utility class cannot be instantiated
10837          */
MetadataSyncState()10838         private MetadataSyncState() {
10839         }
10840 
10841         /**
10842          * The content:// style URI for this table.
10843          */
10844         public static final Uri CONTENT_URI =
10845                 Uri.withAppendedPath(MetadataSync.METADATA_AUTHORITY_URI, "metadata_sync_state");
10846 
10847         /**
10848          * The MIME type of {@link #CONTENT_URI} providing a directory of contact metadata sync
10849          * states.
10850          */
10851         public static final String CONTENT_TYPE =
10852                 "vnd.android.cursor.dir/contact_metadata_sync_state";
10853 
10854         /**
10855          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single contact metadata sync
10856          * state.
10857          */
10858         public static final String CONTENT_ITEM_TYPE =
10859                 "vnd.android.cursor.item/contact_metadata_sync_state";
10860     }
10861 
nullSafeCall(@onNull ContentResolver resolver, @NonNull Uri uri, @NonNull String method, @Nullable String arg, @Nullable Bundle extras)10862     private static Bundle nullSafeCall(@NonNull ContentResolver resolver, @NonNull Uri uri,
10863             @NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
10864         try (ContentProviderClient client = resolver.acquireContentProviderClient(uri)) {
10865             return client.call(method, arg, extras);
10866         } catch (RemoteException e) {
10867             throw e.rethrowAsRuntimeException();
10868         }
10869     }
10870 }
10871