diff options
| -rw-r--r-- | core/api/current.txt | 19 | ||||
| -rw-r--r-- | core/api/system-current.txt | 5 | ||||
| -rw-r--r-- | core/java/android/provider/ContactsContract.java | 323 |
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 */ |