Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 57fbdab2 authored by SongFerngWang's avatar SongFerngWang Committed by Automerger Merge Worker
Browse files

switch SIM refactor to support MEP am: 37358798 am: 483ff27a

parents 4b3a1761 483ff27a
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -7958,11 +7958,17 @@
    <!-- Checkbox to always use for calls.  [CHAR LIMIT=40] -->
    <string name="sim_calls_always_use">Always use this for calls</string>
    <!-- Message for selecting sim for data in settings.  [CHAR LIMIT=40] -->
    <string name="select_sim_for_data">Select a SIM for data</string>
    <string name="select_sim_for_data">Choose SIM for mobile data</string>
    <!-- Message for selecting sim for SMS in settings.  [CHAR LIMIT=40] -->
    <string name="select_sim_for_sms">Select a SIM for SMS</string>
    <!-- Message for switching data SIM; switching takes a while -->
    <string name="data_switch_started">Switching data SIM, this may take up to a minute\u2026</string>
    <!-- Title for selecting specific sim for data in settings.  [CHAR LIMIT=40] -->
    <string name="select_specific_sim_for_data_title">Use <xliff:g id="new_sim" example="carrierA">%1$s</xliff:g> for mobile data?</string>
    <!-- Message for selecting specific sim for data in settings.  [CHAR LIMIT=NONE] -->
    <string name="select_specific_sim_for_data_msg">If you switch to <xliff:g id="new_sim" example="carrierA">%1$s</xliff:g>, <xliff:g id="old_sim" example="carrierB">%2$s</xliff:g> will no longer be used for mobile data.</string>
    <!-- Button on a selecting specific sim dialog to confirm data in settings.  [CHAR LIMIT=40] -->
    <string name="select_specific_sim_for_data_button">Use <xliff:g id="new_sim" example="carrierA">%1$s</xliff:g></string>
    <!-- Message for selecting sim for call in settings.  [CHAR LIMIT=40] -->
    <string name="select_sim_for_calls">Call with</string>
    <!-- Title for selecting a SIM card.  [CHAR LIMIT=40] -->
@@ -12744,14 +12750,22 @@
    <string name="sim_action_switch_sub_dialog_title">Switch to <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g>?</string>
    <!-- Title of confirmation dialog asking the user if they want to switch to the SIM card. [CHAR_LIMIT=NONE] -->
    <string name="sim_action_switch_psim_dialog_title">Switch to using SIM card?</string>
    <!-- Title of confirmation dialog asking the user if they want to switch subscription. [CHAR_LIMIT=NONE] -->
    <string name="sim_action_switch_sub_dialog_mep_title">Use <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g>?</string>
    <!-- Body text of confirmation dialog for switching subscription that involves switching SIM slots. Indicates that only one SIM can be active at a time. Also that switching will not cancel the user's mobile service plan. [CHAR_LIMIT=NONE] -->
    <string name="sim_action_switch_sub_dialog_text">Only one SIM can be active at a time.\n\nSwitching to <xliff:g id="to_carrier_name" example="Google Fi">%1$s</xliff:g> won\u2019t cancel your <xliff:g id="from_carrier_name" example="Sprint">%2$s</xliff:g> service.</string>
    <!-- Body text of confirmation dialog for switching subscription between two eSIM profiles. Indicates that only one downloaded SIM can be active at a time. Also that switching will not cancel the user's mobile service plan. [CHAR_LIMIT=NONE] -->
    <string name="sim_action_switch_sub_dialog_text_downloaded">Only one downloaded SIM can be active at a time.\n\nSwitching to <xliff:g id="to_carrier_name" example="Google Fi">%1$s</xliff:g> won\u2019t cancel your <xliff:g id="from_carrier_name" example="Sprint">%2$s</xliff:g> service.</string>
    <!-- Body text of confirmation dialog for switching subscription between two eSIM profiles. Indicates that only one SIM can be active at a time. Also that switching will not cancel the user's mobile service plan. [CHAR_LIMIT=NONE] -->
    <string name="sim_action_switch_sub_dialog_text_single_sim">Only one SIM can be active at a time.\n\nSwitching won\u2019t cancel your <xliff:g id="to_carrier_name" example="Google Fi">%1$s</xliff:g> service.</string>
    <!-- Body text of confirmation dialog for switching subscription between two eSIM profiles. Indicates that only one downloaded SIM can be active at a time. Also that switching will not cancel the user's mobile service plan. [CHAR_LIMIT=NONE] -->
    <string name="sim_action_switch_sub_dialog_mep_text">You can use 2 SIMs at a time. To use <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g>, turn off another SIM.</string>
    <!-- Text of confirm button in the confirmation dialog asking the user if they want to switch subscription. [CHAR_LIMIT=NONE] -->
    <string name="sim_action_switch_sub_dialog_confirm">Switch to <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g></string>
    <!-- Text of carrier list item in the mep confirmation dialog asking the user if they want to turn off the carrier. [CHAR_LIMIT=NONE] -->
    <string name="sim_action_switch_sub_dialog_carrier_list_item_for_turning_off">Turn off <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g></string>
    <!-- Text of carrier list item in the mep confirmation dialog asking the user if they want to turn off the carrier. [CHAR_LIMIT=NONE] -->
    <string name="sim_action_switch_sub_dialog_info_outline_for_turning_off">Turning off a SIM won\u2019t cancel your service</string>
    <!-- Status message indicating the device is in the process of disconnecting from one mobile network and immediately connecting to another. [CHAR_LIMIT=NONE] -->
    <string name="sim_action_enabling_sim_without_carrier_name">Connecting to network&#8230;</string>
    <!-- Text of progress dialog indicating the subscription switch is in progress. [CHAR_LIMIT=NONE] -->
