TelephonyManager#hasCarrierPrivileges internally uses
SubscriptionManager#canManageSubscription to decide whether to grant
carrier privilege status to an app or not.
SubscriptionManager#canManageSubscription returns true if caller APK's
certificate matches with one of the mNativeAccessRules or
mCarrierConfigAccessRules. This over-grants carrier privilege status
to apps that only has mNativeAccessRules.
Carrier privilege status should
be granted to the caller APK only if it's certificate matches with one
of mCarrierConfigAccessRules.
Replaced SubscriptionManager#canManageSubscription with
PhoneInterfaceManager#hasCarrierConfigAccess which returns true only if
caller APK certificates matches with one of mCarrierConfigAccessRules of
the given subscription.
Bug: 226593252
Test: Manual Testing as explained in b/226593252#comment51
atest CtsTelephonyTestCases
Flashed build on raven-userdebug and performed basic
funtionality tests
Change-Id: I662064529d2a9348f395fe3b541366de8bc2fe7d
943 lines
33 KiB
Java
943 lines
33 KiB
Java
/*
|
|
* 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.NonNull;
|
|
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.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.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
|
|
*/
|
|
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;
|
|
|
|
/**
|
|
* 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.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;
|
|
}
|
|
|
|
/**
|
|
* @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) {
|
|
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
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
* @return mCarrierConfigAccessRules associated with this subscription.
|
|
*/
|
|
public @NonNull List<UiccAccessRule> getCarrierConfigAccessRules() {
|
|
return mCarrierConfigAccessRules == null ? Collections.emptyList() :
|
|
Arrays.asList(mCarrierConfigAccessRules);
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
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();
|
|
Bitmap iconBitmap = source.readParcelable(Bitmap.class.getClassLoader());
|
|
boolean isEmbedded = source.readBoolean();
|
|
UiccAccessRule[] nativeAccessRules = source.createTypedArray(UiccAccessRule.CREATOR);
|
|
String cardString = source.readString();
|
|
int cardId = 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();
|
|
|
|
SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName,
|
|
carrierName, nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc,
|
|
countryIso, isEmbedded, nativeAccessRules, cardString, cardId, isOpportunistic,
|
|
groupUUID, isGroupDisabled, carrierid, profileClass, subType, groupOwner,
|
|
carrierConfigAccessRules, areUiccApplicationsEnabled);
|
|
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);
|
|
dest.writeParcelable(mIconBitmap, flags);
|
|
dest.writeBoolean(mIsEmbedded);
|
|
dest.writeTypedArray(mNativeAccessRules, flags);
|
|
dest.writeString(mCardString);
|
|
dest.writeInt(mCardId);
|
|
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);
|
|
}
|
|
|
|
@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
|
|
+ " 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 + "}";
|
|
}
|
|
|
|
@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);
|
|
}
|
|
|
|
@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)
|
|
&& 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);
|
|
}
|
|
}
|