| /* |
| * 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.telephony.euicc; |
| |
| import android.Manifest; |
| import android.annotation.IntDef; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.annotation.RequiresPermission; |
| import android.annotation.SdkConstant; |
| import android.annotation.SystemApi; |
| import android.app.Activity; |
| import android.app.PendingIntent; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentSender; |
| import android.content.pm.PackageManager; |
| import android.os.Bundle; |
| import android.os.RemoteException; |
| import android.os.ServiceManager; |
| import android.telephony.TelephonyManager; |
| import android.telephony.euicc.EuiccCardManager.ResetOption; |
| |
| import com.android.internal.telephony.euicc.IEuiccController; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| |
| /** |
| * EuiccManager is the application interface to eUICCs, or eSIMs/embedded SIMs. |
| * |
| * <p>You do not instantiate this class directly; instead, you retrieve an instance through |
| * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}. This instance will be |
| * created using the default eUICC. |
| * |
| * <p>On a device with multiple eUICCs, you may want to create multiple EuiccManagers. To do this |
| * you can call {@link #createForCardId}. |
| * |
| * <p>See {@link #isEnabled} before attempting to use these APIs. |
| */ |
| public class EuiccManager { |
| |
| /** |
| * Intent action to launch the embedded SIM (eUICC) management settings screen. |
| * |
| * <p>This screen shows a list of embedded profiles and offers the user the ability to switch |
| * between them, download new profiles, and delete unused profiles. |
| * |
| * <p>The activity will immediately finish with {@link android.app.Activity#RESULT_CANCELED} if |
| * {@link #isEnabled} is false. |
| * |
| * This is ued by non-LPA app to bring up LUI. |
| */ |
| @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) |
| public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = |
| "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS"; |
| |
| /** |
| * Broadcast Action: The eUICC OTA status is changed. |
| * <p class="note"> |
| * Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. |
| * |
| * <p class="note">This is a protected intent that can only be sent |
| * by the system. |
| * |
| * @hide |
| */ |
| @SystemApi |
| @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) |
| @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) |
| public static final String ACTION_OTA_STATUS_CHANGED = |
| "android.telephony.euicc.action.OTA_STATUS_CHANGED"; |
| |
| /** |
| * Broadcast Action: The action sent to carrier app so it knows the carrier setup is not |
| * completed. |
| */ |
| @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) |
| public static final String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = |
| "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE"; |
| |
| /** |
| * Intent action to provision an embedded subscription. |
| * |
| * <p>May be called during device provisioning to launch a screen to perform embedded SIM |
| * provisioning, e.g. if no physical SIM is present and the user elects to configure their |
| * embedded SIM. |
| * |
| * <p>The activity will immediately finish with {@link android.app.Activity#RESULT_CANCELED} if |
| * {@link #isEnabled} is false. |
| * |
| * @hide |
| */ |
| @SystemApi |
| @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) |
| public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = |
| "android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION"; |
| |
| /** |
| * Intent action to handle a resolvable error. |
| * @hide |
| */ |
| public static final String ACTION_RESOLVE_ERROR = |
| "android.telephony.euicc.action.RESOLVE_ERROR"; |
| |
| /** |
| * Intent action sent by system apps (such as the Settings app) to the Telephony framework to |
| * enable or disable a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID} and |
| * {@link #EXTRA_ENABLE_SUBSCRIPTION}, and optionally {@link #EXTRA_FROM_SUBSCRIPTION_ID}. |
| * |
| * <p>Requires the caller to be a privileged process with the |
| * {@link android.permission#CALL_PRIVILEGED} permission for the intent to reach the Telephony |
| * stack. |
| * |
| * <p>Unlike {@link #switchToSubscription(int, PendingIntent)}, using this action allows the |
| * underlying eUICC service (i.e. the LPA app) to control the UI experience during this |
| * operation. The action is received by the Telephony framework, which in turn selects and |
| * launches an appropriate LPA activity to present UI to the user. For example, the activity may |
| * show a confirmation dialog, a progress dialog, or an error dialog when necessary. |
| * |
| * <p>The launched activity will immediately finish with |
| * {@link android.app.Activity#RESULT_CANCELED} if {@link #isEnabled} is false. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED = |
| "android.telephony.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED"; |
| |
| /** |
| * Intent action sent by system apps (such as the Settings app) to the Telephony framework to |
| * delete a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID}. |
| * |
| * <p>Requires the caller to be a privileged process with the |
| * {@link android.permission#CALL_PRIVILEGED} permission for the intent to reach the Telephony |
| * stack. |
| * |
| * <p>Unlike {@link #deleteSubscription(int, PendingIntent)}, using this action allows the |
| * underlying eUICC service (i.e. the LPA app) to control the UI experience during this |
| * operation. The action is received by the Telephony framework, which in turn selects and |
| * launches an appropriate LPA activity to present UI to the user. For example, the activity may |
| * show a confirmation dialog, a progress dialog, or an error dialog when necessary. |
| * |
| * <p>The launched activity will immediately finish with |
| * {@link android.app.Activity#RESULT_CANCELED} if {@link #isEnabled} is false. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED = |
| "android.telephony.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED"; |
| |
| /** |
| * Intent action sent by system apps (such as the Settings app) to the Telephony framework to |
| * rename a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID} and |
| * {@link #EXTRA_SUBSCRIPTION_NICKNAME}. |
| * |
| * <p>Requires the caller to be a privileged process with the |
| * {@link android.permission#CALL_PRIVILEGED} permission for the intent to reach the Telephony |
| * stack. |
| * |
| * <p>Unlike {@link #updateSubscriptionNickname(int, String, PendingIntent)}, using this action |
| * allows the the underlying eUICC service (i.e. the LPA app) to control the UI experience |
| * during this operation. The action is received by the Telephony framework, which in turn |
| * selects and launches an appropriate LPA activity to present UI to the user. For example, the |
| * activity may show a confirmation dialog, a progress dialog, or an error dialog when |
| * necessary. |
| * |
| * <p>The launched activity will immediately finish with |
| * {@link android.app.Activity#RESULT_CANCELED} if {@link #isEnabled} is false. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED = |
| "android.telephony.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED"; |
| |
| /** |
| * Result code for an operation indicating that the operation succeeded. |
| */ |
| public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0; |
| |
| /** |
| * Result code for an operation indicating that the user must take some action before the |
| * operation can continue. |
| * |
| * @see #startResolutionActivity |
| */ |
| public static final int EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR = 1; |
| |
| /** |
| * Result code for an operation indicating that an unresolvable error occurred. |
| * |
| * {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} will be populated with a detailed error |
| * code for logging/debugging purposes only. |
| */ |
| public static final int EMBEDDED_SUBSCRIPTION_RESULT_ERROR = 2; |
| |
| /** |
| * Key for an extra set on the {@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION} intent for which |
| * kind of activation flow will be evolved. (see {@code EUICC_ACTIVATION_}) |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String EXTRA_ACTIVATION_TYPE = |
| "android.telephony.euicc.extra.ACTIVATION_TYPE"; |
| |
| /** |
| * Key for an extra set on {@link PendingIntent} result callbacks providing a detailed result |
| * code. |
| * |
| * <p>This code is an implementation detail of the embedded subscription manager and is only |
| * intended for logging or debugging purposes. |
| */ |
| public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE = |
| "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE"; |
| |
| /** |
| * Key for an extra set on {@code #getDownloadableSubscriptionMetadata} PendingIntent result |
| * callbacks providing the downloadable subscription metadata. |
| */ |
| public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = |
| "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION"; |
| |
| /** |
| * Key for an extra set on {@link #getDefaultDownloadableSubscriptionList} PendingIntent result |
| * callbacks providing the list of available downloadable subscriptions. |
| * @hide |
| */ |
| @SystemApi |
| public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS = |
| "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS"; |
| |
| /** |
| * Key for an extra set on {@link PendingIntent} result callbacks providing the resolution |
| * pending intent for {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR}s. |
| * @hide |
| */ |
| public static final String EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT = |
| "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT"; |
| |
| /** |
| * Key for an extra set on the {@link #EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT} intent |
| * containing the EuiccService action to launch for resolution. |
| * @hide |
| */ |
| public static final String EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_ACTION = |
| "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_RESOLUTION_ACTION"; |
| |
| /** |
| * Key for an extra set on the {@link #EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT} intent |
| * providing the callback to execute after resolution is completed. |
| * @hide |
| */ |
| public static final String EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT = |
| "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT"; |
| |
| /** |
| * Key for an extra set on the {@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION} intent for |
| * whether eSIM provisioning flow is forced to be started or not. If this extra hasn't been |
| * set, eSIM provisioning flow may be skipped and the corresponding carrier's app will be |
| * notified. Otherwise, eSIM provisioning flow will be started when |
| * {@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION} has been received. |
| * @hide |
| */ |
| @SystemApi |
| public static final String EXTRA_FORCE_PROVISION = |
| "android.telephony.euicc.extra.FORCE_PROVISION"; |
| |
| /** |
| * Key for an extra set on privileged actions {@link #ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED}, |
| * {@link #ACTION_DELETE_SUBSCRIPTION_PRIVILEGED}, and |
| * {@link #ACTION_RENAME_SUBSCRIPTION_PRIVILEGED} providing the ID of the targeted subscription. |
| * |
| * <p>Expected type of the extra data: int |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String EXTRA_SUBSCRIPTION_ID = |
| "android.telephony.euicc.extra.SUBSCRIPTION_ID"; |
| |
| /** |
| * Key for an extra set on {@link #ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED} providing a boolean |
| * value of whether to enable or disable the targeted subscription. |
| * |
| * <p>Expected type of the extra data: boolean |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String EXTRA_ENABLE_SUBSCRIPTION = |
| "android.telephony.euicc.extra.ENABLE_SUBSCRIPTION"; |
| |
| /** |
| * Key for an extra set on {@link #ACTION_RENAME_SUBSCRIPTION_PRIVILEGED} providing a new |
| * nickname for the targeted subscription. |
| * |
| * <p>Expected type of the extra data: String |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String EXTRA_SUBSCRIPTION_NICKNAME = |
| "android.telephony.euicc.extra.SUBSCRIPTION_NICKNAME"; |
| |
| /** |
| * Key for an extra set on {@link #ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED} providing the ID of |
| * the subscription we're toggling from. This extra is optional and is only used for UI |
| * purposes by the underlying eUICC service (i.e. the LPA app), such as displaying a dialog |
| * titled "Switch X with Y". If set, the provided subscription will be used as the "from" |
| * subscription in UI (the "X" in the dialog example). Otherwise, the currently active |
| * subscription that will be disabled is the "from" subscription. |
| * |
| * <p>Expected type of the extra data: int |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String EXTRA_FROM_SUBSCRIPTION_ID = |
| "android.telephony.euicc.extra.FROM_SUBSCRIPTION_ID"; |
| |
| /** |
| * Key for an extra set on privileged actions {@link #ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED} |
| * providing the physical slot ID of the target slot. |
| * |
| * <p>Expected type of the extra data: int |
| * |
| * @hide |
| */ |
| // TODO: Make this a @SystemApi. |
| public static final String EXTRA_PHYSICAL_SLOT_ID = |
| "android.telephony.euicc.extra.PHYSICAL_SLOT_ID"; |
| |
| /** |
| * Optional meta-data attribute for a carrier app providing an icon to use to represent the |
| * carrier. If not provided, the app's launcher icon will be used as a fallback. |
| */ |
| public static final String META_DATA_CARRIER_ICON = "android.telephony.euicc.carriericon"; |
| |
| /** |
| * Euicc activation type which will be included in {@link #EXTRA_ACTIVATION_TYPE} and used to |
| * decide which kind of activation flow should be lauched. |
| * |
| * @hide |
| */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef(prefix = {"EUICC_ACTIVATION_"}, value = { |
| EUICC_ACTIVATION_TYPE_DEFAULT, |
| EUICC_ACTIVATION_TYPE_BACKUP, |
| EUICC_ACTIVATION_TYPE_TRANSFER, |
| EUICC_ACTIVATION_TYPE_ACCOUNT_REQUIRED, |
| }) |
| public @interface EuiccActivationType{} |
| |
| |
| /** |
| * The default euicc activation type which includes checking server side and downloading the |
| * profile based on carrier's download configuration. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final int EUICC_ACTIVATION_TYPE_DEFAULT = 1; |
| |
| /** |
| * The euicc activation type used when the default download process failed. LPA will start the |
| * backup flow and try to download the profile for the carrier. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final int EUICC_ACTIVATION_TYPE_BACKUP = 2; |
| |
| /** |
| * The activation flow of eSIM seamless transfer will be used. LPA will start normal eSIM |
| * activation flow and if it's failed, the name of the carrier selected will be recorded. After |
| * the future device pairing, LPA will contact this carrier to transfer it from the other device |
| * to this device. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final int EUICC_ACTIVATION_TYPE_TRANSFER = 3; |
| |
| /** |
| * The activation flow of eSIM requiring user account will be started. This can only be used |
| * when there is user account signed in. Otherwise, the flow will be failed. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final int EUICC_ACTIVATION_TYPE_ACCOUNT_REQUIRED = 4; |
| |
| /** |
| * Euicc OTA update status which can be got by {@link #getOtaStatus} |
| * @hide |
| */ |
| @SystemApi |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef(prefix = {"EUICC_OTA_"}, value = { |
| EUICC_OTA_IN_PROGRESS, |
| EUICC_OTA_FAILED, |
| EUICC_OTA_SUCCEEDED, |
| EUICC_OTA_NOT_NEEDED, |
| EUICC_OTA_STATUS_UNAVAILABLE |
| |
| }) |
| public @interface OtaStatus{} |
| |
| /** |
| * An OTA is in progress. During this time, the eUICC is not available and the user may lose |
| * network access. |
| * @hide |
| */ |
| @SystemApi |
| public static final int EUICC_OTA_IN_PROGRESS = 1; |
| |
| /** |
| * The OTA update failed. |
| * @hide |
| */ |
| @SystemApi |
| public static final int EUICC_OTA_FAILED = 2; |
| |
| /** |
| * The OTA update finished successfully. |
| * @hide |
| */ |
| @SystemApi |
| public static final int EUICC_OTA_SUCCEEDED = 3; |
| |
| /** |
| * The OTA update not needed since current eUICC OS is latest. |
| * @hide |
| */ |
| @SystemApi |
| public static final int EUICC_OTA_NOT_NEEDED = 4; |
| |
| /** |
| * The OTA status is unavailable since eUICC service is unavailable. |
| * @hide |
| */ |
| @SystemApi |
| public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5; |
| |
| private final Context mContext; |
| private int mCardId; |
| |
| /** @hide */ |
| public EuiccManager(Context context) { |
| mContext = context; |
| TelephonyManager tm = (TelephonyManager) |
| context.getSystemService(Context.TELEPHONY_SERVICE); |
| mCardId = tm.getCardIdForDefaultEuicc(); |
| } |
| |
| /** @hide */ |
| private EuiccManager(Context context, int cardId) { |
| mContext = context; |
| mCardId = cardId; |
| } |
| |
| /** |
| * Create a new EuiccManager object pinned to the given card ID. |
| * |
| * @return an EuiccManager that uses the given card ID for all calls. |
| */ |
| @NonNull |
| public EuiccManager createForCardId(int cardId) { |
| return new EuiccManager(mContext, cardId); |
| } |
| |
| /** |
| * Whether embedded subscriptions are currently enabled. |
| * |
| * <p>Even on devices with the {@link PackageManager#FEATURE_TELEPHONY_EUICC} feature, embedded |
| * subscriptions may be turned off, e.g. because of a carrier restriction from an inserted |
| * physical SIM. Therefore, this runtime check should be used before accessing embedded |
| * subscription APIs. |
| * |
| * @return true if embedded subscriptions are currently enabled. |
| */ |
| public boolean isEnabled() { |
| // In the future, this may reach out to IEuiccController (if non-null) to check any dynamic |
| // restrictions. |
| return getIEuiccController() != null && refreshCardIdIfUninitialized(); |
| } |
| |
| /** |
| * Returns the EID identifying the eUICC hardware. |
| * |
| * <p>Requires that the calling app has carrier privileges on the active subscription on the |
| * current eUICC. A calling app with carrier privileges for one eUICC may not necessarily have |
| * access to the EID of another eUICC. |
| * |
| * @return the EID. May be null if the eUICC is not ready. |
| */ |
| @Nullable |
| public String getEid() { |
| if (!isEnabled()) { |
| return null; |
| } |
| try { |
| return getIEuiccController().getEid(mCardId, mContext.getOpPackageName()); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** |
| * Returns the current status of eUICC OTA. |
| * |
| * <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. |
| * |
| * @return the status of eUICC OTA. If the eUICC is not ready, |
| * {@link OtaStatus#EUICC_OTA_STATUS_UNAVAILABLE} will be returned. |
| * |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) |
| public int getOtaStatus() { |
| if (!isEnabled()) { |
| return EUICC_OTA_STATUS_UNAVAILABLE; |
| } |
| try { |
| return getIEuiccController().getOtaStatus(mCardId); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** |
| * Attempt to download the given {@link DownloadableSubscription}. |
| * |
| * <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, |
| * or the calling app must be authorized to manage both the currently-active subscription on the |
| * current eUICC and the subscription to be downloaded according to the subscription metadata. |
| * Without the former, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be |
| * returned in the callback intent to prompt the user to accept the download. |
| * |
| * <p>On a multi-active SIM device, requires the |
| * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, or a calling app |
| * only if the targeted eUICC does not currently have an active subscription or the calling app |
| * is authorized to manage the active subscription on the target eUICC, and the calling app is |
| * authorized to manage any active subscription on any SIM. Without it, an |
| * {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback |
| * intent to prompt the user to accept the download. The caller should also be authorized to |
| * manage the subscription to be downloaded. |
| * |
| * @param subscription the subscription to download. |
| * @param switchAfterDownload if true, the profile will be activated upon successful download. |
| * @param callbackIntent a PendingIntent to launch when the operation completes. |
| */ |
| @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) |
| public void downloadSubscription(DownloadableSubscription subscription, |
| boolean switchAfterDownload, PendingIntent callbackIntent) { |
| if (!isEnabled()) { |
| sendUnavailableError(callbackIntent); |
| return; |
| } |
| try { |
| getIEuiccController().downloadSubscription(mCardId, subscription, switchAfterDownload, |
| mContext.getOpPackageName(), null /* resolvedBundle */, callbackIntent); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** |
| * Start an activity to resolve a user-resolvable error. |
| * |
| * <p>If an operation returns {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR}, this |
| * method may be called to prompt the user to resolve the issue. |
| * |
| * <p>This method may only be called once for a particular error. |
| * |
| * @param activity the calling activity (which should be in the foreground). |
| * @param requestCode an application-specific request code which will be provided to |
| * {@link Activity#onActivityResult} upon completion. Note that the operation may still be |
| * in progress when the resolution activity completes; it is not fully finished until the |
| * callback intent is triggered. |
| * @param resultIntent the Intent provided to the initial callback intent which failed with |
| * {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR}. |
| * @param callbackIntent a PendingIntent to launch when the operation completes. This is |
| * trigered upon completion of the original operation that required user resolution. |
| * @throws android.content.IntentSender.SendIntentException if called more than once. |
| */ |
| public void startResolutionActivity(Activity activity, int requestCode, Intent resultIntent, |
| PendingIntent callbackIntent) throws IntentSender.SendIntentException { |
| PendingIntent resolutionIntent = |
| resultIntent.getParcelableExtra(EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT); |
| if (resolutionIntent == null) { |
| throw new IllegalArgumentException("Invalid result intent"); |
| } |
| Intent fillInIntent = new Intent(); |
| fillInIntent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT, |
| callbackIntent); |
| activity.startIntentSenderForResult(resolutionIntent.getIntentSender(), requestCode, |
| fillInIntent, 0 /* flagsMask */, 0 /* flagsValues */, 0 /* extraFlags */); |
| } |
| |
| /** |
| * Continue an operation after the user resolves an error. |
| * |
| * <p>To be called by the LUI upon completion of a resolvable error flow. |
| * |
| * <p>Requires that the calling app has the |
| * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. |
| * |
| * @param resolutionIntent The original intent used to start the LUI. |
| * @param resolutionExtras Resolution-specific extras depending on the result of the resolution. |
| * For example, this may indicate whether the user has consented or may include the input |
| * they provided. |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) |
| public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) { |
| if (!isEnabled()) { |
| PendingIntent callbackIntent = |
| resolutionIntent.getParcelableExtra( |
| EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT); |
| if (callbackIntent != null) { |
| sendUnavailableError(callbackIntent); |
| } |
| return; |
| } |
| try { |
| getIEuiccController().continueOperation(mCardId, resolutionIntent, resolutionExtras); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** |
| * Fills in the metadata for a DownloadableSubscription. |
| * |
| * <p>May be used in cases that a DownloadableSubscription was constructed to download a |
| * profile, but the metadata for the profile is unknown (e.g. we only know the activation code). |
| * The callback will be triggered with an Intent with |
| * {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION} set to the |
| * downloadable subscription metadata upon success. |
| * |
| * <p>Requires that the calling app has the |
| * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. This is for |
| * internal system use only. |
| * |
| * @param subscription the subscription which needs metadata filled in |
| * @param callbackIntent a PendingIntent to launch when the operation completes. |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) |
| public void getDownloadableSubscriptionMetadata( |
| DownloadableSubscription subscription, PendingIntent callbackIntent) { |
| if (!isEnabled()) { |
| sendUnavailableError(callbackIntent); |
| return; |
| } |
| try { |
| getIEuiccController().getDownloadableSubscriptionMetadata(mCardId, subscription, |
| mContext.getOpPackageName(), callbackIntent); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** |
| * Gets metadata for subscription which are available for download on this device. |
| * |
| * <p>Subscriptions returned here may be passed to {@link #downloadSubscription}. They may have |
| * been pre-assigned to this particular device, for example. The callback will be triggered with |
| * an Intent with {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS} set to the |
| * list of available subscriptions upon success. |
| * |
| * <p>Requires that the calling app has the |
| * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. This is for |
| * internal system use only. |
| * |
| * @param callbackIntent a PendingIntent to launch when the operation completes. |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) |
| public void getDefaultDownloadableSubscriptionList(PendingIntent callbackIntent) { |
| if (!isEnabled()) { |
| sendUnavailableError(callbackIntent); |
| return; |
| } |
| try { |
| getIEuiccController().getDefaultDownloadableSubscriptionList(mCardId, |
| mContext.getOpPackageName(), callbackIntent); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** |
| * Returns information about the eUICC chip/device. |
| * |
| * @return the {@link EuiccInfo}. May be null if the eUICC is not ready. |
| */ |
| @Nullable |
| public EuiccInfo getEuiccInfo() { |
| if (!isEnabled()) { |
| return null; |
| } |
| try { |
| return getIEuiccController().getEuiccInfo(mCardId); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** |
| * Deletes the given subscription. |
| * |
| * <p>If this subscription is currently active, the device will first switch away from it onto |
| * an "empty" subscription. |
| * |
| * <p>Requires that the calling app has carrier privileges according to the metadata of the |
| * profile to be deleted, or the |
| * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. |
| * |
| * @param subscriptionId the ID of the subscription to delete. |
| * @param callbackIntent a PendingIntent to launch when the operation completes. |
| */ |
| @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) |
| public void deleteSubscription(int subscriptionId, PendingIntent callbackIntent) { |
| if (!isEnabled()) { |
| sendUnavailableError(callbackIntent); |
| return; |
| } |
| try { |
| getIEuiccController().deleteSubscription(mCardId, |
| subscriptionId, mContext.getOpPackageName(), callbackIntent); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** |
| * Switch to (enable) the given subscription. |
| * |
| * <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, |
| * or the calling app must be authorized to manage both the currently-active subscription and |
| * the subscription to be enabled according to the subscription metadata. Without the former, |
| * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback |
| * intent to prompt the user to accept the download. |
| * |
| * <p>On a multi-active SIM device, requires the |
| * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, or a calling app |
| * only if the targeted eUICC does not currently have an active subscription or the calling app |
| * is authorized to manage the active subscription on the target eUICC, and the calling app is |
| * authorized to manage any active subscription on any SIM. Without it, an |
| * {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback |
| * intent to prompt the user to accept the download. The caller should also be authorized to |
| * manage the subscription to be enabled. |
| * |
| * @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. |
| * @param callbackIntent a PendingIntent to launch when the operation completes. |
| */ |
| @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) |
| public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) { |
| if (!isEnabled()) { |
| sendUnavailableError(callbackIntent); |
| return; |
| } |
| try { |
| getIEuiccController().switchToSubscription(mCardId, |
| subscriptionId, mContext.getOpPackageName(), callbackIntent); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** |
| * Update the nickname for the given subscription. |
| * |
| * <p>Requires that the calling app has carrier privileges according to the metadata of the |
| * profile to be updated, or the |
| * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. |
| * |
| * @param subscriptionId the ID of the subscription to update. |
| * @param nickname the new nickname to apply. |
| * @param callbackIntent a PendingIntent to launch when the operation completes. |
| */ |
| @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) |
| public void updateSubscriptionNickname( |
| int subscriptionId, @Nullable String nickname, @NonNull PendingIntent callbackIntent) { |
| if (!isEnabled()) { |
| sendUnavailableError(callbackIntent); |
| return; |
| } |
| try { |
| getIEuiccController().updateSubscriptionNickname(mCardId, |
| subscriptionId, nickname, mContext.getOpPackageName(), callbackIntent); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** |
| * Erase all operational subscriptions and reset the eUICC. |
| * |
| * <p>Requires that the calling app has the |
| * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. |
| * |
| * @param callbackIntent a PendingIntent to launch when the operation completes. |
| * |
| * @deprecated From R, callers should specify a flag for specific set of subscriptions to erase |
| * and use {@link #eraseSubscriptionsWithOptions(int, PendingIntent)} instead |
| * |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) |
| @Deprecated |
| public void eraseSubscriptions(@NonNull PendingIntent callbackIntent) { |
| if (!isEnabled()) { |
| sendUnavailableError(callbackIntent); |
| return; |
| } |
| try { |
| getIEuiccController().eraseSubscriptions(mCardId, callbackIntent); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** |
| * Erase all specific subscriptions and reset the eUICC. |
| * |
| * <p>Requires that the calling app has the |
| * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. |
| * |
| * @param options flag indicating specific set of subscriptions to erase |
| * @param callbackIntent a PendingIntent to launch when the operation completes. |
| * |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) |
| public void eraseSubscriptionsWithOptions( |
| @ResetOption int options, @NonNull PendingIntent callbackIntent) { |
| if (!isEnabled()) { |
| sendUnavailableError(callbackIntent); |
| return; |
| } |
| try { |
| getIEuiccController().eraseSubscriptionsWithOptions(mCardId, options, callbackIntent); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** |
| * Ensure that subscriptions will be retained on the next factory reset. |
| * |
| * <p>By default, all subscriptions on the eUICC are erased the first time a device boots (ever |
| * and after factory resets). This ensures that the data is wiped after a factory reset is |
| * performed via fastboot or recovery mode, as these modes do not support the necessary radio |
| * communication needed to wipe the eSIM. |
| * |
| * <p>However, this method may be called right before a factory reset issued via settings when |
| * the user elects to retain subscriptions. Doing so will mark them for retention so that they |
| * are not cleared after the ensuing reset. |
| * |
| * <p>Requires that the calling app has the {@link android.Manifest.permission#MASTER_CLEAR} |
| * permission. This is for internal system use only. |
| * |
| * @param callbackIntent a PendingIntent to launch when the operation completes. |
| * @hide |
| */ |
| public void retainSubscriptionsForFactoryReset(PendingIntent callbackIntent) { |
| if (!isEnabled()) { |
| sendUnavailableError(callbackIntent); |
| return; |
| } |
| try { |
| getIEuiccController().retainSubscriptionsForFactoryReset(mCardId, callbackIntent); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| |
| /** |
| * Refreshes the cardId if its uninitialized, and returns whether we should continue the |
| * operation. |
| * <p> |
| * Note that after a successful refresh, the mCardId may be TelephonyManager.UNSUPPORTED_CARD_ID |
| * on older HALs. For backwards compatability, we continue to the LPA and let it decide which |
| * card to use. |
| */ |
| private boolean refreshCardIdIfUninitialized() { |
| // Refresh mCardId if its UNINITIALIZED_CARD_ID |
| if (mCardId == TelephonyManager.UNINITIALIZED_CARD_ID) { |
| TelephonyManager tm = (TelephonyManager) |
| mContext.getSystemService(Context.TELEPHONY_SERVICE); |
| mCardId = tm.getCardIdForDefaultEuicc(); |
| } |
| if (mCardId == TelephonyManager.UNINITIALIZED_CARD_ID) { |
| return false; |
| } |
| return true; |
| } |
| |
| private static void sendUnavailableError(PendingIntent callbackIntent) { |
| try { |
| callbackIntent.send(EMBEDDED_SUBSCRIPTION_RESULT_ERROR); |
| } catch (PendingIntent.CanceledException e) { |
| // Caller canceled the callback; do nothing. |
| } |
| } |
| |
| private static IEuiccController getIEuiccController() { |
| return IEuiccController.Stub.asInterface(ServiceManager.getService("econtroller")); |
| } |
| } |