diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index a49a61b592ba3..b6ae53017f645 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -25,15 +25,20 @@ import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.app.Activity; import android.app.PendingIntent; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager; +import android.os.Build; import android.os.Bundle; import android.os.RemoteException; +import android.telephony.SubscriptionInfo; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; import android.telephony.euicc.EuiccCardManager.ResetOption; +import android.util.Log; import com.android.internal.telephony.euicc.IEuiccController; @@ -57,6 +62,7 @@ import java.util.stream.Collectors; */ @RequiresFeature(PackageManager.FEATURE_TELEPHONY_EUICC) public class EuiccManager { + private static final String TAG = "EuiccManager"; /** * Intent action to launch the embedded SIM (eUICC) management settings screen. @@ -811,6 +817,14 @@ public class EuiccManager { */ public static final int ERROR_INVALID_PORT = 10017; + /** + * Apps targeting on Android T and beyond will get exception whenever switchToSubscription + * without portIndex is called for disable subscription. + * @hide + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + public static final long SWITCH_WITHOUT_PORT_INDEX_EXCEPTION_ON_DISABLE = 218393363L; private final Context mContext; private int mCardId; @@ -1127,7 +1141,7 @@ public class EuiccManager { * intent to prompt the user to accept the download. The caller should also be authorized to * manage the subscription to be enabled. * - *

From Android T, devices might support MEP(Multiple Enabled Profile), the subscription + *

From Android T, devices might support MEP(Multiple Enabled Profiles), the subscription * can be installed on different port from the eUICC. Calling apps with carrier privilege * (see {@link TelephonyManager#hasCarrierPrivileges}) over the currently active subscriptions * can use {@link #switchToSubscription(int, int, PendingIntent)} to specify which port to @@ -1138,10 +1152,12 @@ public class EuiccManager { * * @param subscriptionId the ID of the subscription to enable. May be * {@link android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID} to deactivate the - * current profile without activating another profile to replace it. If it's a disable - * operation, requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} - * permission, or the calling app must be authorized to manage the active subscription on - * the target eUICC. + * current profile without activating another profile to replace it. Calling apps targeting + * on android T must use {@link #switchToSubscription(int, int, PendingIntent)} API for + * disable profile, port index can be found from {@link SubscriptionInfo#getPortIndex()}. + * If it's a disable operation, requires the + * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, or the + * calling app must be authorized to manage the active subscription on the target eUICC. * @param callbackIntent a PendingIntent to launch when the operation completes. */ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) @@ -1151,6 +1167,18 @@ public class EuiccManager { return; } try { + // TODO: Uncomment below compat change code once callers are ported to use + // switchToSubscription with portIndex for disable operation. + // if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID + // && getIEuiccController().isCompatChangeEnabled(mContext.getOpPackageName(), + // SWITCH_WITHOUT_PORT_INDEX_EXCEPTION_ON_DISABLE)) { + // // Apps targeting on Android T and beyond will get exception whenever + // // switchToSubscription without portIndex is called with INVALID_SUBSCRIPTION_ID. + // Log.e(TAG, "switchToSubscription without portIndex is not allowed for" + // + " disable operation"); + // throw new IllegalArgumentException("Must use switchToSubscription with portIndex" + // + " API for disable operation"); + // } getIEuiccController().switchToSubscription(mCardId, subscriptionId, mContext.getOpPackageName(), callbackIntent); } catch (RemoteException e) { @@ -1180,7 +1208,10 @@ public class EuiccManager { * current profile without activating another profile to replace it. If it's a disable * operation, requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} * permission, or the calling app must be authorized to manage the active subscription on - * the target eUICC. + * the target eUICC. From Android T, multiple enabled profiles is supported. Calling apps + * targeting on android T must use {@link #switchToSubscription(int, int, PendingIntent)} + * API for disable profile, port index can be found from + * {@link SubscriptionInfo#getPortIndex()}. * @param portIndex the index of the port to target for the enabled subscription * @param callbackIntent a PendingIntent to launch when the operation completes. */ @@ -1192,6 +1223,17 @@ public class EuiccManager { return; } try { + boolean canWriteEmbeddedSubscriptions = mContext.checkCallingOrSelfPermission( + Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) + == PackageManager.PERMISSION_GRANTED; + // If the caller is not privileged caller and does not have the carrier privilege over + // any active subscription, do not continue. + if (!canWriteEmbeddedSubscriptions && !getIEuiccController() + .hasCarrierPrivilegesForPackageOnAnyPhone(mContext.getOpPackageName())) { + Log.e(TAG, "Not permitted to use switchToSubscription with portIndex"); + throw new SecurityException( + "Must have carrier privileges to use switchToSubscription with portIndex"); + } getIEuiccController().switchToSubscriptionWithPort(mCardId, subscriptionId, portIndex, mContext.getOpPackageName(), callbackIntent); } catch (RemoteException e) { diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl index dda95b1595524..19f1a5b832fd6 100644 --- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl +++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl @@ -55,4 +55,6 @@ interface IEuiccController { List getSupportedCountries(boolean isSupported); boolean isSupportedCountry(String countryIso); boolean isSimPortAvailable(int cardId, int portIndex, String callingPackage); + boolean hasCarrierPrivilegesForPackageOnAnyPhone(String callingPackage); + boolean isCompatChangeEnabled(String callingPackage, long changeId); }