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

Commit 28bed8ec authored by SongFerngWang's avatar SongFerngWang
Browse files

[MEP]The Esim's PhysicalSlotIndex is wrong

Using the getUiccSlotInfo API to get the PhysicalSlotIndex of esim

Bug: 215302360
Test: atest UiccSlotUtilTest
Change-Id: Ic43d6c4a3209d24673769b71b9a148e780ee81ab
parent 0042654d
Loading
Loading
Loading
Loading
+20 −9
Original line number Diff line number Diff line
@@ -37,7 +37,6 @@ public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar {
    private static final String TAG = "SwitchToEuiccSidecar";
    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;
@@ -92,11 +91,20 @@ public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar {
        setState(State.RUNNING, Substate.UNUSED);
        mCallbackIntent = createCallbackIntent();
        mSubId = subscriptionId;
        int targetSlot = getTargetSlot();
        if (targetSlot < 0) {
            Log.d(TAG, "There is no esim, the TargetSlot is " + targetSlot);
            setState(State.ERROR, Substate.UNUSED);
            return;
        }

        // 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;
        mPort = (port < 0) ? getTargetPortId(removedSubInfo, targetSlot) : port;
        mRemovedSubInfo = removedSubInfo;
        Log.i(TAG, "The SubId is " + mSubId + ". The port is " + mPort);
        Log.d(TAG,
                String.format("set esim into the Slot%d SubId%d:Port%d",
                        targetSlot, mSubId, mPort));

        if (mTelephonyManager.isMultiSimEnabled() && removedSubInfo != null
                && removedSubInfo.isEmbedded()) {
@@ -108,11 +116,11 @@ public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar {
            mEuiccManager.switchToSubscription(SubscriptionManager.INVALID_SUBSCRIPTION_ID, mPort,
                    mCallbackIntent);
        } else {
            mSwitchSlotSidecar.runSwitchToEuiccSlot(getTargetSlot(), mPort, removedSubInfo);
            mSwitchSlotSidecar.runSwitchToEuiccSlot(targetSlot, mPort, removedSubInfo);
        }
    }

    private int getTargetPortId(SubscriptionInfo removedSubInfo) {
    private int getTargetPortId(SubscriptionInfo removedSubInfo, int targetSlot) {
        if (!mTelephonyManager.isMultiSimEnabled() || !isMultipleEnabledProfilesSupported()) {
            // In the 'SS mode' or 'DSDS+no MEP', the port is 0.
            return 0;
@@ -124,16 +132,19 @@ public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar {
            return removedSubInfo.getPortIndex();
        }

        // In DSDS+MEP mode, the removedSubInfo is psim or is null, it means the this esim need
        // In DSDS+MEP mode, the removedSubInfo is psim or is null, it means this esim needs
        // another port in the esim slot.
        // To find another esim's port and value is from 0;
        // To find another esim's port and value is from 0.
        // For example:
        // 1) If there is no enabled esim and the user add new esim. This new esim's port is 0.
        // 2) If there is one enabled esim and the user add new esim. This new esim's port is 1.
        int port = 0;
        Collection<UiccSlotMapping> uiccSlotMappings = mTelephonyManager.getSimSlotMapping();
        for (UiccSlotMapping uiccSlotMapping :
                uiccSlotMappings.stream()
                        .filter(
                                uiccSlotMapping -> uiccSlotMapping.getPhysicalSlotIndex()
                                        == getTargetSlot())
                                        == targetSlot)
                        .collect(Collectors.toList())) {
            if (uiccSlotMapping.getPortIndex() == port) {
                port++;
@@ -143,7 +154,7 @@ public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar {
    }

    private int getTargetSlot() {
        return ESIM_SLOT_ID;
        return UiccSlotUtil.getEsimSlotId(getContext());
    }

    private void onSwitchSlotSidecarStateChange() {
+23 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import java.util.Collection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

// ToDo: to do the refactor for renaming
public class UiccSlotUtil {
@@ -174,6 +175,28 @@ public class UiccSlotUtil {
        performSwitchToSlot(telMgr, newUiccSlotMappings, context);
    }

    /**
     * @param context the application context.
     * @return the esim slot. If the value is -1, there is not the esim.
     */
    public static int getEsimSlotId(Context context) {
        TelephonyManager telMgr = context.getSystemService(TelephonyManager.class);
        ImmutableList<UiccSlotInfo> slotInfos = UiccSlotUtil.getSlotInfos(telMgr);
        int firstEsimSlot = IntStream.range(0, slotInfos.size())
                .filter(
                        index -> {
                            UiccSlotInfo slotInfo = slotInfos.get(index);
                            if (slotInfo == null) {
                                return false;
                            }
                            return !slotInfo.isRemovable();
                        })
                .findFirst().orElse(-1);

        Log.i(TAG, "firstEsimSlot: " + firstEsimSlot);
        return firstEsimSlot;
    }

    private static boolean isTargetSlotActive(Collection<UiccSlotMapping> uiccSlotMappings,
            int slotId, int port) {
        return uiccSlotMappings.stream()
+191 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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 com.android.settings.network;

import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.telephony.TelephonyManager;
import android.telephony.UiccPortInfo;
import android.telephony.UiccSlotInfo;

import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import com.google.common.collect.ImmutableList;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.Arrays;
import java.util.Collections;

@RunWith(AndroidJUnit4.class)
public class UiccSlotUtilTest {
    private Context mContext;
    @Mock
    private TelephonyManager mTelephonyManager;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        mContext = spy(ApplicationProvider.getApplicationContext());
        when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
    }

    @Test
    public void getSlotInfos_oneSimSlotDevice_returnTheCorrectSlotInfoList() {
        when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(oneSimSlotDevice_ActivePsim());
        ImmutableList<UiccSlotInfo> testUiccSlotInfos =
                UiccSlotUtil.getSlotInfos(mTelephonyManager);

        assertThat(testUiccSlotInfos.size()).isEqualTo(1);
    }

    @Test
    public void getSlotInfos_twoSimSlotsDevice_returnTheCorrectSlotInfoList() {
        when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
                twoSimSlotsDevice_ActivePsimActiveEsim());
        ImmutableList<UiccSlotInfo> testUiccSlotInfos =
                UiccSlotUtil.getSlotInfos(mTelephonyManager);

        assertThat(testUiccSlotInfos.size()).isEqualTo(2);
    }

    @Test
    public void getEsimSlotId_twoSimSlotsDeviceAndEsimIsSlot0_returnTheCorrectEsimSlot() {
        when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
                twoSimSlotsDevice_ActiveEsimActivePsim());
        int testSlot = UiccSlotUtil.getEsimSlotId(mContext);

        assertThat(testSlot).isEqualTo(0);
    }

    @Test
    public void getEsimSlotId_twoSimSlotsDeviceAndEsimIsSlot1_returnTheCorrectEsimSlot() {
        when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
                twoSimSlotsDevice_ActivePsimActiveEsim());
        int testSlot = UiccSlotUtil.getEsimSlotId(mContext);

        assertThat(testSlot).isEqualTo(1);
    }

    @Test
    public void getEsimSlotId_noEimSlotDevice_returnTheCorrectEsimSlot() {
        when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
                oneSimSlotDevice_ActivePsim());
        int testSlot = UiccSlotUtil.getEsimSlotId(mContext);

        assertThat(testSlot).isEqualTo(-1);
    }

    /**
     * The "oneSimSlotDevice" has below cases
     * 1) The device is one psim slot and no esim slot
     * 2) The device is no psim slot and one esim slot. like the watch.
     *
     * The "twoSimsSlotDevice" has below cases
     * 1) The device is one psim slot and one esim slot
     * 2) The device is two psim slots
     */

    private UiccSlotInfo[] oneSimSlotDevice_ActivePsim() {
        return new UiccSlotInfo[]{createUiccSlotInfo(false, true, 0, true)};
    }

    private UiccSlotInfo[] oneSimSlotDevice_ActiveEsim() {
        return new UiccSlotInfo[]{createUiccSlotInfo(true, false, 1, true)};
    }

    private UiccSlotInfo[] twoSimSlotsDevice_ActivePsimActiveEsim() {
        return new UiccSlotInfo[]{
                createUiccSlotInfo(false, true, 0, true),
                createUiccSlotInfo(true, false, 1, true)};
    }

    private UiccSlotInfo[] twoSimSlotsDevice_ActiveEsimActivePsim() {
        return new UiccSlotInfo[]{
                createUiccSlotInfo(true, false, 0, true),
                createUiccSlotInfo(false, true, 1, true)};
    }

    private UiccSlotInfo[] twoSimSlotsDevice_twoActiveEsims() {
        // device supports MEP, so device can enable two esims.
        // If device has psim slot, the UiccSlotInfo of psim always be in UiccSlotInfo[].
        return new UiccSlotInfo[]{
                createUiccSlotInfo(false, true, -1, true),
                createUiccSlotInfoForEsimMep(0, true, 1, true)};
    }

    private UiccSlotInfo[] twoSimSlotsDevice_ActivePsimInactiveEsim() {
        return new UiccSlotInfo[]{
                createUiccSlotInfo(false, true, 0, true),
                createUiccSlotInfo(true, false, -1, false)};
    }

    private UiccSlotInfo[] twoSimSlotsDevice_InactivePsimActiveEsim() {
        return new UiccSlotInfo[]{
                createUiccSlotInfo(false, true, 0, false),
                createUiccSlotInfo(true, false, 1, true)};
    }

    private UiccSlotInfo[] twoSimSlotsDevice_NoInsertPsimActiveEsim() {
        return new UiccSlotInfo[]{
                createUiccSlotInfo(false, true, -1, false),
                createUiccSlotInfo(true, false, 1, true)};
    }
    //ToDo: add more cases.

    private UiccSlotInfo createUiccSlotInfo(boolean isEuicc, boolean isRemovable,
            int logicalSlotIdx, boolean isActive) {
        return new UiccSlotInfo(
                isEuicc, /* isEuicc */
                "123", /* cardId */
                CARD_STATE_INFO_PRESENT, /* cardStateInfo */
                true, /* isExtendApduSupported */
                isRemovable, /* isRemovable */
                Collections.singletonList(
                        new UiccPortInfo("" /* iccId */, 0 /* portIdx */,
                                logicalSlotIdx /* logicalSlotIdx */, isActive /* isActive */))
        );
    }

    private UiccSlotInfo createUiccSlotInfoForEsimMep(int logicalSlotIdx1, boolean isActiveEsim1,
            int logicalSlotIdx2, boolean isActiveEsim2) {
        return new UiccSlotInfo(
                true, /* isEuicc */
                "123", /* cardId */
                CARD_STATE_INFO_PRESENT, /* cardStateInfo */
                true, /* isExtendApduSupported */
                false, /* isRemovable */
                Arrays.asList(
                        new UiccPortInfo("" /* iccId */, 0 /* portIdx */,
                                logicalSlotIdx1 /* logicalSlotIdx */, isActiveEsim1 /* isActive */),
                        new UiccPortInfo("" /* iccId */, 1 /* portIdx */,
                                logicalSlotIdx2 /* logicalSlotIdx */,
                                isActiveEsim2 /* isActive */)));
    }
}