summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt19
-rw-r--r--core/api/system-current.txt5
-rw-r--r--core/java/android/provider/ContactsContract.java323
3 files changed, 347 insertions, 0 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index ed92c2977a2f..5af08e33d9e1 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -38699,6 +38699,25 @@ package android.provider {
field public static final String UNGROUPED_WITH_PHONES = "summ_phones";
}
+ public static final class ContactsContract.SimAccount implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public String getAccountName();
+ method @NonNull public String getAccountType();
+ method public int getEfType();
+ method public int getSimSlotIndex();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int ADN_EF_TYPE = 1; // 0x1
+ field @NonNull public static final android.os.Parcelable.Creator<android.provider.ContactsContract.SimAccount> CREATOR;
+ field public static final int FDN_EF_TYPE = 3; // 0x3
+ field public static final int SDN_EF_TYPE = 2; // 0x2
+ field public static final int UNKNOWN_EF_TYPE = 0; // 0x0
+ }
+
+ public static final class ContactsContract.SimContacts {
+ method @NonNull public static java.util.List<android.provider.ContactsContract.SimAccount> getSimAccounts(@NonNull android.content.ContentResolver);
+ field public static final String ACTION_SIM_ACCOUNTS_CHANGED = "android.provider.action.SIM_ACCOUNTS_CHANGED";
+ }
+
protected static interface ContactsContract.StatusColumns {
field public static final int AVAILABLE = 5; // 0x5
field public static final int AWAY = 2; // 0x2
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 8eb1b5f084fe..5270d0054cf4 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -8383,6 +8383,11 @@ package android.provider {
field @Deprecated public static final String STATE = "state";
}
+ public static final class ContactsContract.SimContacts {
+ method @RequiresPermission("android.contacts.permission.MANAGE_SIM_ACCOUNTS") public static void addSimAccount(@NonNull android.content.ContentResolver, @NonNull String, @NonNull String, int, int);
+ method @RequiresPermission("android.contacts.permission.MANAGE_SIM_ACCOUNTS") public static void removeSimAccounts(@NonNull android.content.ContentResolver, int);
+ }
+
public final class DeviceConfig {
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static boolean getBoolean(@NonNull String, @NonNull String, boolean);
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 03e8a070b237..da06e821ea9f 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -19,6 +19,7 @@ package android.provider;
import android.accounts.Account;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
@@ -47,6 +48,9 @@ import android.database.DatabaseUtils;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
@@ -54,11 +58,15 @@ import android.util.DisplayMetrics;
import android.util.Pair;
import android.view.View;
+import com.google.android.collect.Sets;
+
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
/**
* <p>
@@ -8188,6 +8196,321 @@ public final class ContactsContract {
public static final String RAW_CONTACT_ID2 = "raw_contact_id2";
}
+
+ /**
+ * Class containing utility methods around determine what accounts in the ContactsProvider are
+ * related to the SIM cards in the device.
+ * <p>
+ * Apps interested in managing contacts from SIM cards can query the ContactsProvider using
+ * {@link #getSimAccounts(ContentResolver)} to get all accounts that relate to SIM cards. They
+ * can also register a receiver for the {@link #ACTION_SIM_ACCOUNTS_CHANGED} broadcast to be
+ * notified when these accounts change.
+ */
+ public static final class SimContacts {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private SimContacts() {
+ }
+
+ /**
+ * The method to invoke in order to add a new SIM account for a newly inserted SIM card.
+ *
+ * @hide
+ */
+ public static final String ADD_SIM_ACCOUNT_METHOD = "addSimAccount";
+
+ /**
+ * The method to invoke in order to remove a SIM account once the corresponding SIM card is
+ * ejected.
+ *
+ * @hide
+ */
+ public static final String REMOVE_SIM_ACCOUNT_METHOD = "removeSimAccount";
+
+ /**
+ * The method to invoke in order to query all SIM accounts.
+ *
+ * @hide
+ */
+ public static final String QUERY_SIM_ACCOUNTS_METHOD = "querySimAccounts";
+
+ /**
+ * Key to add in the outgoing Bundle for the SIM slot.
+ *
+ * @hide
+ */
+ public static final String KEY_SIM_SLOT_INDEX = "key_sim_slot_index";
+
+ /**
+ * Key to add in the outgoing Bundle for the SIM account's EF type.
+ * See {@link SimAccount#mEfType} for more information.
+ *
+ * @hide
+ */
+ public static final String KEY_SIM_EF_TYPE = "key_sim_ef_type";
+
+ /**
+ * Key to add in the outgoing Bundle for the account name.
+ *
+ * @hide
+ */
+ public static final String KEY_ACCOUNT_NAME = "key_sim_account_name";
+
+ /**
+ * Key to add in the outgoing Bundle for the account type.
+ *
+ * @hide
+ */
+ public static final String KEY_ACCOUNT_TYPE = "key_sim_account_type";
+
+ /**
+ * Key in the incoming Bundle for the all the SIM accounts.
+ *
+ * @hide
+ */
+ public static final String KEY_SIM_ACCOUNTS = "key_sim_accounts";
+
+ /**
+ * Broadcast Action: SIM accounts have changed, call
+ * {@link #getSimAccounts(ContentResolver)} to get the latest.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SIM_ACCOUNTS_CHANGED =
+ "android.provider.action.SIM_ACCOUNTS_CHANGED";
+
+ /**
+ * Adds a new SIM account that maps to the corresponding SIM slot.
+ *
+ * @param accountName accountName value for the account
+ * @param accountType accountType value for the account
+ * @param contentResolver to perform the operation on.
+ * @param simSlotIndex the SIM slot index of this new account.
+ * @param efType the EF type of this new account.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission("android.contacts.permission.MANAGE_SIM_ACCOUNTS")
+ public static void addSimAccount(@NonNull ContentResolver contentResolver,
+ @NonNull String accountName,
+ @NonNull String accountType,
+ int simSlotIndex,
+ int efType) {
+ if (simSlotIndex < 0) {
+ throw new IllegalArgumentException("Sim slot is negative");
+ }
+ if (!SimAccount.getValidEfTypes().contains(efType)) {
+ throw new IllegalArgumentException("Invalid EF type");
+ }
+ if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
+ throw new IllegalArgumentException("Account name or type is empty");
+ }
+
+ Bundle extras = new Bundle();
+ extras.putInt(KEY_SIM_SLOT_INDEX, simSlotIndex);
+ extras.putInt(KEY_SIM_EF_TYPE, efType);
+ extras.putString(KEY_ACCOUNT_NAME, accountName);
+ extras.putString(KEY_ACCOUNT_TYPE, accountType);
+
+ contentResolver.call(ContactsContract.AUTHORITY_URI,
+ ContactsContract.SimContacts.ADD_SIM_ACCOUNT_METHOD,
+ null, extras);
+ }
+
+ /**
+ * Removes all SIM accounts that map to the corresponding SIM slot.
+ *
+ * @param contentResolver to perform the operation on.
+ * @param simSlotIndex the SIM slot index of the accounts to remove.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission("android.contacts.permission.MANAGE_SIM_ACCOUNTS")
+ public static void removeSimAccounts(@NonNull ContentResolver contentResolver,
+ int simSlotIndex) {
+ if (simSlotIndex < 0) {
+ throw new IllegalArgumentException("Sim slot is negative");
+ }
+
+ Bundle extras = new Bundle();
+ extras.putInt(KEY_SIM_SLOT_INDEX, simSlotIndex);
+
+ contentResolver.call(ContactsContract.AUTHORITY_URI,
+ ContactsContract.SimContacts.REMOVE_SIM_ACCOUNT_METHOD,
+ null, extras);
+ }
+
+ /**
+ * Returns all known SIM accounts. May be empty but never null.
+ *
+ * @param contentResolver content resolver to query.
+ */
+ public static @NonNull List<SimAccount> getSimAccounts(
+ @NonNull ContentResolver contentResolver) {
+ Bundle response = contentResolver.call(ContactsContract.AUTHORITY_URI,
+ ContactsContract.SimContacts.QUERY_SIM_ACCOUNTS_METHOD,
+ null, null);
+ List<SimAccount> result = response.getParcelableArrayList(KEY_SIM_ACCOUNTS);
+
+ if (result == null) {
+ result = new ArrayList<>();
+ }
+
+ return result;
+ }
+ }
+
+ /**
+ * A parcelable class encapsulating account data for contacts that originate from a SIM card.
+ */
+ public static final class SimAccount implements Parcelable {
+ /** An invalid EF type identifier. */
+ public static final int UNKNOWN_EF_TYPE = 0;
+ /** EF type identifier for the ADN partition. */
+ public static final int ADN_EF_TYPE = 1;
+ /** EF type identifier for the SDN partition. */
+ public static final int SDN_EF_TYPE = 2;
+ /** EF type identifier for the FDN partition. */
+ public static final int FDN_EF_TYPE = 3;
+
+ /**
+ * The account_name of this SIM account. See {@link RawContacts#ACCOUNT_NAME}.
+ */
+ private final String mAccountName;
+
+ /**
+ * The account_type of this SIM account. See {@link RawContacts#ACCOUNT_TYPE}.
+ */
+ private final String mAccountType;
+
+ /**
+ * The slot index of the SIM card this account maps to. See {@link
+ * android.telephony.SubscriptionInfo#getSimSlotIndex()}.
+ */
+ private final int mSimSlotIndex;
+
+ /**
+ * The EF type of the contacts stored in this account. One of
+ * {@link #ADN_EF_TYPE}, {@link #SDN_EF_TYPE} or {@link #FDN_EF_TYPE}.
+ *
+ * EF type is the Elementary File type of the partition these contacts come from within the
+ * SIM card.
+ *
+ * ADN is the "abbreviated dialing numbers" or the user managed SIM contacts.
+ *
+ * SDN is the "service dialing numbers" which are usually preloaded onto the SIM by the
+ * carrier.
+ *
+ * FDN is the "fixed dialing numbers" which are contacts which can only be dialed from that
+ * SIM, used in cases such as parental control.
+ */
+ private final int mEfType;
+
+ /**
+ * @return A set containing all known EF type values
+ * @hide
+ */
+ public static @NonNull Set<Integer> getValidEfTypes() {
+ return Sets.newArraySet(ADN_EF_TYPE, SDN_EF_TYPE, FDN_EF_TYPE);
+ }
+
+ /**
+ * @hide
+ */
+ public SimAccount(@NonNull String accountName, @NonNull String accountType,
+ int simSlotIndex,
+ int efType) {
+ this.mAccountName = accountName;
+ this.mAccountType = accountType;
+ this.mSimSlotIndex = simSlotIndex;
+ this.mEfType = efType;
+ }
+
+ /**
+ * @return The account_name of this SIM account. See {@link RawContacts#ACCOUNT_NAME}.
+ */
+ public @NonNull String getAccountName() {
+ return mAccountName;
+ }
+
+ /**
+ * @return The account_type of this SIM account. See {@link RawContacts#ACCOUNT_TYPE}.
+ */
+ public @NonNull String getAccountType() {
+ return mAccountType;
+ }
+
+ /**
+ * @return The slot index of the SIM card this account maps to. See
+ * {@link android.telephony.SubscriptionInfo#getSimSlotIndex()}.
+ */
+ public int getSimSlotIndex() {
+ return mSimSlotIndex;
+ }
+
+ /**
+ * @return The EF type of the contacts stored in this account.
+ */
+ public int getEfType() {
+ return mEfType;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mAccountName, mAccountType, mSimSlotIndex, mEfType);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) return false;
+ if (obj == this) return true;
+
+ SimAccount toCompare;
+ try {
+ toCompare = (SimAccount) obj;
+ } catch (ClassCastException ex) {
+ return false;
+ }
+
+ return mSimSlotIndex == toCompare.mSimSlotIndex
+ && mEfType == toCompare.mEfType
+ && Objects.equals(mAccountName, toCompare.mAccountName)
+ && Objects.equals(mAccountType, toCompare.mAccountType);
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mAccountName);
+ dest.writeString(mAccountType);
+ dest.writeInt(mSimSlotIndex);
+ dest.writeInt(mEfType);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Parcelable.Creator<SimAccount> CREATOR =
+ new Parcelable.Creator<SimAccount>() {
+ @Override
+ public SimAccount createFromParcel(Parcel source) {
+ String accountName = source.readString();
+ String accountType = source.readString();
+ int simSlot = source.readInt();
+ int efType = source.readInt();
+ SimAccount simAccount = new SimAccount(accountName, accountType, simSlot,
+ efType);
+ return simAccount;
+ }
+
+ @Override
+ public SimAccount[] newArray(int size) {
+ return new SimAccount[size];
+ }
+ };
+ }
+
/**
* @see Settings
*/