+24 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.settings.network;
import android.annotation.IntDef;
import android.app.FragmentManager;
import android.os.Bundle;
import android.telephony.SubscriptionInfo;
import android.util.Log;

import com.android.settings.AsyncTaskSidecar;
@@ -41,11 +42,14 @@ public class SwitchSlotSidecar
    })
    private @interface Command {
        int SWITCH_TO_REMOVABLE_SIM = 0;
        int SWITCH_TO_EUICC_SIM = 1;
    }

    static class Param {
        @Command int command;
        int slotId;
        int port;
        SubscriptionInfo removedSubInfo;
    }

    static class Result {
@@ -65,13 +69,24 @@ public class SwitchSlotSidecar
    }

    /** Starts switching to the removable slot. */
    public void runSwitchToRemovableSlot(int id) {
    public void runSwitchToRemovableSlot(int id, SubscriptionInfo removedSubInfo) {
        Param param = new Param();
        param.command = Command.SWITCH_TO_REMOVABLE_SIM;
        param.slotId = id;
        param.removedSubInfo = removedSubInfo;
        param.port = 0;
        super.run(param);
    }

    /** Starts switching to the removable slot. */
    public void runSwitchToEuiccSlot(int id, int port, SubscriptionInfo removedSubInfo) {
        Param param = new Param();
        param.command = Command.SWITCH_TO_EUICC_SIM;
        param.slotId = id;
        param.removedSubInfo = removedSubInfo;
        param.port = port;
        super.run(param);
    }
    /**
     * Returns the exception thrown during the execution of a command. Will be null in any state
     * other than {@link State#SUCCESS}, and may be null in that state if there was not an error.
@@ -91,7 +106,14 @@ public class SwitchSlotSidecar
        try {
            switch (param.command) {
                case Command.SWITCH_TO_REMOVABLE_SIM:
                    UiccSlotUtil.switchToRemovableSlot(param.slotId, getContext());
                    Log.i(TAG, "Start to switch to removable slot.");
                    UiccSlotUtil.switchToRemovableSlot(getContext(), param.slotId,
                            param.removedSubInfo);
                    break;
                case Command.SWITCH_TO_EUICC_SIM:
                    Log.i(TAG, "Start to switch to euicc slot.");
                    UiccSlotUtil.switchToEuiccSlot(getContext(), param.slotId, param.port,
                            param.removedSubInfo);
                    break;
                default:
                    Log.e(TAG, "Wrong command.");
+122 −0
Original line number Diff line number Diff line
@@ -18,17 +18,30 @@ package com.android.settings.network;

import android.app.FragmentManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.telephony.SubscriptionInfo;
import android.telephony.UiccCardInfo;
import android.telephony.UiccSlotMapping;
import android.telephony.euicc.EuiccManager;
import android.util.Log;

import com.android.settings.SidecarFragment;
import com.android.settings.network.telephony.EuiccOperationSidecar;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/** A headless fragment encapsulating long-running eSIM enabling/disabling operations. */
public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar {
    private static final String TAG = "SwitchToEuiccSubscriptionSidecar";
    private static final String ACTION_SWITCH_TO_SUBSCRIPTION =
            "com.android.settings.network.SWITCH_TO_SUBSCRIPTION";
    private static final int ESIM_SLOT_ID = 1;

    private PendingIntent mCallbackIntent;
    private int mSubId;
    private int mPort;

    /** Returns a SwitchToEuiccSubscriptionSidecar sidecar instance. */
    public static SwitchToEuiccSubscriptionSidecar get(FragmentManager fm) {
@@ -46,10 +59,119 @@ public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar {
        return mCallbackIntent;
    }

    @Override
    public void onStateChange(SidecarFragment fragment) {
        if (fragment == mSwitchSlotSidecar) {
            onSwitchSlotSidecarStateChange();
        } else {
            Log.wtf(TAG, "Received state change from a sidecar not expected.");
        }
    }

    /** Starts calling EuiccManager#switchToSubscription to enable/disable the eSIM profile. */
    // ToDo: delete this api and refactor the related code.
    public void run(int subscriptionId) {
        setState(State.RUNNING, Substate.UNUSED);
        mCallbackIntent = createCallbackIntent();
        mEuiccManager.switchToSubscription(subscriptionId, mCallbackIntent);
    }

    /**
     * Starts calling EuiccManager#switchToSubscription to enable/disable the eSIM profile.
     *
     * @param subscriptionId the esim's subscriptionId.
     * @param port the esim's portId. If user wants to inactivate esim, then user must to assign the
     *             the port. If user wants to activate esim, then the port can be -1.
     * @param removedSubInfo if the all of slots have sims, it should remove the one of active sim.
     *                       If the removedSubInfo is null, then use the default value.
     *                       The default value is the esim slot and portId 0.
     */
    public void run(int subscriptionId, int port, SubscriptionInfo removedSubInfo) {
        setState(State.RUNNING, Substate.UNUSED);
        mCallbackIntent = createCallbackIntent();
        mSubId = subscriptionId;
        // To check whether the esim slot's port is active. If yes, skip setSlotMapping. If no,
        // set this slot+port into setSimSlotMapping.
        mPort = (port < 0) ? getTargetPortId(removedSubInfo) : port;
        Log.i(TAG, "The SubId is " + mSubId + "The port is " + mPort);

        mSwitchSlotSidecar.runSwitchToEuiccSlot(getTargetSlot(), mPort, removedSubInfo);
    }

    private int getTargetPortId(SubscriptionInfo removedSubInfo) {
        if (!mTelephonyManager.isMultiSimEnabled() || !isMultipleEnabledProfilesSupported()) {
            // In the 'SS mode' or 'DSDS+no MEP', the port is 0.
            return 0;
        }

        // In the 'DSDS+MEP', if the removedSubInfo is esim, then the port is
        // removedSubInfo's port.
        if (removedSubInfo != null && removedSubInfo.isEmbedded()) {
            return removedSubInfo.getPortIndex();
        }

        // In DSDS+MEP mode, the removedSubInfo is psim or is null, it means the this esim need
        // another port in the esim slot.
        // To find another esim's port and value is from 0;
        int port = 0;
        Collection<UiccSlotMapping> uiccSlotMappings = mTelephonyManager.getSimSlotMapping();
        for (UiccSlotMapping uiccSlotMapping :
                uiccSlotMappings.stream()
                        .filter(
                                uiccSlotMapping -> uiccSlotMapping.getPhysicalSlotIndex()
                                        == getTargetSlot())
                        .collect(Collectors.toList())) {
            if (uiccSlotMapping.getPortIndex() == port) {
                port++;
            }
        }
        return port;
    }

    private int getTargetSlot() {
        return ESIM_SLOT_ID;
    }

    private void onSwitchSlotSidecarStateChange() {
        switch (mSwitchSlotSidecar.getState()) {
            case State.SUCCESS:
                mSwitchSlotSidecar.reset();
                Log.i(TAG,
                        "Successfully SimSlotMapping. Start to enable/disable esim");
                switchToSubscription();
                break;
            case State.ERROR:
                mSwitchSlotSidecar.reset();
                Log.i(TAG, "Failed to set SimSlotMapping");
                setState(State.ERROR, Substate.UNUSED);
                break;
        }
    }

    private boolean isMultipleEnabledProfilesSupported() {
        List<UiccCardInfo> cardInfos = mTelephonyManager.getUiccCardsInfo();
        if (cardInfos == null) {
            Log.w(TAG, "UICC cards info list is empty.");
            return false;
        }
        return cardInfos.stream().anyMatch(
                cardInfo -> cardInfo.isMultipleEnabledProfilesSupported());
    }

    private void switchToSubscription() {
        // The SimSlotMapping is ready, then to execute activate/inactivate esim.
        EuiccManager.ResultListener callback = new EuiccManager.ResultListener() {
            @Override
            public void onComplete(int resultCode, Intent resultIntent) {
                Log.i(TAG, String.format("Result code : %d;", resultCode));
                if (resultCode == EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK) {
                    setState(State.SUCCESS, Substate.UNUSED);
                } else {
                    setState(State.ERROR, resultCode);
                }
            }
        };
        mEuiccManager.switchToSubscription(mSubId, mPort, getContext().getMainExecutor(),
                callback);
    }
}
+23 −9
Original line number Diff line number Diff line
@@ -38,8 +38,8 @@ public class SwitchToRemovableSlotSidecar extends EuiccOperationSidecar

    // Stateless members.
    private SwitchToEuiccSubscriptionSidecar mSwitchToSubscriptionSidecar;
    private SwitchSlotSidecar mSwitchSlotSidecar;
    private int mPhysicalSlotId;
    private SubscriptionInfo mRemovedSubInfo;

    /** Returns a SwitchToRemovableSlotSidecar sidecar instance. */
    public static SwitchToRemovableSlotSidecar get(FragmentManager fm) {
@@ -51,20 +51,17 @@ public class SwitchToRemovableSlotSidecar extends EuiccOperationSidecar
        super.onCreate(savedInstanceState);
        mSwitchToSubscriptionSidecar =
                SwitchToEuiccSubscriptionSidecar.get(getChildFragmentManager());
        mSwitchSlotSidecar = SwitchSlotSidecar.get(getChildFragmentManager());
    }

    @Override
    public void onResume() {
        super.onResume();
        mSwitchToSubscriptionSidecar.addListener(this);
        mSwitchSlotSidecar.addListener(this);
    }

    @Override
    public void onPause() {
        mSwitchToSubscriptionSidecar.removeListener(this);
        mSwitchSlotSidecar.removeListener(this);
        super.onPause();
    }

@@ -90,29 +87,46 @@ public class SwitchToRemovableSlotSidecar extends EuiccOperationSidecar
     *
     * @param physicalSlotId removable physical SIM slot ID.
     */
    // ToDo: delete this api and refactor the related code.
    public void run(int physicalSlotId) {
        mPhysicalSlotId = physicalSlotId;
        SubscriptionManager subscriptionManager =
                getContext().getSystemService(SubscriptionManager.class);
        if (SubscriptionUtil.getActiveSubscriptions(subscriptionManager).stream()
                .anyMatch(SubscriptionInfo::isEmbedded)) {
            // In SS mode, the esim is active, then inactivate the esim.
            Log.i(TAG, "There is an active eSIM profile. Disable the profile first.");
            // Use INVALID_SUBSCRIPTION_ID to disable the only active profile.
            mSwitchToSubscriptionSidecar.run(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
            mSwitchToSubscriptionSidecar.run(SubscriptionManager.INVALID_SUBSCRIPTION_ID, 0, null);
        } else {
            Log.i(TAG, "There is no active eSIM profiles. Start to switch to removable slot.");
            mSwitchSlotSidecar.runSwitchToRemovableSlot(mPhysicalSlotId);
            mSwitchSlotSidecar.runSwitchToRemovableSlot(mPhysicalSlotId, null);
        }
    }

    /**
     * Starts switching to the removable slot.
     *
     * @param physicalSlotId removable physical SIM slot ID.
     * @param removedSubInfo if the all of slots have sims, it should remove the one of active sim.
     *                       If the removedSubInfo is null, then use the default value.
     *                       The default value is the removable physical SIM slot and portId 0.
     */
    public void run(int physicalSlotId, SubscriptionInfo removedSubInfo) {
        mPhysicalSlotId = physicalSlotId;
        mRemovedSubInfo = removedSubInfo;

        Log.i(TAG, "Start to switch to removable slot.");
        mSwitchSlotSidecar.runSwitchToRemovableSlot(mPhysicalSlotId, mRemovedSubInfo);
    }

    private void onSwitchToSubscriptionSidecarStateChange() {
        switch (mSwitchToSubscriptionSidecar.getState()) {
            case State.SUCCESS:
                mSwitchToSubscriptionSidecar.reset();
                Log.i(
                        TAG,
                Log.i(TAG,
                        "Successfully disabled eSIM profile. Start to switch to Removable slot.");
                mSwitchSlotSidecar.runSwitchToRemovableSlot(mPhysicalSlotId);
                mSwitchSlotSidecar.runSwitchToRemovableSlot(mPhysicalSlotId, mRemovedSubInfo);
                break;
            case State.ERROR:
                mSwitchToSubscriptionSidecar.reset();
+168 −40

File changed.

Preview size limit exceeded, changes collapsed.

Loading