|  | /* | 
|  | * Copyright (C) 2014 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | package android.telephony; | 
|  |  | 
|  | import static android.text.TextUtils.formatSimple; | 
|  |  | 
|  | import android.annotation.Nullable; | 
|  | import android.annotation.SystemApi; | 
|  | import android.compat.annotation.UnsupportedAppUsage; | 
|  | import android.content.Context; | 
|  | import android.content.pm.PackageInfo; | 
|  | import android.content.pm.PackageManager; | 
|  | import android.graphics.Bitmap; | 
|  | import android.graphics.BitmapFactory; | 
|  | import android.graphics.Canvas; | 
|  | import android.graphics.Color; | 
|  | import android.graphics.Paint; | 
|  | import android.graphics.PorterDuff; | 
|  | import android.graphics.PorterDuffColorFilter; | 
|  | import android.graphics.Rect; | 
|  | import android.graphics.Typeface; | 
|  | import android.os.Build; | 
|  | import android.os.Parcel; | 
|  | import android.os.ParcelUuid; | 
|  | import android.os.Parcelable; | 
|  | import android.telephony.SubscriptionManager.UsageSetting; | 
|  | import android.text.TextUtils; | 
|  | import android.util.DisplayMetrics; | 
|  | import android.util.Log; | 
|  |  | 
|  | import com.android.internal.telephony.util.TelephonyUtils; | 
|  | import com.android.telephony.Rlog; | 
|  |  | 
|  | import java.util.ArrayList; | 
|  | import java.util.Arrays; | 
|  | import java.util.Collections; | 
|  | import java.util.List; | 
|  | import java.util.Objects; | 
|  |  | 
|  | /** | 
|  | * A Parcelable class for Subscription Information. | 
|  | */ | 
|  | public class SubscriptionInfo implements Parcelable { | 
|  |  | 
|  | /** | 
|  | * Size of text to render on the icon. | 
|  | */ | 
|  | private static final int TEXT_SIZE = 16; | 
|  |  | 
|  | /** | 
|  | * Subscription Identifier, this is a device unique number | 
|  | * and not an index into an array | 
|  | */ | 
|  | private int mId; | 
|  |  | 
|  | /** | 
|  | * The GID for a SIM that maybe associated with this subscription, empty if unknown | 
|  | */ | 
|  | private String mIccId; | 
|  |  | 
|  | /** | 
|  | * The index of the slot that currently contains the subscription | 
|  | * and not necessarily unique and maybe INVALID_SLOT_ID if unknown | 
|  | */ | 
|  | private int mSimSlotIndex; | 
|  |  | 
|  | /** | 
|  | * The name displayed to the user that identifies this subscription | 
|  | */ | 
|  | private CharSequence mDisplayName; | 
|  |  | 
|  | /** | 
|  | * String that identifies SPN/PLMN | 
|  | * TODO : Add a new field that identifies only SPN for a sim | 
|  | */ | 
|  | private CharSequence mCarrierName; | 
|  |  | 
|  | /** | 
|  | * The subscription carrier id. | 
|  | * @see TelephonyManager#getSimCarrierId() | 
|  | */ | 
|  | private int mCarrierId; | 
|  |  | 
|  | /** | 
|  | * The source of the name, NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SPN, | 
|  | * NAME_SOURCE_SIM_PNN, or NAME_SOURCE_USER_INPUT. | 
|  | */ | 
|  | private int mNameSource; | 
|  |  | 
|  | /** | 
|  | * The color to be used for tinting the icon when displaying to the user | 
|  | */ | 
|  | private int mIconTint; | 
|  |  | 
|  | /** | 
|  | * A number presented to the user identify this subscription | 
|  | */ | 
|  | private String mNumber; | 
|  |  | 
|  | /** | 
|  | * Data roaming state, DATA_ROAMING_ENABLE, DATA_ROAMING_DISABLE | 
|  | */ | 
|  | private int mDataRoaming; | 
|  |  | 
|  | /** | 
|  | * SIM icon bitmap cache | 
|  | */ | 
|  | @Nullable private Bitmap mIconBitmap; | 
|  |  | 
|  | /** | 
|  | * Mobile Country Code | 
|  | */ | 
|  | private String mMcc; | 
|  |  | 
|  | /** | 
|  | * Mobile Network Code | 
|  | */ | 
|  | private String mMnc; | 
|  |  | 
|  | /** | 
|  | * EHPLMNs associated with the subscription | 
|  | */ | 
|  | private String[] mEhplmns; | 
|  |  | 
|  | /** | 
|  | * HPLMNs associated with the subscription | 
|  | */ | 
|  | private String[] mHplmns; | 
|  |  | 
|  | /** | 
|  | * ISO Country code for the subscription's provider | 
|  | */ | 
|  | private String mCountryIso; | 
|  |  | 
|  | /** | 
|  | * Whether the subscription is an embedded one. | 
|  | */ | 
|  | private boolean mIsEmbedded; | 
|  |  | 
|  | /** | 
|  | * The access rules for this subscription, if it is embedded and defines any. | 
|  | * This does not include access rules for non-embedded subscriptions. | 
|  | */ | 
|  | @Nullable | 
|  | private UiccAccessRule[] mNativeAccessRules; | 
|  |  | 
|  | /** | 
|  | * The carrier certificates for this subscription that are saved in carrier configs. | 
|  | * This does not include access rules from the Uicc, whether embedded or non-embedded. | 
|  | */ | 
|  | @Nullable | 
|  | private UiccAccessRule[] mCarrierConfigAccessRules; | 
|  |  | 
|  | /** | 
|  | * The string ID of the SIM card. It is the ICCID of the active profile for a UICC card and the | 
|  | * EID for an eUICC card. | 
|  | */ | 
|  | private String mCardString; | 
|  |  | 
|  | /** | 
|  | * The card ID of the SIM card. This maps uniquely to the card string. | 
|  | */ | 
|  | private int mCardId; | 
|  |  | 
|  | /** | 
|  | * Whether the subscription is opportunistic. | 
|  | */ | 
|  | private boolean mIsOpportunistic; | 
|  |  | 
|  | /** | 
|  | * A UUID assigned to the subscription group. It returns null if not assigned. | 
|  | * Check {@link SubscriptionManager#createSubscriptionGroup(List)} for more details. | 
|  | */ | 
|  | @Nullable | 
|  | private ParcelUuid mGroupUUID; | 
|  |  | 
|  | /** | 
|  | * A package name that specifies who created the group. Null if mGroupUUID is null. | 
|  | */ | 
|  | private String mGroupOwner; | 
|  |  | 
|  | /** | 
|  | * Whether group of the subscription is disabled. | 
|  | * This is only useful if it's a grouped opportunistic subscription. In this case, if all | 
|  | * primary (non-opportunistic) subscriptions in the group are deactivated (unplugged pSIM | 
|  | * or deactivated eSIM profile), we should disable this opportunistic subscription. | 
|  | */ | 
|  | private boolean mIsGroupDisabled = false; | 
|  |  | 
|  | /** | 
|  | * Profile class, PROFILE_CLASS_TESTING, PROFILE_CLASS_OPERATIONAL | 
|  | * PROFILE_CLASS_PROVISIONING, or PROFILE_CLASS_UNSET. | 
|  | * A profile on the eUICC can be defined as test, operational, provisioning, or unset. | 
|  | * The profile class will be populated from the profile metadata if present. Otherwise, | 
|  | * the profile class defaults to unset if there is no profile metadata or the subscription | 
|  | * is not on an eUICC ({@link #isEmbedded} returns false). | 
|  | */ | 
|  | private int mProfileClass; | 
|  |  | 
|  | /** | 
|  | * Type of subscription | 
|  | */ | 
|  | private int mSubscriptionType; | 
|  |  | 
|  | /** | 
|  | * Whether uicc applications are configured to enable or disable. | 
|  | * By default it's true. | 
|  | */ | 
|  | private boolean mAreUiccApplicationsEnabled = true; | 
|  |  | 
|  | /** | 
|  | * The port index of the Uicc card. | 
|  | */ | 
|  | private final int mPortIndex; | 
|  |  | 
|  | /** | 
|  | * Subscription's preferred usage setting. | 
|  | */ | 
|  | private @UsageSetting int mUsageSetting = SubscriptionManager.USAGE_SETTING_UNKNOWN; | 
|  |  | 
|  | /** | 
|  | * Public copy constructor. | 
|  | * @hide | 
|  | */ | 
|  | public SubscriptionInfo(SubscriptionInfo info) { | 
|  | this(info.mId, info.mIccId, info.mSimSlotIndex, info.mDisplayName, info.mCarrierName, | 
|  | info.mNameSource, info.mIconTint, info.mNumber, info.mDataRoaming, info.mIconBitmap, | 
|  | info.mMcc, info.mMnc, info.mCountryIso, info.mIsEmbedded, info.mNativeAccessRules, | 
|  | info.mCardString, info.mCardId, info.mIsOpportunistic, | 
|  | info.mGroupUUID == null ? null : info.mGroupUUID.toString(), info.mIsGroupDisabled, | 
|  | info.mCarrierId, info.mProfileClass, info.mSubscriptionType, info.mGroupOwner, | 
|  | info.mCarrierConfigAccessRules, info.mAreUiccApplicationsEnabled); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @hide | 
|  | */ | 
|  | public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, | 
|  | CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, | 
|  | Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, | 
|  | @Nullable UiccAccessRule[] nativeAccessRules, String cardString) { | 
|  | this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number, | 
|  | roaming, icon, mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, -1, | 
|  | false, null, false, TelephonyManager.UNKNOWN_CARRIER_ID, | 
|  | SubscriptionManager.PROFILE_CLASS_UNSET, | 
|  | SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @hide | 
|  | */ | 
|  | public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, | 
|  | CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, | 
|  | Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, | 
|  | @Nullable UiccAccessRule[] nativeAccessRules, String cardString, | 
|  | boolean isOpportunistic, @Nullable String groupUUID, int carrierId, int profileClass) { | 
|  | this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number, | 
|  | roaming, icon, mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, -1, | 
|  | isOpportunistic, groupUUID, false, carrierId, profileClass, | 
|  | SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @hide | 
|  | */ | 
|  | public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, | 
|  | CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, | 
|  | Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, | 
|  | @Nullable UiccAccessRule[] nativeAccessRules, String cardString, int cardId, | 
|  | boolean isOpportunistic, @Nullable String groupUUID, boolean isGroupDisabled, | 
|  | int carrierId, int profileClass, int subType, @Nullable String groupOwner, | 
|  | @Nullable UiccAccessRule[] carrierConfigAccessRules, | 
|  | boolean areUiccApplicationsEnabled) { | 
|  | this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number, | 
|  | roaming, icon, mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, | 
|  | cardId, isOpportunistic, groupUUID, isGroupDisabled, carrierId, profileClass, | 
|  | subType, groupOwner, carrierConfigAccessRules, areUiccApplicationsEnabled, 0); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @hide | 
|  | */ | 
|  | public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, | 
|  | CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, | 
|  | Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, | 
|  | @Nullable UiccAccessRule[] nativeAccessRules, String cardString, int cardId, | 
|  | boolean isOpportunistic, @Nullable String groupUUID, boolean isGroupDisabled, | 
|  | int carrierId, int profileClass, int subType, @Nullable String groupOwner, | 
|  | @Nullable UiccAccessRule[] carrierConfigAccessRules, | 
|  | boolean areUiccApplicationsEnabled, int portIndex) { | 
|  | this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number, | 
|  | roaming, icon, mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, | 
|  | cardId, isOpportunistic, groupUUID, isGroupDisabled, carrierId, profileClass, | 
|  | subType, groupOwner, carrierConfigAccessRules, areUiccApplicationsEnabled, | 
|  | portIndex, SubscriptionManager.USAGE_SETTING_DEFAULT); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @hide | 
|  | */ | 
|  | public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, | 
|  | CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, | 
|  | Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, | 
|  | @Nullable UiccAccessRule[] nativeAccessRules, String cardString, int cardId, | 
|  | boolean isOpportunistic, @Nullable String groupUUID, boolean isGroupDisabled, | 
|  | int carrierId, int profileClass, int subType, @Nullable String groupOwner, | 
|  | @Nullable UiccAccessRule[] carrierConfigAccessRules, | 
|  | boolean areUiccApplicationsEnabled, int portIndex, @UsageSetting int usageSetting) { | 
|  | this.mId = id; | 
|  | this.mIccId = iccId; | 
|  | this.mSimSlotIndex = simSlotIndex; | 
|  | this.mDisplayName = displayName; | 
|  | this.mCarrierName = carrierName; | 
|  | this.mNameSource = nameSource; | 
|  | this.mIconTint = iconTint; | 
|  | this.mNumber = number; | 
|  | this.mDataRoaming = roaming; | 
|  | this.mIconBitmap = icon; | 
|  | this.mMcc = mcc; | 
|  | this.mMnc = mnc; | 
|  | this.mCountryIso = countryIso; | 
|  | this.mIsEmbedded = isEmbedded; | 
|  | this.mNativeAccessRules = nativeAccessRules; | 
|  | this.mCardString = cardString; | 
|  | this.mCardId = cardId; | 
|  | this.mIsOpportunistic = isOpportunistic; | 
|  | this.mGroupUUID = groupUUID == null ? null : ParcelUuid.fromString(groupUUID); | 
|  | this.mIsGroupDisabled = isGroupDisabled; | 
|  | this.mCarrierId = carrierId; | 
|  | this.mProfileClass = profileClass; | 
|  | this.mSubscriptionType = subType; | 
|  | this.mGroupOwner = groupOwner; | 
|  | this.mCarrierConfigAccessRules = carrierConfigAccessRules; | 
|  | this.mAreUiccApplicationsEnabled = areUiccApplicationsEnabled; | 
|  | this.mPortIndex = portIndex; | 
|  | this.mUsageSetting = usageSetting; | 
|  | } | 
|  | /** | 
|  | * @return the subscription ID. | 
|  | */ | 
|  | public int getSubscriptionId() { | 
|  | return this.mId; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the ICC ID. | 
|  | * | 
|  | * Starting with API level 29 Security Patch 2021-04-05, returns the ICC ID if the calling app | 
|  | * has been granted the READ_PRIVILEGED_PHONE_STATE permission, has carrier privileges (see | 
|  | * {@link TelephonyManager#hasCarrierPrivileges}), or is a device owner or profile owner that | 
|  | * has been granted the READ_PHONE_STATE permission. The profile owner is an app that owns a | 
|  | * managed profile on the device; for more details see <a | 
|  | * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile | 
|  | * owner access is deprecated and will be removed in a future release. | 
|  | * | 
|  | * @return the ICC ID, or an empty string if one of these requirements is not met | 
|  | */ | 
|  | public String getIccId() { | 
|  | return this.mIccId; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @hide | 
|  | */ | 
|  | public void clearIccId() { | 
|  | this.mIccId = ""; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the slot index of this Subscription's SIM card. | 
|  | */ | 
|  | public int getSimSlotIndex() { | 
|  | return this.mSimSlotIndex; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the carrier id of this Subscription carrier. | 
|  | * @see TelephonyManager#getSimCarrierId() | 
|  | */ | 
|  | public int getCarrierId() { | 
|  | return this.mCarrierId; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the name displayed to the user that identifies this subscription | 
|  | */ | 
|  | public CharSequence getDisplayName() { | 
|  | return this.mDisplayName; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the name displayed to the user that identifies this subscription | 
|  | * @hide | 
|  | */ | 
|  | @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) | 
|  | public void setDisplayName(CharSequence name) { | 
|  | this.mDisplayName = name; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the name displayed to the user that identifies Subscription provider name | 
|  | */ | 
|  | public CharSequence getCarrierName() { | 
|  | return this.mCarrierName; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the name displayed to the user that identifies Subscription provider name | 
|  | * @hide | 
|  | */ | 
|  | public void setCarrierName(CharSequence name) { | 
|  | this.mCarrierName = name; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the source of the name, eg NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SPN or | 
|  | * NAME_SOURCE_USER_INPUT. | 
|  | * @hide | 
|  | */ | 
|  | @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) | 
|  | public int getNameSource() { | 
|  | return this.mNameSource; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @hide | 
|  | */ | 
|  | public void setAssociatedPlmns(String[] ehplmns, String[] hplmns) { | 
|  | mEhplmns = ehplmns; | 
|  | mHplmns = hplmns; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Creates and returns an icon {@code Bitmap} to represent this {@code SubscriptionInfo} in a | 
|  | * user interface. | 
|  | * | 
|  | * @param context A {@code Context} to get the {@code DisplayMetrics}s from. | 
|  | * | 
|  | * @return A bitmap icon for this {@code SubscriptionInfo}. | 
|  | */ | 
|  | public Bitmap createIconBitmap(Context context) { | 
|  | if (mIconBitmap == null) { | 
|  | mIconBitmap = BitmapFactory.decodeResource(context.getResources(), | 
|  | com.android.internal.R.drawable.ic_sim_card_multi_24px_clr); | 
|  | } | 
|  | int width = mIconBitmap.getWidth(); | 
|  | int height = mIconBitmap.getHeight(); | 
|  | DisplayMetrics metrics = context.getResources().getDisplayMetrics(); | 
|  |  | 
|  | // Create a new bitmap of the same size because it will be modified. | 
|  | Bitmap workingBitmap = Bitmap.createBitmap(metrics, width, height, mIconBitmap.getConfig()); | 
|  |  | 
|  | Canvas canvas = new Canvas(workingBitmap); | 
|  | Paint paint = new Paint(); | 
|  |  | 
|  | // Tint the icon with the color. | 
|  | paint.setColorFilter(new PorterDuffColorFilter(mIconTint, PorterDuff.Mode.SRC_ATOP)); | 
|  | canvas.drawBitmap(mIconBitmap, 0, 0, paint); | 
|  | paint.setColorFilter(null); | 
|  |  | 
|  | // Write the sim slot index. | 
|  | paint.setAntiAlias(true); | 
|  | paint.setTypeface(Typeface.create("sans-serif", Typeface.NORMAL)); | 
|  | paint.setColor(Color.WHITE); | 
|  | // Set text size scaled by density | 
|  | paint.setTextSize(TEXT_SIZE * metrics.density); | 
|  | // Convert sim slot index to localized string | 
|  | final String index = formatSimple("%d", mSimSlotIndex + 1); | 
|  | final Rect textBound = new Rect(); | 
|  | paint.getTextBounds(index, 0, 1, textBound); | 
|  | final float xOffset = (width / 2.f) - textBound.centerX(); | 
|  | final float yOffset = (height / 2.f) - textBound.centerY(); | 
|  | canvas.drawText(index, xOffset, yOffset, paint); | 
|  |  | 
|  | return workingBitmap; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * A highlight color to use in displaying information about this {@code PhoneAccount}. | 
|  | * | 
|  | * @return A hexadecimal color value. | 
|  | */ | 
|  | public int getIconTint() { | 
|  | return mIconTint; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the color displayed to the user that identifies this subscription | 
|  | * @hide | 
|  | */ | 
|  | @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) | 
|  | public void setIconTint(int iconTint) { | 
|  | this.mIconTint = iconTint; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the number of this subscription. | 
|  | * | 
|  | * Starting with API level 30, returns the number of this subscription if the calling app meets | 
|  | * one of the following requirements: | 
|  | * <ul> | 
|  | *     <li>If the calling app's target SDK is API level 29 or lower and the app has been granted | 
|  | *     the READ_PHONE_STATE permission. | 
|  | *     <li>If the calling app has been granted any of READ_PRIVILEGED_PHONE_STATE, | 
|  | *     READ_PHONE_NUMBERS, or READ_SMS. | 
|  | *     <li>If the calling app has carrier privileges (see {@link | 
|  | *     TelephonyManager#hasCarrierPrivileges}). | 
|  | *     <li>If the calling app is the default SMS role holder. | 
|  | * </ul> | 
|  | * | 
|  | * @return the number of this subscription, or an empty string if one of these requirements is | 
|  | * not met | 
|  | * @deprecated use {@link SubscriptionManager#getPhoneNumber(int)} instead, which takes a | 
|  | *             {@link #getSubscriptionId() subscription ID}. | 
|  | */ | 
|  | @Deprecated | 
|  | public String getNumber() { | 
|  | return mNumber; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @hide | 
|  | */ | 
|  | public void clearNumber() { | 
|  | mNumber = ""; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the data roaming state for this subscription, either | 
|  | * {@link SubscriptionManager#DATA_ROAMING_ENABLE} or {@link SubscriptionManager#DATA_ROAMING_DISABLE}. | 
|  | */ | 
|  | public int getDataRoaming() { | 
|  | return this.mDataRoaming; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the MCC. | 
|  | * @deprecated Use {@link #getMccString()} instead. | 
|  | */ | 
|  | @Deprecated | 
|  | public int getMcc() { | 
|  | try { | 
|  | return this.mMcc == null ? 0 : Integer.valueOf(this.mMcc); | 
|  | } catch (NumberFormatException e) { | 
|  | Log.w(SubscriptionInfo.class.getSimpleName(), "MCC string is not a number"); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the MNC. | 
|  | * @deprecated Use {@link #getMncString()} instead. | 
|  | */ | 
|  | @Deprecated | 
|  | public int getMnc() { | 
|  | try { | 
|  | return this.mMnc == null ? 0 : Integer.valueOf(this.mMnc); | 
|  | } catch (NumberFormatException e) { | 
|  | Log.w(SubscriptionInfo.class.getSimpleName(), "MNC string is not a number"); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return The MCC, as a string. | 
|  | */ | 
|  | public @Nullable String getMccString() { | 
|  | return this.mMcc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return The MNC, as a string. | 
|  | */ | 
|  | public @Nullable String getMncString() { | 
|  | return this.mMnc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the ISO country code | 
|  | */ | 
|  | public String getCountryIso() { | 
|  | return this.mCountryIso; | 
|  | } | 
|  |  | 
|  | /** @return whether the subscription is an eUICC one. */ | 
|  | public boolean isEmbedded() { | 
|  | return this.mIsEmbedded; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * An opportunistic subscription connects to a network that is | 
|  | * limited in functionality and / or coverage. | 
|  | * | 
|  | * @return whether subscription is opportunistic. | 
|  | */ | 
|  | public boolean isOpportunistic() { | 
|  | return mIsOpportunistic; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Used in scenarios where different subscriptions are bundled as a group. | 
|  | * It's typically a primary and an opportunistic subscription. (see {@link #isOpportunistic()}) | 
|  | * Such that those subscriptions will have some affiliated behaviors such as opportunistic | 
|  | * subscription may be invisible to the user. | 
|  | * | 
|  | * @return group UUID a String of group UUID if it belongs to a group. Otherwise | 
|  | * it will return null. | 
|  | */ | 
|  | public @Nullable ParcelUuid getGroupUuid() { | 
|  | return mGroupUUID; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @hide | 
|  | */ | 
|  | public void clearGroupUuid() { | 
|  | this.mGroupUUID = null; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @hide | 
|  | */ | 
|  | public List<String> getEhplmns() { | 
|  | return mEhplmns == null ? Collections.emptyList() : Arrays.asList(mEhplmns); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @hide | 
|  | */ | 
|  | public List<String> getHplmns() { | 
|  | return mHplmns == null ? Collections.emptyList() : Arrays.asList(mHplmns); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Return owner package of group the subscription belongs to. | 
|  | * | 
|  | * @hide | 
|  | */ | 
|  | public @Nullable String getGroupOwner() { | 
|  | return mGroupOwner; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the profile class of this subscription. | 
|  | * @hide | 
|  | */ | 
|  | @SystemApi | 
|  | public @SubscriptionManager.ProfileClass int getProfileClass() { | 
|  | return this.mProfileClass; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This method returns the type of a subscription. It can be | 
|  | * {@link SubscriptionManager#SUBSCRIPTION_TYPE_LOCAL_SIM} or | 
|  | * {@link SubscriptionManager#SUBSCRIPTION_TYPE_REMOTE_SIM}. | 
|  | * @return the type of subscription | 
|  | */ | 
|  | public @SubscriptionManager.SubscriptionType int getSubscriptionType() { | 
|  | return mSubscriptionType; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Checks whether the app with the given context is authorized to manage this subscription | 
|  | * according to its metadata. Only supported for embedded subscriptions (if {@link #isEmbedded} | 
|  | * returns true). | 
|  | * | 
|  | * @param context Context of the application to check. | 
|  | * @return whether the app is authorized to manage this subscription per its metadata. | 
|  | * @hide | 
|  | * @deprecated - Do not use. | 
|  | */ | 
|  | @Deprecated | 
|  | public boolean canManageSubscription(Context context) { | 
|  | return canManageSubscription(context, context.getPackageName()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Checks whether the given app is authorized to manage this subscription according to its | 
|  | * metadata. Only supported for embedded subscriptions (if {@link #isEmbedded} returns true). | 
|  | * | 
|  | * @param context Any context. | 
|  | * @param packageName Package name of the app to check. | 
|  | * @return whether the app is authorized to manage this subscription per its metadata. | 
|  | * @hide | 
|  | * @deprecated - Do not use. | 
|  | */ | 
|  | @Deprecated | 
|  | public boolean canManageSubscription(Context context, String packageName) { | 
|  | List<UiccAccessRule> allAccessRules = getAllAccessRules(); | 
|  | if (allAccessRules == null) { | 
|  | return false; | 
|  | } | 
|  | PackageManager packageManager = context.getPackageManager(); | 
|  | PackageInfo packageInfo; | 
|  | try { | 
|  | packageInfo = packageManager.getPackageInfo(packageName, | 
|  | PackageManager.GET_SIGNING_CERTIFICATES); | 
|  | } catch (PackageManager.NameNotFoundException e) { | 
|  | Log.d("SubscriptionInfo", "canManageSubscription: Unknown package: " + packageName, e); | 
|  | return false; | 
|  | } | 
|  | for (UiccAccessRule rule : allAccessRules) { | 
|  | if (rule.getCarrierPrivilegeStatus(packageInfo) | 
|  | == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the {@link UiccAccessRule}s that are stored in Uicc, dictating who | 
|  | * is authorized to manage this subscription. | 
|  | * TODO and fix it properly in R / master: either deprecate this and have 3 APIs | 
|  | *  native + carrier + all, or have this return all by default. | 
|  | * @hide | 
|  | */ | 
|  | @SystemApi | 
|  | public @Nullable List<UiccAccessRule> getAccessRules() { | 
|  | if (mNativeAccessRules == null) return null; | 
|  | return Arrays.asList(mNativeAccessRules); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return the {@link UiccAccessRule}s that are both stored on Uicc and in carrierConfigs | 
|  | * dictating who is authorized to manage this subscription. | 
|  | * @hide | 
|  | */ | 
|  | public @Nullable List<UiccAccessRule> getAllAccessRules() { | 
|  | List<UiccAccessRule> merged = new ArrayList<>(); | 
|  | if (mNativeAccessRules != null) { | 
|  | merged.addAll(getAccessRules()); | 
|  | } | 
|  | if (mCarrierConfigAccessRules != null) { | 
|  | merged.addAll(Arrays.asList(mCarrierConfigAccessRules)); | 
|  | } | 
|  | return merged.isEmpty() ? null : merged; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the card string of the SIM card which contains the subscription. | 
|  | * | 
|  | * Starting with API level 29 Security Patch 2021-04-05, returns the card string if the calling | 
|  | * app has been granted the READ_PRIVILEGED_PHONE_STATE permission, has carrier privileges (see | 
|  | * {@link TelephonyManager#hasCarrierPrivileges}), or is a device owner or profile owner that | 
|  | * has been granted the READ_PHONE_STATE permission. The profile owner is an app that owns a | 
|  | * managed profile on the device; for more details see <a | 
|  | * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile | 
|  | * owner access is deprecated and will be removed in a future release. | 
|  | * | 
|  | * @return the card string of the SIM card which contains the subscription or an empty string | 
|  | * if these requirements are not met. The card string is the ICCID for UICCs or the EID for | 
|  | * eUICCs. | 
|  | * @hide | 
|  | * //TODO rename usages in LPA: UiccSlotUtil.java, UiccSlotsManager.java, UiccSlotInfoTest.java | 
|  | */ | 
|  | public String getCardString() { | 
|  | return this.mCardString; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @hide | 
|  | */ | 
|  | public void clearCardString() { | 
|  | this.mCardString = ""; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the card ID of the SIM card which contains the subscription (see | 
|  | * {@link UiccCardInfo#getCardId()}. | 
|  | * @return the cardId | 
|  | */ | 
|  | public int getCardId() { | 
|  | return this.mCardId; | 
|  | } | 
|  | /** | 
|  | * Returns the port index of the SIM card which contains the subscription. | 
|  | * | 
|  | * @return the portIndex | 
|  | */ | 
|  | public int getPortIndex() { | 
|  | return this.mPortIndex; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Set whether the subscription's group is disabled. | 
|  | * @hide | 
|  | */ | 
|  | public void setGroupDisabled(boolean isGroupDisabled) { | 
|  | this.mIsGroupDisabled = isGroupDisabled; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Return whether the subscription's group is disabled. | 
|  | * @hide | 
|  | */ | 
|  | @SystemApi | 
|  | public boolean isGroupDisabled() { | 
|  | return mIsGroupDisabled; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Return whether uicc applications are set to be enabled or disabled. | 
|  | * @hide | 
|  | */ | 
|  | @SystemApi | 
|  | public boolean areUiccApplicationsEnabled() { | 
|  | return mAreUiccApplicationsEnabled; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Get the usage setting for this subscription. | 
|  | * | 
|  | * @return the usage setting used for this subscription. | 
|  | */ | 
|  | public @UsageSetting int getUsageSetting() { | 
|  | return mUsageSetting; | 
|  | } | 
|  |  | 
|  | public static final @android.annotation.NonNull | 
|  | Parcelable.Creator<SubscriptionInfo> CREATOR = | 
|  | new Parcelable.Creator<SubscriptionInfo>() { | 
|  | @Override | 
|  | public SubscriptionInfo createFromParcel(Parcel source) { | 
|  | int id = source.readInt(); | 
|  | String iccId = source.readString(); | 
|  | int simSlotIndex = source.readInt(); | 
|  | CharSequence displayName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); | 
|  | CharSequence carrierName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); | 
|  | int nameSource = source.readInt(); | 
|  | int iconTint = source.readInt(); | 
|  | String number = source.readString(); | 
|  | int dataRoaming = source.readInt(); | 
|  | String mcc = source.readString(); | 
|  | String mnc = source.readString(); | 
|  | String countryIso = source.readString(); | 
|  | boolean isEmbedded = source.readBoolean(); | 
|  | UiccAccessRule[] nativeAccessRules = source.createTypedArray(UiccAccessRule.CREATOR); | 
|  | String cardString = source.readString(); | 
|  | int cardId = source.readInt(); | 
|  | int portId = source.readInt(); | 
|  | boolean isOpportunistic = source.readBoolean(); | 
|  | String groupUUID = source.readString(); | 
|  | boolean isGroupDisabled = source.readBoolean(); | 
|  | int carrierid = source.readInt(); | 
|  | int profileClass = source.readInt(); | 
|  | int subType = source.readInt(); | 
|  | String[] ehplmns = source.createStringArray(); | 
|  | String[] hplmns = source.createStringArray(); | 
|  | String groupOwner = source.readString(); | 
|  | UiccAccessRule[] carrierConfigAccessRules = source.createTypedArray( | 
|  | UiccAccessRule.CREATOR); | 
|  | boolean areUiccApplicationsEnabled = source.readBoolean(); | 
|  | int usageSetting = source.readInt(); | 
|  |  | 
|  | SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName, | 
|  | carrierName, nameSource, iconTint, number, dataRoaming, /* icon= */ null, | 
|  | mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, cardId, | 
|  | isOpportunistic, groupUUID, isGroupDisabled, carrierid, profileClass, subType, | 
|  | groupOwner, carrierConfigAccessRules, areUiccApplicationsEnabled, | 
|  | portId, usageSetting); | 
|  | info.setAssociatedPlmns(ehplmns, hplmns); | 
|  | return info; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public SubscriptionInfo[] newArray(int size) { | 
|  | return new SubscriptionInfo[size]; | 
|  | } | 
|  | }; | 
|  |  | 
|  | @Override | 
|  | public void writeToParcel(Parcel dest, int flags) { | 
|  | dest.writeInt(mId); | 
|  | dest.writeString(mIccId); | 
|  | dest.writeInt(mSimSlotIndex); | 
|  | TextUtils.writeToParcel(mDisplayName, dest, 0); | 
|  | TextUtils.writeToParcel(mCarrierName, dest, 0); | 
|  | dest.writeInt(mNameSource); | 
|  | dest.writeInt(mIconTint); | 
|  | dest.writeString(mNumber); | 
|  | dest.writeInt(mDataRoaming); | 
|  | dest.writeString(mMcc); | 
|  | dest.writeString(mMnc); | 
|  | dest.writeString(mCountryIso); | 
|  | // Do not write mIconBitmap since it should be lazily loaded on first usage | 
|  | dest.writeBoolean(mIsEmbedded); | 
|  | dest.writeTypedArray(mNativeAccessRules, flags); | 
|  | dest.writeString(mCardString); | 
|  | dest.writeInt(mCardId); | 
|  | dest.writeInt(mPortIndex); | 
|  | dest.writeBoolean(mIsOpportunistic); | 
|  | dest.writeString(mGroupUUID == null ? null : mGroupUUID.toString()); | 
|  | dest.writeBoolean(mIsGroupDisabled); | 
|  | dest.writeInt(mCarrierId); | 
|  | dest.writeInt(mProfileClass); | 
|  | dest.writeInt(mSubscriptionType); | 
|  | dest.writeStringArray(mEhplmns); | 
|  | dest.writeStringArray(mHplmns); | 
|  | dest.writeString(mGroupOwner); | 
|  | dest.writeTypedArray(mCarrierConfigAccessRules, flags); | 
|  | dest.writeBoolean(mAreUiccApplicationsEnabled); | 
|  | dest.writeInt(mUsageSetting); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public int describeContents() { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @hide | 
|  | */ | 
|  | public static String givePrintableIccid(String iccId) { | 
|  | String iccIdToPrint = null; | 
|  | if (iccId != null) { | 
|  | if (iccId.length() > 9 && !TelephonyUtils.IS_DEBUGGABLE) { | 
|  | iccIdToPrint = iccId.substring(0, 9) + Rlog.pii(false, iccId.substring(9)); | 
|  | } else { | 
|  | iccIdToPrint = iccId; | 
|  | } | 
|  | } | 
|  | return iccIdToPrint; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String toString() { | 
|  | String iccIdToPrint = givePrintableIccid(mIccId); | 
|  | String cardStringToPrint = givePrintableIccid(mCardString); | 
|  | return "{id=" + mId + " iccId=" + iccIdToPrint + " simSlotIndex=" + mSimSlotIndex | 
|  | + " carrierId=" + mCarrierId + " displayName=" + mDisplayName | 
|  | + " carrierName=" + mCarrierName + " nameSource=" + mNameSource | 
|  | + " iconTint=" + mIconTint | 
|  | + " number=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mNumber) | 
|  | + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc=" + mMcc | 
|  | + " mnc=" + mMnc + " countryIso=" + mCountryIso + " isEmbedded=" + mIsEmbedded | 
|  | + " nativeAccessRules=" + Arrays.toString(mNativeAccessRules) | 
|  | + " cardString=" + cardStringToPrint + " cardId=" + mCardId | 
|  | + " portIndex=" + mPortIndex | 
|  | + " isOpportunistic=" + mIsOpportunistic + " groupUUID=" + mGroupUUID | 
|  | + " isGroupDisabled=" + mIsGroupDisabled | 
|  | + " profileClass=" + mProfileClass | 
|  | + " ehplmns=" + Arrays.toString(mEhplmns) | 
|  | + " hplmns=" + Arrays.toString(mHplmns) | 
|  | + " subscriptionType=" + mSubscriptionType | 
|  | + " groupOwner=" + mGroupOwner | 
|  | + " carrierConfigAccessRules=" + Arrays.toString(mCarrierConfigAccessRules) | 
|  | + " areUiccApplicationsEnabled=" + mAreUiccApplicationsEnabled | 
|  | + " usageSetting=" + mUsageSetting + "}"; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public int hashCode() { | 
|  | return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded, | 
|  | mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc, mCountryIso, mCardString, | 
|  | mCardId, mDisplayName, mCarrierName, mNativeAccessRules, mIsGroupDisabled, | 
|  | mCarrierId, mProfileClass, mGroupOwner, mAreUiccApplicationsEnabled, mPortIndex, | 
|  | mUsageSetting); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean equals(Object obj) { | 
|  | if (obj == null) return false; | 
|  | if (obj == this) return true; | 
|  |  | 
|  | SubscriptionInfo toCompare; | 
|  | try { | 
|  | toCompare = (SubscriptionInfo) obj; | 
|  | } catch (ClassCastException ex) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return mId == toCompare.mId | 
|  | && mSimSlotIndex == toCompare.mSimSlotIndex | 
|  | && mNameSource == toCompare.mNameSource | 
|  | && mIconTint == toCompare.mIconTint | 
|  | && mDataRoaming == toCompare.mDataRoaming | 
|  | && mIsEmbedded == toCompare.mIsEmbedded | 
|  | && mIsOpportunistic == toCompare.mIsOpportunistic | 
|  | && mIsGroupDisabled == toCompare.mIsGroupDisabled | 
|  | && mAreUiccApplicationsEnabled == toCompare.mAreUiccApplicationsEnabled | 
|  | && mCarrierId == toCompare.mCarrierId | 
|  | && Objects.equals(mGroupUUID, toCompare.mGroupUUID) | 
|  | && Objects.equals(mIccId, toCompare.mIccId) | 
|  | && Objects.equals(mNumber, toCompare.mNumber) | 
|  | && Objects.equals(mMcc, toCompare.mMcc) | 
|  | && Objects.equals(mMnc, toCompare.mMnc) | 
|  | && Objects.equals(mCountryIso, toCompare.mCountryIso) | 
|  | && Objects.equals(mCardString, toCompare.mCardString) | 
|  | && Objects.equals(mCardId, toCompare.mCardId) | 
|  | && mPortIndex == toCompare.mPortIndex | 
|  | && Objects.equals(mGroupOwner, toCompare.mGroupOwner) | 
|  | && TextUtils.equals(mDisplayName, toCompare.mDisplayName) | 
|  | && TextUtils.equals(mCarrierName, toCompare.mCarrierName) | 
|  | && Arrays.equals(mNativeAccessRules, toCompare.mNativeAccessRules) | 
|  | && mProfileClass == toCompare.mProfileClass | 
|  | && Arrays.equals(mEhplmns, toCompare.mEhplmns) | 
|  | && Arrays.equals(mHplmns, toCompare.mHplmns) | 
|  | && mUsageSetting == toCompare.mUsageSetting; | 
|  | } | 
|  | } |