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 * <meta-data android:name="android.content.ContactDirectory" 383 * android:value="true" /> 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("limit", "3") 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, "Mike Sullivan"); 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<ContentProviderOperation> ops = 2587 * new ArrayList<ContentProviderOperation>(); 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, "Mike Sullivan") 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 + "<>0", null, null, null); 2659 * ... 2660 * Cursor c2 = getContentResolver().query(rawContactUri, 2661 * RawContacts.DELETED + "<>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<ContentProviderOperation> ops = 5131 * new ArrayList<ContentProviderOperation>(); 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<ContentProviderOperation> ops = 5150 * new ArrayList<ContentProviderOperation>(); 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<ContentProviderOperation> ops = 5167 * new ArrayList<ContentProviderOperation>(); 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 + "=?" + " 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 + "=?" + " 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<ContentProviderOperation> ops = 6626 * new ArrayList<ContentProviderOperation>(); 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, "Bob Parr") 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<ContentValues> data = new ArrayList<ContentValues>(); 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