From d02731ffff9b8eb9b604377f50b2c43a9c753c2e Mon Sep 17 00:00:00 2001 From: Jeff Davidson Date: Sun, 9 Apr 2017 14:31:09 -0700 Subject: [PATCH] Define APIs for listing embedded subscriptions. Two new APIs will list all embedded subscriptions along with any active ones. One API requires the ability to read phone state and returns all subscriptions. The other requires no special permissions but will only return those subscriptions which the caller may manage according to their metadata. A list result from the LPA includes whether the current eUICC is removable. If true, subscriptions in the list are considered transient and always removed upon the next list update (i.e. SIM card state change) unless that update includes the subscription. Otherwise, they will be retained across future list operations for which the current eUICC is removable. This allows callers to retain knowledge about available embedded subscriptions on an inactive but still accessible eUICC, as long as that eUICC is permanent. The LPA may request a refresh of the list at any time; this is intended to be used of the list or metadata is updated through a non-API operation, e.g. a server-initiated metadata update. For operations driven through a platform API, the list will be refreshed automatically. Bug: 33075886 Test: TreeHugger Change-Id: I1887cbca835c304b9eb285fd972c7c8eaffa6e1d --- Android.mk | 2 + .../service/euicc/EuiccProfileInfo.java | 84 +++++++++++ .../android/service/euicc/EuiccService.java | 22 +++ .../euicc/GetEuiccProfileInfoListResult.aidl | 19 +++ .../euicc/GetEuiccProfileInfoListResult.java | 128 ++++++++++++++++ .../android/service/euicc/IEuiccService.aidl | 2 + .../IGetEuiccProfileInfoListCallback.aidl | 24 +++ .../android/telephony/SubscriptionInfo.java | 113 +++++++++++++- .../telephony/SubscriptionManager.java | 141 +++++++++++++++++- .../android/telephony/UiccAccessRule.java | 22 ++- .../com/android/internal/telephony/ISub.aidl | 15 ++ 11 files changed, 561 insertions(+), 11 deletions(-) create mode 100644 core/java/android/service/euicc/EuiccProfileInfo.java create mode 100644 core/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl create mode 100644 core/java/android/service/euicc/GetEuiccProfileInfoListResult.java create mode 100644 core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl diff --git a/Android.mk b/Android.mk index 28abb89690798..a4d1107286b3d 100644 --- a/Android.mk +++ b/Android.mk @@ -287,6 +287,7 @@ LOCAL_SRC_FILES += \ core/java/android/service/euicc/IEuiccService.aidl \ core/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl \ core/java/android/service/euicc/IGetEidCallback.aidl \ + core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl \ core/java/android/service/gatekeeper/IGateKeeperService.aidl \ core/java/android/service/notification/INotificationListener.aidl \ core/java/android/service/notification/IStatusBarNotificationHolder.aidl \ @@ -754,6 +755,7 @@ aidl_files := \ frameworks/base/core/java/android/service/carrier/MessagePdu.aidl \ frameworks/base/core/java/android/service/euicc/DownloadResult.aidl \ frameworks/base/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl \ + frameworks/base/core/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl \ frameworks/base/core/java/android/service/notification/Adjustment.aidl \ frameworks/base/core/java/android/service/notification/Condition.aidl \ frameworks/base/core/java/android/service/notification/SnoozeCriterion.aidl \ diff --git a/core/java/android/service/euicc/EuiccProfileInfo.java b/core/java/android/service/euicc/EuiccProfileInfo.java new file mode 100644 index 0000000000000..ba6c9a2d1b572 --- /dev/null +++ b/core/java/android/service/euicc/EuiccProfileInfo.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2017 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.service.euicc; + +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.UiccAccessRule; +import android.text.TextUtils; + +/** + * Information about an embedded profile (subscription) on an eUICC. + * + * @hide + * + * TODO(b/35851809): Make this a SystemApi. + */ +public final class EuiccProfileInfo implements Parcelable { + + /** The iccid of the subscription. */ + public final String iccid; + + /** + * Optional access rules defining which apps can manage this subscription. If unset, only the + * platform can manage it. + */ + public final @Nullable UiccAccessRule[] accessRules; + + /** An optional nickname for the subscription. */ + public final @Nullable String nickname; + + public static final Creator CREATOR = new Creator() { + @Override + public EuiccProfileInfo createFromParcel(Parcel in) { + return new EuiccProfileInfo(in); + } + + @Override + public EuiccProfileInfo[] newArray(int size) { + return new EuiccProfileInfo[size]; + } + }; + + public EuiccProfileInfo(String iccid, @Nullable UiccAccessRule[] accessRules, + @Nullable String nickname) { + if (!TextUtils.isDigitsOnly(iccid)) { + throw new IllegalArgumentException("iccid contains invalid characters: " + iccid); + } + this.iccid = iccid; + this.accessRules = accessRules; + this.nickname = nickname; + } + + private EuiccProfileInfo(Parcel in) { + iccid = in.readString(); + accessRules = in.createTypedArray(UiccAccessRule.CREATOR); + nickname = in.readString(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(iccid); + dest.writeTypedArray(accessRules, flags); + dest.writeString(nickname); + } + + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java index 03aa967f9611b..917cf7e588877 100644 --- a/core/java/android/service/euicc/EuiccService.java +++ b/core/java/android/service/euicc/EuiccService.java @@ -164,6 +164,17 @@ public abstract class EuiccService extends Service { DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim); + /** + * Return a list of all @link EuiccProfileInfo}s. + * + * @param slotId ID of the SIM slot to use when starting the download. This is currently not + * populated but is here to future-proof the APIs. + * @return The result of the operation. + * @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList + * @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList + */ + public abstract GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int slotId); + /** * Wrapper around IEuiccService that forwards calls to implementations of {@link EuiccService}. */ @@ -205,5 +216,16 @@ public abstract class EuiccService extends Service { // Can't communicate with the phone process; ignore. } } + + @Override + public void getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback) { + GetEuiccProfileInfoListResult result = + EuiccService.this.onGetEuiccProfileInfoList(slotId); + try { + callback.onComplete(result); + } catch (RemoteException e) { + // Can't communicate with the phone process; ignore. + } + } } } diff --git a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl new file mode 100644 index 0000000000000..6003b79462da1 --- /dev/null +++ b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2017 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.service.euicc; + +parcelable GetEuiccProfileInfoListResult; diff --git a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java new file mode 100644 index 0000000000000..5ac10fef3c233 --- /dev/null +++ b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2017 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.service.euicc; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Result of a {@link EuiccService#onGetEuiccProfileInfoList} operation. + * @hide + * + * TODO(b/35851809): Make this a SystemApi. + */ +public final class GetEuiccProfileInfoListResult implements Parcelable { + + public static final Creator CREATOR = + new Creator() { + @Override + public GetEuiccProfileInfoListResult createFromParcel(Parcel in) { + return new GetEuiccProfileInfoListResult(in); + } + + @Override + public GetEuiccProfileInfoListResult[] newArray(int size) { + return new GetEuiccProfileInfoListResult[size]; + } + }; + + /** @hide */ + @IntDef({ + RESULT_OK, + RESULT_GENERIC_ERROR, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ResultCode {} + + public static final int RESULT_OK = 0; + public static final int RESULT_GENERIC_ERROR = 1; + + /** Result of the operation - one of the RESULT_* constants. */ + public final @ResultCode int result; + + /** Implementation-defined detailed error code in case of a failure not covered here. */ + public final int detailedCode; + + /** The profile list (only upon success). */ + @Nullable + public final EuiccProfileInfo[] profiles; + + /** Whether the eUICC is removable. */ + public final boolean isRemovable; + + private GetEuiccProfileInfoListResult(int result, int detailedCode, EuiccProfileInfo[] profiles, + boolean isRemovable) { + this.result = result; + this.detailedCode = detailedCode; + this.profiles = profiles; + this.isRemovable = isRemovable; + } + + private GetEuiccProfileInfoListResult(Parcel in) { + this.result = in.readInt(); + this.detailedCode = in.readInt(); + this.profiles = in.createTypedArray(EuiccProfileInfo.CREATOR); + this.isRemovable = in.readBoolean(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(result); + dest.writeInt(detailedCode); + dest.writeTypedArray(profiles, flags); + dest.writeBoolean(isRemovable); + } + + /** + * Return a result indicating that the listing was successful. + * + * @param profiles the list of profiles + * @param isRemovable whether the eUICC in this slot is removable. If true, the profiles + * returned here will only be considered accessible as long as this eUICC is present. + * Otherwise, they will remain accessible until the next time a response with isRemovable + * set to false is returned. + */ + public static GetEuiccProfileInfoListResult success( + EuiccProfileInfo[] profiles, boolean isRemovable) { + return new GetEuiccProfileInfoListResult( + RESULT_OK, 0 /* detailedCode */, profiles, isRemovable); + } + + /** + * Return a result indicating that an error occurred for which no other more specific error + * code has been defined. + * + * @param detailedCode an implementation-defined detailed error code for debugging purposes. + * @param isRemovable whether the eUICC in this slot is removable. If true, only removable + * profiles will be made inaccessible. Otherwise, all embedded profiles will be + * considered inaccessible. + */ + public static GetEuiccProfileInfoListResult genericError( + int detailedCode, boolean isRemovable) { + return new GetEuiccProfileInfoListResult( + RESULT_GENERIC_ERROR, detailedCode, null /* profiles */, isRemovable); + } + + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/service/euicc/IEuiccService.aidl b/core/java/android/service/euicc/IEuiccService.aidl index 3658d9a357beb..502fc844977ed 100644 --- a/core/java/android/service/euicc/IEuiccService.aidl +++ b/core/java/android/service/euicc/IEuiccService.aidl @@ -19,6 +19,7 @@ package android.service.euicc; import android.service.euicc.IDownloadSubscriptionCallback; import android.service.euicc.IGetDownloadableSubscriptionMetadataCallback; import android.service.euicc.IGetEidCallback; +import android.service.euicc.IGetEuiccProfileInfoListCallback; import android.telephony.euicc.DownloadableSubscription; /** @hide */ @@ -29,4 +30,5 @@ oneway interface IEuiccService { void getDownloadableSubscriptionMetadata(int slotId, in DownloadableSubscription subscription, boolean forceDeactivateSim, in IGetDownloadableSubscriptionMetadataCallback callback); void getEid(int slotId, in IGetEidCallback callback); + void getEuiccProfileInfoList(int slotId, in IGetEuiccProfileInfoListCallback callback); } \ No newline at end of file diff --git a/core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl b/core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl new file mode 100644 index 0000000000000..761ec1f01324c --- /dev/null +++ b/core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2017 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.service.euicc; + +import android.service.euicc.GetEuiccProfileInfoListResult; + +/** @hide */ +oneway interface IGetEuiccProfileInfoListCallback { + void onComplete(in GetEuiccProfileInfoListResult result); +} \ No newline at end of file diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index cf2d27e287090..4e1c15fa12516 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -16,7 +16,10 @@ package android.telephony; +import android.annotation.Nullable; 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; @@ -30,6 +33,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.DisplayMetrics; +import java.util.Arrays; + /** * A Parcelable class for Subscription Information. */ @@ -109,12 +114,35 @@ public class SubscriptionInfo implements Parcelable { */ 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. + */ + @Nullable + private UiccAccessRule[] mAccessRules; + /** * @hide */ public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, Bitmap icon, int mcc, int mnc, String countryIso) { + this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number, + roaming, icon, mcc, mnc, countryIso, false /* isEmbedded */, + null /* accessRules */); + } + + /** + * @hide + */ + public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, + CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, + Bitmap icon, int mcc, int mnc, String countryIso, boolean isEmbedded, + @Nullable UiccAccessRule[] accessRules) { this.mId = id; this.mIccId = iccId; this.mSimSlotIndex = simSlotIndex; @@ -128,6 +156,8 @@ public class SubscriptionInfo implements Parcelable { this.mMcc = mcc; this.mMnc = mnc; this.mCountryIso = countryIso; + this.mIsEmbedded = isEmbedded; + this.mAccessRules = accessRules; } /** @@ -284,6 +314,79 @@ public class SubscriptionInfo implements Parcelable { return this.mCountryIso; } + /** + * @return whether the subscription is an embedded one. + * @hide + * + * TODO(b/35851809): Make this public. + */ + public boolean isEmbedded() { + return this.mIsEmbedded; + } + + /** + * 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. + * @throws UnsupportedOperationException if this subscription is not embedded. + * @hide + * + * TODO(b/35851809): Make this public. + */ + 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. + * @throws UnsupportedOperationException if this subscription is not embedded. + * @hide + */ + public boolean canManageSubscription(Context context, String packageName) { + if (!isEmbedded()) { + throw new UnsupportedOperationException("Not an embedded subscription"); + } + if (mAccessRules == null) { + return false; + } + PackageManager packageManager = context.getPackageManager(); + PackageInfo packageInfo; + try { + packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + } catch (PackageManager.NameNotFoundException e) { + throw new IllegalArgumentException("Unknown package: " + packageName, e); + } + for (UiccAccessRule rule : mAccessRules) { + if (rule.getCarrierPrivilegeStatus(packageInfo) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { + return true; + } + } + return false; + } + + /** + * @return the {@link UiccAccessRule}s dictating who is authorized to manage this subscription. + * @throws UnsupportedOperationException if this subscription is not embedded. + * @hide + * + * TODO(b/35851809): Make this a SystemApi. + */ + public @Nullable UiccAccessRule[] getAccessRules() { + if (!isEmbedded()) { + throw new UnsupportedOperationException("Not an embedded subscription"); + } + return mAccessRules; + } + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public SubscriptionInfo createFromParcel(Parcel source) { @@ -300,9 +403,12 @@ public class SubscriptionInfo implements Parcelable { int mnc = source.readInt(); String countryIso = source.readString(); Bitmap iconBitmap = Bitmap.CREATOR.createFromParcel(source); + boolean isEmbedded = source.readBoolean(); + UiccAccessRule[] accessRules = source.createTypedArray(UiccAccessRule.CREATOR); return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName, - nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso); + nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso, + isEmbedded, accessRules); } @Override @@ -326,6 +432,8 @@ public class SubscriptionInfo implements Parcelable { dest.writeInt(mMnc); dest.writeString(mCountryIso); mIconBitmap.writeToParcel(dest, flags); + dest.writeBoolean(mIsEmbedded); + dest.writeTypedArray(mAccessRules, flags); } @Override @@ -355,6 +463,7 @@ public class SubscriptionInfo implements Parcelable { + " displayName=" + mDisplayName + " carrierName=" + mCarrierName + " nameSource=" + mNameSource + " iconTint=" + mIconTint + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc - + " mnc " + mMnc + "}"; + + " mnc " + mMnc + " isEmbedded " + mIsEmbedded + + " accessRules " + Arrays.toString(mAccessRules) + "}"; } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 7f616ad6fb080..77525ff500401 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -24,17 +24,17 @@ import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.net.Uri; -import android.telephony.Rlog; import android.os.Handler; import android.os.Message; -import android.os.ServiceManager; import android.os.RemoteException; +import android.os.ServiceManager; import android.util.DisplayMetrics; -import com.android.internal.telephony.ISub; import com.android.internal.telephony.IOnSubscriptionsChangedListener; +import com.android.internal.telephony.ISub; import com.android.internal.telephony.ITelephonyRegistry; import com.android.internal.telephony.PhoneConstants; + import java.util.ArrayList; import java.util.List; @@ -45,7 +45,8 @@ import java.util.List; * You do not instantiate this class directly; instead, you retrieve * a reference to an instance through {@link #from}. *

- * All SDK public methods require android.Manifest.permission.READ_PHONE_STATE. + * All SDK public methods require android.Manifest.permission.READ_PHONE_STATE unless otherwise + * specified. */ public class SubscriptionManager { private static final String LOG_TAG = "SubscriptionManager"; @@ -259,6 +260,32 @@ public class SubscriptionManager { */ public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status"; + /** + * TelephonyProvider column name for whether a subscription is embedded (that is, present on an + * eSIM). + *

Type: INTEGER (int), 1 for embedded or 0 for non-embedded. + * @hide + */ + public static final String IS_EMBEDDED = "is_embedded"; + + /** + * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from + * {@link UiccAccessRule#encodeRules}. Only present if {@link #IS_EMBEDDED} is 1. + *

TYPE: BLOB + * @hide + */ + public static final String ACCESS_RULES = "access_rules"; + + /** + * TelephonyProvider column name identifying whether an embedded subscription is on a removable + * card. Such subscriptions are marked inaccessible as soon as the current card is removed. + * Otherwise, they will remain accessible unless explicitly deleted. Only present if + * {@link #IS_EMBEDDED} is 1. + *

TYPE: INTEGER (int), 1 for removable or 0 for non-removable. + * @hide + */ + public static final String IS_REMOVABLE = "is_removable"; + /** * TelephonyProvider column name for extreme threat in CB settings * @hide @@ -632,6 +659,112 @@ public class SubscriptionManager { return result; } + /** + * Gets the SubscriptionInfo(s) of all available subscriptions, if any. + * + *

Available subscriptions include active ones (those with a non-negative + * {@link SubscriptionInfo#getSimSlotIndex()}) as well as inactive but installed embedded + * subscriptions. + * + *

The records will be sorted by {@link SubscriptionInfo#getSimSlotIndex} then by + * {@link SubscriptionInfo#getSubscriptionId}. + * + * @return Sorted list of the current {@link SubscriptionInfo} records available on the + * device. + *

    + *
  • + * If null is returned the current state is unknown but if a + * {@link OnSubscriptionsChangedListener} has been registered + * {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be invoked in the future. + *
  • + * If the list is empty then there are no {@link SubscriptionInfo} records currently available. + *
  • + * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex} + * then by {@link SubscriptionInfo#getSubscriptionId}. + *
+ * @hide + * + * TODO(b/35851809): Make this a SystemApi. + */ + public List getAvailableSubscriptionInfoList() { + List result = null; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.getAvailableSubscriptionInfoList(mContext.getOpPackageName()); + } + } catch (RemoteException ex) { + // ignore it + } + return result; + } + + /** + * Gets the SubscriptionInfo(s) of all embedded subscriptions accessible to the calling app, if + * any. + * + *

Only those subscriptions for which the calling app has carrier privileges per the + * subscription metadata, if any, will be included in the returned list. + * + *

The records will be sorted by {@link SubscriptionInfo#getSimSlotIndex} then by + * {@link SubscriptionInfo#getSubscriptionId}. + * + * @return Sorted list of the current embedded {@link SubscriptionInfo} records available on the + * device which are accessible to the caller. + *

    + *
  • + * If null is returned the current state is unknown but if a + * {@link OnSubscriptionsChangedListener} has been registered + * {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be invoked in the future. + *
  • + * If the list is empty then there are no {@link SubscriptionInfo} records currently available. + *
  • + * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex} + * then by {@link SubscriptionInfo#getSubscriptionId}. + *
+ * @hide + * + * TODO(b/35851809): Make this public. + */ + public List getAccessibleSubscriptionInfoList() { + List result = null; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.getAccessibleSubscriptionInfoList(mContext.getOpPackageName()); + } + } catch (RemoteException ex) { + // ignore it + } + return result; + } + + /** + * Request a refresh of the platform cache of profile information. + * + *

Should be called by the EuiccService implementation whenever this information changes due + * to an operation done outside the scope of a request initiated by the platform to the + * EuiccService. There is no need to refresh for downloads, deletes, or other operations that + * were made through the EuiccService. + * + *

Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. + * @hide + * + * TODO(b/35851809): Make this a SystemApi. + */ + public void requestEmbeddedSubscriptionInfoListRefresh() { + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + iSub.requestEmbeddedSubscriptionInfoListRefresh(); + } + } catch (RemoteException ex) { + // ignore it + } + } + /** * @return the count of all subscriptions in the database, this includes * all subscriptions that have been seen. diff --git a/telephony/java/android/telephony/UiccAccessRule.java b/telephony/java/android/telephony/UiccAccessRule.java index 1ac4c5cf7d801..e42a758350083 100644 --- a/telephony/java/android/telephony/UiccAccessRule.java +++ b/telephony/java/android/telephony/UiccAccessRule.java @@ -16,7 +16,6 @@ package android.telephony; import android.annotation.Nullable; -import android.annotation.SystemApi; import android.content.pm.PackageInfo; import android.content.pm.Signature; import android.os.Parcel; @@ -63,7 +62,11 @@ public final class UiccAccessRule implements Parcelable { * Encode these access rules as a byte array which can be parsed with {@link #decodeRules}. * @hide */ - public static byte[] encodeRules(UiccAccessRule[] accessRules) { + @Nullable + public static byte[] encodeRules(@Nullable UiccAccessRule[] accessRules) { + if (accessRules == null) { + return null; + } try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream output = new DataOutputStream(baos); @@ -72,7 +75,12 @@ public final class UiccAccessRule implements Parcelable { for (UiccAccessRule accessRule : accessRules) { output.writeInt(accessRule.mCertificateHash.length); output.write(accessRule.mCertificateHash); - output.writeUTF(accessRule.mPackageName); + if (accessRule.mPackageName != null) { + output.writeBoolean(true); + output.writeUTF(accessRule.mPackageName); + } else { + output.writeBoolean(false); + } output.writeLong(accessRule.mAccessType); } output.close(); @@ -87,7 +95,11 @@ public final class UiccAccessRule implements Parcelable { * Decodes a byte array generated with {@link #encodeRules}. * @hide */ - public static UiccAccessRule[] decodeRules(byte[] encodedRules) { + @Nullable + public static UiccAccessRule[] decodeRules(@Nullable byte[] encodedRules) { + if (encodedRules == null) { + return null; + } ByteArrayInputStream bais = new ByteArrayInputStream(encodedRules); try (DataInputStream input = new DataInputStream(bais)) { input.readInt(); // version; currently ignored @@ -97,7 +109,7 @@ public final class UiccAccessRule implements Parcelable { int certificateHashLength = input.readInt(); byte[] certificateHash = new byte[certificateHashLength]; input.readFully(certificateHash); - String packageName = input.readUTF(); + String packageName = input.readBoolean() ? input.readUTF() : null; long accessType = input.readLong(); accessRules[i] = new UiccAccessRule(certificateHash, packageName, accessType); } diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index 71f2c6b80927c..644ad49734dc4 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -93,6 +93,21 @@ interface ISub { */ int getActiveSubInfoCountMax(); + /** + * @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList + */ + List getAvailableSubscriptionInfoList(String callingPackage); + + /** + * @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList + */ + List getAccessibleSubscriptionInfoList(String callingPackage); + + /** + * @see android.telephony.SubscriptionManager#requestEmbeddedSubscriptionInfoListRefresh + */ + oneway void requestEmbeddedSubscriptionInfoListRefresh(); + /** * Add a new SubscriptionInfo to subinfo database if needed * @param iccId the IccId of the SIM card