Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a0a45ef authored by Gary Mai's avatar Gary Mai
Browse files

Add Sim categorization Java API to ContactsContract

Adding just the client facing APIs and docs

Test: Manual build and flash
Bug: 170653527
Change-Id: I51da8a61fa5b43b3127f8cf4fc52fbd77e219404
parent d90d9a1a
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -38655,6 +38655,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
+5 −0
Original line number Diff line number Diff line
@@ -8366,6 +8366,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);
+323 −0
Original line number Diff line number Diff line
@@ -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
     */