/*
 * 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.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SuppressAutoDoc;
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.SubscriptionManager;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.TelephonyManager;
import android.telephony.UiccCardInfo;
import android.telephony.euicc.EuiccCardManager.ResetOption;
import android.util.Log;

import com.android.internal.telephony.euicc.IEuiccController;
import com.android.internal.telephony.flags.Flags;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 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.
 */
@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.
     *
     * <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";


    /**
     * Intent action to transfer an embedded subscriptions.
     *
     * <p> Action sent by apps (such as the Settings app) to the Telephony framework to transfer an
     * embedded subscription.
     *
     * <p> Requires that the calling app has the
     * {@code android.Manifest.permission#MODIFY_PHONE_STATE} permission.
     *
     * <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)
    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
    public static final String ACTION_TRANSFER_EMBEDDED_SUBSCRIPTIONS =
            "android.telephony.euicc.action.TRANSFER_EMBEDDED_SUBSCRIPTIONS";

    /**
     * Intent action to convert the physical subscription to an embedded subscription.
     *
     * <p> Action sent by apps (such as the Settings app) to the Telephony framework to convert
     * physical sim to embedded sim.
     *
     * <p> Requires that the calling app has the
     * {@code android.Manifest.permission#MODIFY_PHONE_STATE} permission.
     *
     * <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)
    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
    public static final String ACTION_CONVERT_TO_EMBEDDED_SUBSCRIPTION =
            "android.telephony.euicc.action.CONVERT_TO_EMBEDDED_SUBSCRIPTION";

    /**
     * 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";

    /**
     * Intent action sent by a carrier app to launch the eSIM activation flow provided by the LPA UI
     * (LUI). The carrier app must send this intent with one of the following:
     *
     * <p>{@link #EXTRA_USE_QR_SCANNER} not set or set to false: The LPA should try to get an
     * activation code from the carrier app by binding to the carrier app service implementing
     * {@code android.service.euicc.EuiccService#ACTION_BIND_CARRIER_PROVISIONING_SERVICE}.
     * <p>{@link #EXTRA_USE_QR_SCANNER} set to true: The LPA should launch a QR scanner for the user
     * to scan an eSIM profile QR code.
     *
     * <p>Upon completion, the LPA should return one of the following results to the carrier app:
     *
     * <p>{@code Activity.RESULT_OK}: The LPA has succeeded in downloading the new eSIM profile.
     * <p>{@code Activity.RESULT_CANCELED}: The carrier app should treat this as if the user pressed
     * the back button.
     * <p>Anything else: The carrier app should treat this as an error.
     *
     * <p>LPA needs to check if caller's package name is allowed to perform this action.
     **/
    @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
    public static final String ACTION_START_EUICC_ACTIVATION =
            "android.telephony.euicc.action.START_EUICC_ACTIVATION";

    /**
     * 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>The value of this key is an integer and contains two portions. The first byte is
     * OperationCode and the reaming three bytes is the ErrorCode.
     *
     * OperationCode is the first byte of the result code and is a categorization which defines what
     * type of operation took place when an error occurred. e.g {@link #OPERATION_DOWNLOAD} means
     * the error is related to download.Since the OperationCode only uses at most one byte, the
     * maximum allowed quantity is 255(0xFF).
     *
     * ErrorCode is the remaining three bytes of the result code, and it denotes what happened.
     * e.g a combination of {@link #OPERATION_DOWNLOAD} and {@link #ERROR_TIME_OUT} will suggest the
     * download operation has timed out. The only exception here is
     * {@link #OPERATION_SMDX_SUBJECT_REASON_CODE}, where instead of ErrorCode, SubjectCode[5.2.6.1
     * from GSMA (SGP.22 v2.2) and ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2) are encoded. @see
     * {@link #EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_SUBJECT_CODE} and
     * {@link #EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_REASON_CODE}
     *
     * In the case where ErrorCode contains a value of 0, it means it's an unknown error. E.g Intent
     * only contains {@link #OPERATION_DOWNLOAD} and ErrorCode is 0 implies this is an unknown
     * Download error.
     *
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_OPERATION_CODE
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_SUBJECT_CODE
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_REASON_CODE
     */
    public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE =
            "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE";

    /**
     * Key for an extra set on {@link PendingIntent} result callbacks providing a
     * OperationCode of {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE},
     * value will be an int.
     */
    public static final String EXTRA_EMBEDDED_SUBSCRIPTION_OPERATION_CODE =
            "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_OPERATION_CODE";

    /**
     * Key for an extra set on {@link PendingIntent} result callbacks providing a
     * ErrorCode of {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE},
     * value will be an int.
     */
    public static final String EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE =
            "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_ERROR_CODE";

    /**
     * Key for an extra set on {@link PendingIntent} result callbacks providing a
     * SubjectCode[5.2.6.1] from GSMA (SGP.22 v2.2) decoded from
     * {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE}.
     * The value of this extra will be a String.
     */
    public static final String EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_SUBJECT_CODE =
            "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_SMDX_SUBJECT_CODE";

    /**
     * Key for an extra set on {@link PendingIntent} result callbacks providing a
     * ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2) decoded from
     * {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE}.
     * The value of this extra will be a String.
     */
    public static final String EXTRA_EMBEDDED_SUBSCRIPTION_SMDX_REASON_CODE =
            "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_SMDX_REASON_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
     */
    @SystemApi
    public static final String EXTRA_PHYSICAL_SLOT_ID =
            "android.telephony.euicc.extra.PHYSICAL_SLOT_ID";


    /**
     * Key for an extra set on actions {@link #ACTION_START_EUICC_ACTIVATION} providing a boolean
     * value of whether to start eSIM activation with QR scanner.
     *
     * <p>Expected type of the extra data: boolean
     **/
    public static final String EXTRA_USE_QR_SCANNER =
            "android.telephony.euicc.extra.USE_QR_SCANNER";

    /**
     * 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,
            EUICC_ACTIVATION_TYPE_TRANSFER_FINAL_HOLD,
    })
    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;

    /**
     * The activation flow of eSIM transfer to block the transfer process before B&R flow.
     * This is needed to avoid connection overlapping between eSIM connection B&R connection.
     *
     * @hide
     */
     // TODO(b/329212614): add system api annotation during the allowed api timeline.
     public static final int EUICC_ACTIVATION_TYPE_TRANSFER_FINAL_HOLD = 5;

    /**
     * Euicc OTA update status which can be got by {@link #getOtaStatus}
     * @removed mistakenly exposed as system-api previously
     */
    @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;

    /**
     * List of OperationCode corresponding to {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE}'s
     * value, an integer. @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     *
     * @hide
     */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = {"OPERATION_"}, value = {
            OPERATION_SYSTEM,
            OPERATION_SIM_SLOT,
            OPERATION_EUICC_CARD,
            OPERATION_SWITCH,
            OPERATION_DOWNLOAD,
            OPERATION_METADATA,
            OPERATION_EUICC_GSMA,
            OPERATION_APDU,
            OPERATION_SMDX,
            OPERATION_HTTP,
            OPERATION_SMDX_SUBJECT_REASON_CODE,
    })
    public @interface OperationCode {
    }

    /**
     * Internal system error.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int OPERATION_SYSTEM = 1;

    /**
     * SIM slot error. Failed to switch slot, failed to access the physical slot etc.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int OPERATION_SIM_SLOT = 2;

    /**
     * eUICC card error.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int OPERATION_EUICC_CARD = 3;

    /**
     * Generic switching profile error
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int OPERATION_SWITCH = 4;

    /**
     * Download profile error.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int OPERATION_DOWNLOAD = 5;

    /**
     * Subscription's metadata error
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int OPERATION_METADATA = 6;

    /**
     * eUICC returned an error defined in GSMA (SGP.22 v2.2) while running one of the ES10x
     * functions.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int OPERATION_EUICC_GSMA = 7;

    /**
     * The exception of failing to execute an APDU command. It can be caused by an error
     * happening on opening the basic or logical channel, or the response of the APDU command is
     * not success (0x9000).
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int OPERATION_APDU = 8;

    /**
     * SMDX(SMDP/SMDS) error
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int OPERATION_SMDX = 9;

    /**
     * SubjectCode[5.2.6.1] and ReasonCode[5.2.6.2] error from GSMA (SGP.22 v2.2)
     * When {@link #OPERATION_SMDX_SUBJECT_REASON_CODE} is used as the
     * {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE}, the remaining three bytes of the integer
     * result from {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} will be used to stored the
     * SubjectCode and ReasonCode from the GSMA spec and NOT ErrorCode.
     *
     * The encoding will follow the format of:
     * 1. The first byte of the result will be 255(0xFF).
     * 2. Remaining three bytes(24 bits) will be split into six sections, 4 bits in each section.
     * 3. A SubjectCode/ReasonCode will take 12 bits each.
     * 4. The maximum number can be represented per section is 15, as that is the maximum number
     * allowed to be stored into 4 bits
     * 5. Maximum supported nested category from GSMA is three layers. E.g 8.11.1.2 is not
     * supported.
     *
     * E.g given SubjectCode(8.11.1) and ReasonCode(5.1)
     *
     * Base10:  0       10      8       11      1       0       5       1
     * Base2:   0000    1010    1000    1011    0001    0000    0101    0001
     * Base16:  0       A       8       B       1       0       5       1
     *
     * Thus the integer stored in {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE} is
     * 0xA8B1051(176885841)
     *
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int OPERATION_SMDX_SUBJECT_REASON_CODE = 10;

    /**
     * HTTP error
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int OPERATION_HTTP = 11;

    /**
     * List of ErrorCode corresponding to {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE}
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     * @hide
     */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = {"ERROR_"}, value = {
            ERROR_CARRIER_LOCKED,
            ERROR_INVALID_ACTIVATION_CODE,
            ERROR_INVALID_CONFIRMATION_CODE,
            ERROR_INCOMPATIBLE_CARRIER,
            ERROR_EUICC_INSUFFICIENT_MEMORY,
            ERROR_TIME_OUT,
            ERROR_EUICC_MISSING,
            ERROR_UNSUPPORTED_VERSION,
            ERROR_SIM_MISSING,
            ERROR_INSTALL_PROFILE,
            ERROR_DISALLOWED_BY_PPR,
            ERROR_ADDRESS_MISSING,
            ERROR_CERTIFICATE_ERROR,
            ERROR_NO_PROFILES_AVAILABLE,
            ERROR_CONNECTION_ERROR,
            ERROR_INVALID_RESPONSE,
            ERROR_OPERATION_BUSY,
    })
    public @interface ErrorCode{}

    /**
     * Operation such as downloading/switching to another profile failed due to device being
     * carrier locked.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_CARRIER_LOCKED = 10000;

    /**
     * The activation code(SGP.22 v2.2 section[4.1]) is invalid.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_INVALID_ACTIVATION_CODE = 10001;

    /**
     * The confirmation code(SGP.22 v2.2 section[4.7]) is invalid.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_INVALID_CONFIRMATION_CODE = 10002;

    /**
     * The profile's carrier is incompatible with the LPA.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_INCOMPATIBLE_CARRIER = 10003;

    /**
     * There is no more space available on the eUICC for new profiles.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_EUICC_INSUFFICIENT_MEMORY = 10004;

    /**
     * Timed out while waiting for an operation to complete. i.e restart, disable,
     * switch reset etc.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_TIME_OUT = 10005;

    /**
     * eUICC is missing or defective on the device.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_EUICC_MISSING = 10006;

    /**
     * The eUICC card(hardware) version is incompatible with the software
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_UNSUPPORTED_VERSION = 10007;

    /**
     * No SIM card is available in the device.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_SIM_MISSING = 10008;

    /**
     * Failure to load the profile onto the eUICC card. e.g
     * 1. iccid of the profile already exists on the eUICC.
     * 2. GSMA(.22 v2.2) Profile Install Result - installFailedDueToDataMismatch
     * 3. operation was interrupted
     * 4. SIMalliance error in PEStatus(SGP.22 v2.2 section 2.5.6.1)
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_INSTALL_PROFILE = 10009;

    /**
     * Failed to load profile onto eUICC due to Profile Policy Rules.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_DISALLOWED_BY_PPR = 10010;


    /**
     * Address is missing e.g SMDS/SMDP address is missing.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_ADDRESS_MISSING = 10011;

    /**
     * Certificate needed for authentication is not valid or missing. E.g  SMDP/SMDS authentication
     * failed.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_CERTIFICATE_ERROR = 10012;


    /**
     * No profiles available.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_NO_PROFILES_AVAILABLE = 10013;

    /**
     * Failure to create a connection.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_CONNECTION_ERROR = 10014;

    /**
     * Response format is invalid. e.g SMDP/SMDS response contains invalid json, header or/and ASN1.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_INVALID_RESPONSE = 10015;

    /**
     * The operation is currently busy, try again later.
     * @see #EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE for details
     */
    public static final int ERROR_OPERATION_BUSY = 10016;

    /**
     * Failure due to target port is not supported.
     * @see #switchToSubscription(int, int, PendingIntent)
     */
    public static final int ERROR_INVALID_PORT = 10017;

    /** Temporary failure to retrieve available memory because eUICC is not ready. */
    @FlaggedApi(Flags.FLAG_ESIM_AVAILABLE_MEMORY)
    public static final long EUICC_MEMORY_FIELD_UNAVAILABLE = -1L;

    /**
     * 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;

    /**
     * With support for MEP(multiple enabled profile) in Android T, a SIM card can enable multiple
     * profile on different port. If apps are not target SDK T yet and keep calling the
     * switchToSubscription or download API without specifying the port index, we should
     * keep the existing behaviour by always use port index 0 even the device itself has MEP eUICC,
     * this is for carrier app's backward compatibility.
     * @hide
     */
    @ChangeId
    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
    public static final long SHOULD_RESOLVE_PORT_INDEX_FOR_APPS = 224562872L;

    /**
     * Starting with Android U, a port is available if it is active without an enabled profile
     * on it or calling app can activate a new profile on the selected port without any user
     * interaction.
     * @hide
     */
    @ChangeId
    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
    public static final long INACTIVE_PORT_AVAILABILITY_CHECK = 240273417L;

    private final Context mContext;
    private int mCardId;

    /** @hide */
    public EuiccManager(Context context) {
        mContext = context;
        mCardId = 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.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     */
    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.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     */
    @Nullable
    public String getEid() {
        if (!isEnabled()) {
            return null;
        }
        try {
            return getIEuiccController().getEid(mCardId, mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Returns the available memory in bytes of the eUICC.
     *
     * @return the available memory in bytes. May be {@link #EUICC_MEMORY_FIELD_UNAVAILABLE} if the
     *     eUICC is not ready. Check {@link #isEnabled} for more information.
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC} or
     *          device doesn't support querying this information from the eUICC.
     */
    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
    @FlaggedApi(Flags.FLAG_ESIM_AVAILABLE_MEMORY)
    @RequiresPermission(
            anyOf = {
                Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
                "carrier privileges"
            })
    public long getAvailableMemoryInBytes() {
        if (!isEnabled()) {
            return EUICC_MEMORY_FIELD_UNAVAILABLE;
        }
        try {
            return getIEuiccController()
                    .getAvailableMemoryInBytes(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.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     * @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}
     * 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> Starting from Android {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM},
     * if the caller has the
     * {@code android.Manifest.permission#MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS} permission or
     * is a profile owner or device owner, then the downloaded subscription
     * will be managed by that caller.
     * In case the caller is device owner or profile owner of an organization-owned device, {@code
     * switchAfterDownload} can be set to true to automatically enable the subscription after
     * download. If the caller is a profile owner on non organization owned device
     * {@code switchAfterDownload} should be false otherwise the operation will fail with
     * {@link #EMBEDDED_SUBSCRIPTION_RESULT_ERROR}.
     *
     * <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.
     *
     * <p>If device support {@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP} and
     * switchAfterDownload is {@code true}, the subscription will be enabled on an esim port based
     * on the following selection rules:
     * <ul>
     *    <li>In SS(Single SIM) mode, if the embedded slot already has an active port, then download
     *    and enable the subscription on this port.
     *    <li>In SS mode, if the embedded slot is not active, then try to download and enable the
     *    subscription on the default port 0 of eUICC.
     *    <li>In DSDS mode, find first available port to download and enable the subscription.
     *    (see {@link #isSimPortAvailable(int)})
     *</ul>
     * If there is no available port, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR}
     * will be returned in the callback intent to prompt the user to disable an already-active
     * subscription.
     *
     * @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.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     */
    @RequiresPermission(anyOf = {
            Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS,
            Manifest.permission.MANAGE_DEVICE_POLICY_MANAGED_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, android.app.PendingIntent.class);
        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.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     * @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, android.app.PendingIntent.class);
            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.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     * @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.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     * @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.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     */
    @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.
     * Starting from Android {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}, if the
     * caller is a device owner, profile owner, or holds the
     * {@code android.Manifest.permission#MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS} permission,
     * then the caller can delete a subscription that was downloaded by that caller.
     * If such a caller tries to delete any other subscription then the
     * operation will fail with {@link #EMBEDDED_SUBSCRIPTION_RESULT_ERROR}.
     *
     * @param subscriptionId the ID of the subscription to delete.
     * @param callbackIntent a PendingIntent to launch when the operation completes.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     */
    @RequiresPermission(anyOf = {
            Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS,
            Manifest.permission.MANAGE_DEVICE_POLICY_MANAGED_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.
     *
     * <p> From Android T, devices might support {@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP},
     * 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 enable the subscription. Otherwise, use this API to enable the
     * subscription on the eUICC and the platform will internally resolve a port based on following
     * rules:
     * <ul>
     *    <li>always use the default port 0 is eUICC does not support MEP or the apps are
     *    not targeting on Android T.
     *    <li>In SS(Single SIM) mode, if the embedded slot already has an active port, then enable
     *    the subscription on this port.
     *    <li>In SS mode, if the embedded slot is not active, then try to enable the subscription on
     *    the default port 0 of eUICC.
     *    <li>In DSDS mode, find first available port to enable the subscription.
     *    (see {@link #isSimPortAvailable(int)})
     *</ul>
     * If there is no available port, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR}
     * will be returned in the callback intent to prompt the user to disable an already-active
     * subscription.
     *
     * @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. 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.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     */
    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
    public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) {
        if (!isEnabled()) {
            sendUnavailableError(callbackIntent);
            return;
        }
        try {
            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) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Switch to (enable) the given subscription.
     *
     * <p> Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
     * or the caller must be having both the carrier privileges
     * (see {@link TelephonyManager#hasCarrierPrivileges}) over any currently active subscriptions
     * and the subscription to be enabled according to the subscription metadata.
     * Without the former permissions, an SecurityException is thrown.
     *
     * <p> If the caller is passing invalid port index,
     * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_ERROR} with detailed error code
     * {@link #ERROR_INVALID_PORT} will be returned. The port index is invalid if one of the
     * following requirements is met:
     * <ul>
     *     <li>index is beyond the range of {@link UiccCardInfo#getPorts()}.
     *     <li>In SS(Single SIM) mode, the embedded slot already has an active port with different
     *     port index.
     *     <li>In DSDS mode, if the psim slot is active and the embedded slot already has an active
     *     empty port with different port index.
     * </ul>
     *
     * <p> Depending on the target port and permission check,
     * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} might be returned to the callback
     * intent to prompt the user to authorize before the switch.
     *
     * @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. 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.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     */
    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
    public void switchToSubscription(int subscriptionId, int portIndex,
            @NonNull PendingIntent callbackIntent) {
        if (!isEnabled()) {
            sendUnavailableError(callbackIntent);
            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) {
            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.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     */
    @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 #eraseSubscriptions(int, PendingIntent)} instead
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     * @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.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     * @hide
     */
    @SystemApi
    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
    public void eraseSubscriptions(
            @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();
        }
    }

    /**
     * Sets the supported countries for eUICC.
     *
     * <p>Requires that the calling app has the
     * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
     *
     * <p>The supported country list will be replaced by {@code supportedCountries}. For how we
     * determine whether a country is supported please check {@link #isSupportedCountry}.
     *
     * @param supportedCountries is a list of strings contains country ISO codes in uppercase.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     * @hide
     */
    @SystemApi
    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
    public void setSupportedCountries(@NonNull List<String> supportedCountries) {
        if (!isEnabled()) {
            return;
        }
        try {
            getIEuiccController().setSupportedCountries(
                    true /* isSupported */,
                    supportedCountries.stream()
                        .map(String::toUpperCase).collect(Collectors.toList()));
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Sets the unsupported countries for eUICC.
     *
     * <p>Requires that the calling app has the
     * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
     *
     * <p>The unsupported country list will be replaced by {@code unsupportedCountries}. For how we
     * determine whether a country is supported please check {@link #isSupportedCountry}.
     *
     * @param unsupportedCountries is a list of strings contains country ISO codes in uppercase.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     * @hide
     */
    @SystemApi
    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
    public void setUnsupportedCountries(@NonNull List<String> unsupportedCountries) {
        if (!isEnabled()) {
            return;
        }
        try {
            getIEuiccController().setSupportedCountries(
                    false /* isSupported */,
                    unsupportedCountries.stream()
                        .map(String::toUpperCase).collect(Collectors.toList()));
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Gets the supported countries for eUICC.
     *
     * <p>Requires that the calling app has the
     * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
     *
     * @return list of strings contains country ISO codes in uppercase.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     * @hide
     */
    @SystemApi
    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
    @NonNull
    public List<String> getSupportedCountries() {
        if (!isEnabled()) {
            return Collections.emptyList();
        }
        try {
            return getIEuiccController().getSupportedCountries(true /* isSupported */);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Gets the unsupported countries for eUICC.
     *
     * <p>Requires that the calling app has the
     * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
     *
     * @return list of strings contains country ISO codes in uppercase.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     * @hide
     */
    @SystemApi
    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
    @NonNull
    public List<String> getUnsupportedCountries() {
        if (!isEnabled()) {
            return Collections.emptyList();
        }
        try {
            return getIEuiccController().getSupportedCountries(false /* isSupported */);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Returns whether the given country supports eUICC.
     *
     * <p>Supported country list has a higher prority than unsupported country list. If the
     * supported country list is not empty, {@code countryIso} will be considered as supported when
     * it exists in the supported country list. Otherwise {@code countryIso} is not supported. If
     * the supported country list is empty, {@code countryIso} will be considered as supported if it
     * does not exist in the unsupported country list. Otherwise {@code countryIso} is not
     * supported. If both supported and unsupported country lists are empty, then all countries are
     * consider be supported. For how to set supported and unsupported country list, please check
     * {@link #setSupportedCountries} and {@link #setUnsupportedCountries}.
     *
     * @param countryIso should be the ISO-3166 country code is provided in uppercase 2 character
     * format.
     * @return whether the given country supports eUICC or not.
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     * @hide
     */
    @SystemApi
    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
    public boolean isSupportedCountry(@NonNull String countryIso) {
        if (!isEnabled()) {
            return false;
        }
        try {
            return getIEuiccController().isSupportedCountry(countryIso.toUpperCase(Locale.ROOT));
        } 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) {
            mCardId = getCardIdForDefaultEuicc();
        }
        return mCardId != TelephonyManager.UNINITIALIZED_CARD_ID;
    }

    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(
                TelephonyFrameworkInitializer
                        .getTelephonyServiceManager()
                        .getEuiccControllerService()
                        .get());
    }

    private int getCardIdForDefaultEuicc() {
        int cardId = TelephonyManager.UNINITIALIZED_CARD_ID;

        if (Flags.enforceTelephonyFeatureMappingForPublicApis()) {
            PackageManager pm = mContext.getPackageManager();
            if (pm != null && pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_EUICC)) {
                TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
                cardId = tm.getCardIdForDefaultEuicc();
            }
        } else {
            TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
            cardId = tm.getCardIdForDefaultEuicc();
        }

        return cardId;
    }

    /**
     * Returns whether the passing portIndex is available.
     * A port is available if it is active without enabled profile on it or
     * calling app has carrier privilege over the profile installed on the selected port.
     *
     * <p> From Android U, a port is available if it is active without an enabled profile on it or
     * calling app can activate a new profile on the selected port without any user interaction.
     *
     * Always returns false if the cardId is a physical card.
     *
     * @param portIndex is an enumeration of the ports available on the UICC.
     * @return {@code true} if port is available
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     */
    public boolean isSimPortAvailable(int portIndex) {
        try {
            return getIEuiccController().isSimPortAvailable(mCardId, portIndex,
                    mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Sets the supported carrier ids for pSIM conversion.
     *
     * <p>Any existing pSIM conversion supported carrier list will be replaced
     * by the {@code carrierIds} set here.
     *
     * @param carrierIds is a list of carrierIds that supports pSIM conversion
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     * @throws IllegalStateException if this method is called when {@link #isEnabled} is false.
     * @hide
     */
    @FlaggedApi(Flags.FLAG_SUPPORT_PSIM_TO_ESIM_CONVERSION)
    @SystemApi
    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
    public void setPsimConversionSupportedCarriers(@NonNull Set<Integer> carrierIds) {
        if (!isEnabled()) {
            throw new IllegalStateException("Euicc is not enabled");
        }
        try {
            int[] arr = carrierIds.stream().mapToInt(Integer::intValue).toArray();
            getIEuiccController().setPsimConversionSupportedCarriers(arr);
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        }
    }

    /**
     * Returns whether the given carrier id supports pSIM conversion or not.
     *
     * @param carrierId to check whether pSIM conversion is supported or not
     * @return whether the given carrier id supports pSIM conversion or not,
     *         or false if {@link #isEnabled} is false
     *
     * @throws UnsupportedOperationException If the device does not have
     *          {@link PackageManager#FEATURE_TELEPHONY_EUICC}.
     * @hide
     */
    @FlaggedApi(Flags.FLAG_SUPPORT_PSIM_TO_ESIM_CONVERSION)
    @SystemApi
    @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
    public boolean isPsimConversionSupported(int carrierId) {
        if (!isEnabled()) {
            return false;
        }
        try {
            return getIEuiccController().isPsimConversionSupported(carrierId);
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        }
    }
}
