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

Commit b9f93b22 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes from topics "MEP_addPortIndex", "mep_switchToSubscription"

* changes:
  [MEP] Add support for port index validation and resolving port index
  [MEP] EuiccManager API modifications to support carrier apps
  [MEP] Add port index in SubscriptionInfo database
parents 56bd87a3 e7cc9665
Loading
Loading
Loading
Loading
+22 −3
Original line number Diff line number Diff line
@@ -589,6 +589,8 @@ public class SubscriptionController extends ISub.Stub {
                SubscriptionManager.GROUP_UUID));
        int profileClass = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.PROFILE_CLASS));
        int portIndex = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.PORT_INDEX));
        int subType = cursor.getInt(cursor.getColumnIndexOrThrow(
                SubscriptionManager.SUBSCRIPTION_TYPE));
        String groupOwner = getOptionalStringFromCursor(cursor, SubscriptionManager.GROUP_OWNER,
@@ -606,7 +608,8 @@ public class SubscriptionController extends ISub.Stub {
                    + " countIso:" + countryIso + " isEmbedded:"
                    + isEmbedded + " accessRules:" + Arrays.toString(accessRules)
                    + " carrierConfigAccessRules: " + Arrays.toString(carrierConfigAccessRules)
                    + " cardId:" + cardIdToPrint + " publicCardId:" + publicCardId
                    + " cardId:" + cardIdToPrint + " portIndex:" + portIndex
                    + " publicCardId:" + publicCardId
                    + " isOpportunistic:" + isOpportunistic + " groupUUID:" + groupUUID
                    + " profileClass:" + profileClass + " subscriptionType: " + subType
                    + " carrierConfigAccessRules:" + carrierConfigAccessRules
@@ -622,7 +625,8 @@ public class SubscriptionController extends ISub.Stub {
                carrierName, nameSource, iconTint, number, dataRoaming, /* icon= */ null,
                mcc, mnc, countryIso, isEmbedded, accessRules, cardId, publicCardId,
                isOpportunistic, groupUUID, /* isGroupDisabled= */ false , carrierId, profileClass,
                subType, groupOwner, carrierConfigAccessRules, areUiccApplicationsEnabled);
                subType, groupOwner, carrierConfigAccessRules, areUiccApplicationsEnabled,
                portIndex);
        info.setAssociatedPlmns(ehplmns, hplmns);
        return info;
    }
@@ -1367,7 +1371,8 @@ public class SubscriptionController extends ISub.Stub {
            Cursor cursor = resolver.query(SubscriptionManager.CONTENT_URI,
                    new String[]{SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID,
                            SubscriptionManager.SIM_SLOT_INDEX, SubscriptionManager.NAME_SOURCE,
                            SubscriptionManager.ICC_ID, SubscriptionManager.CARD_ID},
                            SubscriptionManager.ICC_ID, SubscriptionManager.CARD_ID,
                            SubscriptionManager.PORT_INDEX},
                    selection, args, null);

            boolean setDisplayName = false;
@@ -1394,6 +1399,7 @@ public class SubscriptionController extends ISub.Stub {
                        int nameSource = cursor.getInt(2);
                        String oldIccId = cursor.getString(3);
                        String oldCardId = cursor.getString(4);
                        int oldPortIndex = cursor.getInt(5);
                        ContentValues value = new ContentValues();

                        if (slotIndex != oldSimInfoId) {
@@ -1413,6 +1419,15 @@ public class SubscriptionController extends ISub.Stub {
                            }
                        }

                        //update portIndex for pSim
                        UiccSlot slot = mUiccController.getUiccSlotForPhone(slotIndex);
                        if (slot != null && !slot.isEuicc()) {
                            int portIndex = slot.getPortIndexFromIccId(uniqueId);
                            if (portIndex != oldPortIndex) {
                                value.put(SubscriptionManager.PORT_INDEX, portIndex);
                            }
                        }

                        if (value.size() > 0) {
                            resolver.update(SubscriptionManager.getUriForSubscriptionId(subId),
                                    value, null, null);
@@ -1730,6 +1745,10 @@ public class SubscriptionController extends ISub.Stub {
                    value.put(SubscriptionManager.CARD_ID, cardId);
                }
            }
            UiccSlot slot = mUiccController.getUiccSlotForPhone(slotIndex);
            if (slot != null) {
                value.put(SubscriptionManager.PORT_INDEX, slot.getPortIndexFromIccId(uniqueId));
            }
        }
        value.put(SubscriptionManager.ALLOWED_NETWORK_TYPES,
                "user=" + RadioAccessFamily.getRafFromNetworkType(
+18 −1
Original line number Diff line number Diff line
@@ -65,8 +65,10 @@ import com.android.telephony.Rlog;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;

/**
 *@hide
@@ -698,8 +700,12 @@ public class SubscriptionInfoUpdater extends Handler {
            }
            String iccId = sInactiveIccIds[phoneId] != null
                    ? sInactiveIccIds[phoneId] : sIccId[phoneId];
            ContentValues value = new ContentValues(1);
            ContentValues value = new ContentValues();
            value.put(SubscriptionManager.UICC_APPLICATIONS_ENABLED, true);
            if (isSimAbsent) {
                // When sim is absent, set the port index to invalid port index -1;
                value.put(SubscriptionManager.PORT_INDEX, TelephonyManager.INVALID_PORT_INDEX);
            }
            sContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, value,
                    SubscriptionManager.ICC_ID + "=\'" + iccId + "\'", null);
            sInactiveIccIds[phoneId] = null;
@@ -982,6 +988,8 @@ public class SubscriptionInfoUpdater extends Handler {
                        SubscriptionManager.NAME_SOURCE_CARRIER);
            }
            values.put(SubscriptionManager.PROFILE_CLASS, embeddedProfile.getProfileClass());
            values.put(SubscriptionManager.PORT_INDEX,
                    getEmbeddedProfilePortIndex(embeddedProfile.getIccid()));
            CarrierIdentifier cid = embeddedProfile.getCarrierIdentifier();
            if (cid != null) {
                // Due to the limited subscription information, carrier id identified here might
@@ -1046,6 +1054,15 @@ public class SubscriptionInfoUpdater extends Handler {
        return hasChanges;
    }

    private int getEmbeddedProfilePortIndex(String iccId) {
        UiccSlot[] slots = UiccController.getInstance().getUiccSlots();
        for (UiccSlot slot : slots) {
            if (slot != null && slot.isEuicc() && slot.isIccIdMappedToPortIndex(iccId)) {
                return slot.getPortIndexFromIccId(iccId);
            }
        }
        return TelephonyManager.INVALID_PORT_INDEX;
    }
    /**
     * Called by CarrierConfigLoader to update the subscription before sending a broadcast.
     */
+225 −13
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ import com.android.internal.telephony.SubscriptionController;
import com.android.internal.telephony.euicc.EuiccConnector.OtaStatusChangedCallback;
import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.telephony.uicc.UiccPort;
import com.android.internal.telephony.uicc.UiccSlot;
import com.android.internal.telephony.util.ArrayUtils;

import java.io.FileDescriptor;
@@ -180,12 +181,11 @@ public class EuiccController extends IEuiccController.Stub {
            PendingIntent callbackIntent =
                    resolutionIntent.getParcelableExtra(
                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT);
            int portIndex = resolutionIntent.getIntExtra(
                    EuiccService.EXTRA_RESOLUTION_PORT_INDEX, 0);
            resolutionExtras.putInt(EuiccService.EXTRA_RESOLUTION_PORT_INDEX, portIndex);
            boolean usePortIndex = resolutionIntent.getBooleanExtra(
                    EuiccService.EXTRA_RESOLUTION_USE_PORT_INDEX, false);
            resolutionExtras.putBoolean(EuiccService.EXTRA_RESOLUTION_USE_PORT_INDEX, usePortIndex);
            Log.i(TAG, " continueOperation portIndex: " + resolutionExtras.getInt(
                    EuiccService.EXTRA_RESOLUTION_PORT_INDEX) + " usePortIndex: " + usePortIndex);
            op.continueOperation(cardId, resolutionExtras, callbackIntent);
        } finally {
            Binder.restoreCallingIdentity(token);
@@ -211,7 +211,8 @@ public class EuiccController extends IEuiccController.Stub {
        long token = Binder.clearCallingIdentity();
        try {
            if (!callerCanReadPhoneStatePrivileged
                    && !canManageSubscriptionOnTargetSim(cardId, callingPackage)) {
                    && !canManageSubscriptionOnTargetSim(cardId, callingPackage, false,
                    TelephonyManager.INVALID_PORT_INDEX)) {
                throw new SecurityException(
                        "Must have carrier privileges on subscription to read EID for cardId="
                                + cardId);
@@ -564,7 +565,8 @@ public class EuiccController extends IEuiccController.Stub {
            // Otherwise, the user must provide consent. If it's a single-active SIM device,
            // determine whether the caller can manage the current profile; if so, we can perform
            // the download silently; if not, the user must provide consent.
            if (canManageSubscriptionOnTargetSim(cardId, callingPackage)) {
            if (canManageSubscriptionOnTargetSim(cardId, callingPackage, false,
                    TelephonyManager.INVALID_PORT_INDEX)) {
                mConnector.getDownloadableSubscriptionMetadata(cardId, subscription,
                    forceDeactivateSim,
                    new DownloadSubscriptionGetMetadataCommandCallback(token, subscription,
@@ -994,11 +996,22 @@ public class EuiccController extends IEuiccController.Stub {
                forceDeactivateSim = true;
            }

            // if the caller is not privileged caller and does not have the carrier privilege over
            // any active subscription, do not continue.
            if (!callerCanWriteEmbeddedSubscriptions && usePortIndex
                    && (mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
                    != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS)) {
                Log.e(TAG, "Not permitted to use switchToSubscription with portIndex");
                throw new SecurityException(
                        "Must have carrier privileges to use switchToSubscription with portIndex");
            }
            final String iccid;
            boolean passConsent = false;
            boolean isConsentNeededToResolvePortIndex = false;
            if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
                if (callerCanWriteEmbeddedSubscriptions
                        || canManageActiveSubscriptionOnTargetSim(cardId, callingPackage)) {
                        || canManageActiveSubscriptionOnTargetSim(cardId, callingPackage,
                        usePortIndex, portIndex)) {
                    passConsent = true;
                } else {
                    Log.e(TAG, "Not permitted to switch to empty subscription");
@@ -1022,14 +1035,34 @@ public class EuiccController extends IEuiccController.Stub {
                        return;
                    }

                    if (canManageSubscriptionOnTargetSim(cardId, callingPackage)) {
                    if (canManageSubscriptionOnTargetSim(cardId, callingPackage, usePortIndex,
                            portIndex)) {
                        passConsent = true;
                    }
                }
                iccid = sub.getIccId();
                if (usePortIndex) {
                    boolean hasValidPortIndex = isTargetPortIndexValid(cardId, portIndex);
                    if (!hasValidPortIndex) {
                        // Return permanent error.
                        Log.e(TAG, "Not permitted to switch to invalid portIndex");
                        Intent extrasIntent = new Intent();
                        extrasIntent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE,
                                EuiccManager.ERROR_INVALID_PORT);
                        sendResult(callbackIntent, ERROR, extrasIntent /* extrasIntent */);
                        return;
                    }

            if (!passConsent) {
                } else {
                    // Resolve the portIndex internally if apps are calling switchToSubscription
                    // API without portIndex.
                    portIndex = getResolvedPortIndexForSubscriptionSwitch(cardId);
                    isConsentNeededToResolvePortIndex = (portIndex
                            == TelephonyManager.INVALID_PORT_INDEX);
                    usePortIndex = true;
                    Log.d(TAG, " Resolved portIndex: " + portIndex);
                }
            }
            if (!passConsent || isConsentNeededToResolvePortIndex) {
                // Switch needs consent.
                Intent extrasIntent = new Intent();
                addResolutionIntent(extrasIntent,
@@ -1051,6 +1084,171 @@ public class EuiccController extends IEuiccController.Stub {
        }
    }

    /**
     * Returns the resolved portIndex or {@link TelephonyManager#INVALID_PORT_INDEX} if no port
     * is available without user consent.
     */
    private int getResolvedPortIndexForSubscriptionSwitch(int cardId) {
        int slotIndex = getSlotIndexFromCardId(cardId);
        // Euicc Slot
        UiccSlot slot = UiccController.getInstance().getUiccSlot(slotIndex);
        if (!slot.isMultipleEnabledProfileSupported()) {
            Log.d(TAG, "Multiple enabled profiles is not supported, return default port index");
            return TelephonyManager.DEFAULT_PORT_INDEX;
        }
        boolean isPsimHasActiveSub = isRemovalNonEuiccSlotHasActiveSubscription();
        if (mTelephonyManager.getActiveModemCount() == 1) {
            // SS Mode
            if (isPsimHasActiveSub) {
                // In case of SS Mode and pSim has active subscription, return default port index
                // for two reasons.
                // 1. If psim and esim share the same carrier privilege, then users wouldn't need
                // to consent, the switch should be seamless.
                // 2. If psim and esim doesn't share the same carrier privilege, then permission
                // check dialog will be shown anyway.
                return TelephonyManager.DEFAULT_PORT_INDEX;
            }
            // If esim port is active, return the active portIndex irrespective of whether port is
            // empty or has active subscription.
            for (int portIndex : slot.getPortList()) {
                if (slot.isPortActive(portIndex)) {
                    return portIndex;
                }
            }
        } else {
            // DSDS Mode
            for (int portIndex : slot.getPortList()) {
                if (slot.isPortActive(portIndex)
                        && mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(
                        slot.getPhoneIdFromPortIndex(portIndex)) == null) {
                    // If the port is active and empty, return the portIndex.
                    return portIndex;
                }
            }
            // Check whether the pSim is active and empty
            boolean isPsimEmpty = getRemovableNonEuiccSlot() != null
                    && getRemovableNonEuiccSlot().isActive()
                    && !isPsimHasActiveSub;
            if (isPsimEmpty) {
                // This logic will execute only if below two conditions are true.
                // 1. pSim is active and empty
                // 2. eSim has active subscription
                // Return the next available inactive eSim portIndex.
                return getNextAvailableInActivePortIndex(slot);
            }
        }
        return TelephonyManager.INVALID_PORT_INDEX;
    }

    /**
     * Returns true if the target port index is valid.
     * 1. Port index is valid if it is non-negative and less than the total port count.
     * 2. In SS Mode, port index is invalid if the embedded slot already has an active empty port
     * with different port index than the target port index.
     * 3. In DSDS mode, port index is invalid if the pSim slot is active and the embedded slot
     * already has an active empty port with different port index than the target port index.
     */
    private boolean isTargetPortIndexValid(int cardId, int targetPortIndex) {
        if (targetPortIndex < 0) {
            Log.e(TAG, "Invalid portIndex: " + targetPortIndex);
            return false;
        }
        int slotIndex = getSlotIndexFromCardId(cardId);
        UiccSlot slot = UiccController.getInstance().getUiccSlot(slotIndex);
        if (slot == null || slot.getPortList().length == 0
                || targetPortIndex >= slot.getPortList().length) {
            Log.e(TAG, "Invalid portIndex");
            return false;
        }

        if (mTelephonyManager.getActiveModemCount() == 1) {
            // SS Mode
            for (int portIndex : slot.getPortList()) {
                if (slot.isPortActive(portIndex) && portIndex != targetPortIndex) {
                    // if there is an active esim port, should not try to enable the
                    // profile on other inactive port.
                    Log.e(TAG, "In SS Mode, slot already has active port on portIndex " + portIndex
                            + " , reject the switch request to portIndex " + targetPortIndex);
                    return false;
                }
            }
        } else if (mTelephonyManager.getActiveModemCount() > 1) {
            // DSDS Mode
            // If physical slot has active subscription and eSim has active port (without active
            // subscription), should not try to enable the profile on other inactive port.
            boolean isPsimActive = isRemovalNonEuiccSlotHasActiveSubscription();
            if (isPsimActive) {
                for (int portIndex : slot.getPortList()) {
                    if (slot.isPortActive(portIndex)
                            && mSubscriptionManager
                            .getActiveSubscriptionInfoForSimSlotIndex(
                                    slot.getPhoneIdFromPortIndex(portIndex)) == null
                            && portIndex != targetPortIndex) {
                        Log.e(TAG, "In DSDS Mode, pSim has active subscription, eSim has empty"
                                + " active port on portIndex " + portIndex
                                + " , reject the switch request to portIndex " + targetPortIndex);
                        return false;
                    }
                }
            }
        }
        return true;
    }

    private int getNextAvailableInActivePortIndex(UiccSlot slot) {
        if (slot != null) {
            for (int portIndex : slot.getPortList()) {
                if (!slot.isPortActive(portIndex)) {
                    return portIndex;
                }
            }
        }
        return TelephonyManager.INVALID_PORT_INDEX;
    }

    /**
     * Gets the slot index from the card ID.
     */
    private int getSlotIndexFromCardId(int cardId) {
        List<UiccCardInfo> infos = mTelephonyManager.getUiccCardsInfo();
        if (infos == null || infos.size() == 0) {
            return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
        }
        for (UiccCardInfo info : infos) {
            if (info.getCardId() == cardId) {
                return info.getPhysicalSlotIndex();
            }
        }
        return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
    }

    private boolean isRemovalNonEuiccSlotHasActiveSubscription() {
        UiccSlot uiccSlot = getRemovableNonEuiccSlot();
        if (uiccSlot != null) {
            for (int portIndex : uiccSlot.getPortList()) {
                if (uiccSlot.isPortActive(portIndex)
                        && mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(
                                uiccSlot.getPhoneIdFromPortIndex(portIndex)) != null) {
                    return true;
                }
            }
        }
        return false;
    }

    private UiccSlot getRemovableNonEuiccSlot() {
        UiccSlot[] uiccSlots = UiccController.getInstance().getUiccSlots();
        if (uiccSlots != null) {
            for (int i = 0; i < uiccSlots.length; i++) {
                if (uiccSlots[i] != null && uiccSlots[i].isRemovable()
                        && !uiccSlots[i].isEuicc()) {
                    return uiccSlots[i];
                }
            }
        }
        return null;
    }

    void switchToSubscriptionPrivileged(int cardId, int portIndex, final long callingToken,
            int subscriptionId, boolean forceDeactivateSim, final String callingPackage,
            final PendingIntent callbackIntent, boolean usePortIndex) {
@@ -1503,7 +1701,10 @@ public class EuiccController extends IEuiccController.Stub {

    // Checks whether the caller can manage the active embedded subscription on the SIM with the
    // given cardId.
    private boolean canManageActiveSubscriptionOnTargetSim(int cardId, String callingPackage) {
    // From Android T, if usePortIndex is true then should check if the calling app has carrier
    // privilege over the subscription on the target port index.
    private boolean canManageActiveSubscriptionOnTargetSim(int cardId, String callingPackage,
            boolean usePortIndex, int targetPortIndex) {
        List<SubscriptionInfo> subInfoList = mSubscriptionManager
                .getActiveSubscriptionInfoList(/* userVisibleOnly */false);
        if (subInfoList == null || subInfoList.size() == 0) {
@@ -1517,6 +1718,7 @@ public class EuiccController extends IEuiccController.Stub {
            // subscription on any eSIM. That's the best we can do here.
            if ((cardId == TelephonyManager.UNSUPPORTED_CARD_ID || subInfo.getCardId() == cardId)
                    && subInfo.isEmbedded()
                    && (!usePortIndex || subInfo.getPortIndex() == targetPortIndex)
                    && mSubscriptionManager.canManageSubscription(subInfo, callingPackage)) {
                return true;
            }
@@ -1531,7 +1733,10 @@ public class EuiccController extends IEuiccController.Stub {
    // other SIM. The target SIM should be an eUICC.
    // For a single-active subscription phone, checks whether the caller can manage any active
    // embedded subscription.
    private boolean canManageSubscriptionOnTargetSim(int cardId, String callingPackage) {
    // From Android T, If embedded slot supports Multiple Enabled Profiles then should check if
    // the calling app has carrier privilege over the subscription on the target port index.
    private boolean canManageSubscriptionOnTargetSim(int cardId, String callingPackage,
            boolean usePortIndex, int targetPortIndex) {
        List<SubscriptionInfo> subInfoList = mSubscriptionManager
                .getActiveSubscriptionInfoList(false /* userVisibleonly */);
        // No active subscription on any SIM.
@@ -1549,9 +1754,11 @@ public class EuiccController extends IEuiccController.Stub {
                return false;
            }
            boolean isEuicc = false;
            boolean isMultipleEnabledProfilesSupported = false;
            for (UiccCardInfo info : cardInfos) {
                if (info != null && info.getCardId() == cardId && info.isEuicc()) {
                    isEuicc = true;
                    isMultipleEnabledProfilesSupported = info.isMultipleEnabledProfilesSupported();
                    break;
                }
            }
@@ -1564,8 +1771,13 @@ public class EuiccController extends IEuiccController.Stub {
            // false. If the caller can manage the active embedded subscription on the target SIM,
            // return true directly.
            for (SubscriptionInfo subInfo : subInfoList) {
                // subInfo.isEmbedded() can only be true for the target SIM.
                if (subInfo.isEmbedded() && subInfo.getCardId() == cardId) {
                // 1. subInfo.isEmbedded() can only be true for the target SIM.
                // 2. Check whether the caller can manage subscription on the target portIndex
                // (i.e. subInfo.getPortIndex() == targetPortIndex condition) only in case if
                // isMultipleEnabledProfilesSupported and usePortIndex both are true.
                if (subInfo.isEmbedded() && subInfo.getCardId() == cardId
                        && (!isMultipleEnabledProfilesSupported || !usePortIndex
                        || subInfo.getPortIndex() == targetPortIndex)) {
                    return mSubscriptionManager.canManageSubscription(subInfo, callingPackage);
                }
            }
+18 −0
Original line number Diff line number Diff line
@@ -241,6 +241,24 @@ public class UiccSlot extends Handler {
        }
    }

    public boolean isIccIdMappedToPortIndex(String iccId) {
        synchronized (mLock) {
            return mIccIds.containsValue(iccId);
        }
    }

    public int getPortIndexFromIccId(String iccId) {
        synchronized (mLock) {
            for (Map.Entry<Integer, String> entry : mIccIds.entrySet()) {
                if (entry.getValue().equalsIgnoreCase(iccId)) {
                    return entry.getKey();
                }
            }
            // If iccId is not found, return invalid port index.
            return TelephonyManager.INVALID_PORT_INDEX;
        }
    }

    public int getPhoneIdFromPortIndex(int portIndex) {
        synchronized (mLock) {
            return mPortIdxToPhoneId.getOrDefault(portIndex, INVALID_PHONE_ID);
+2 −1
Original line number Diff line number Diff line
@@ -118,7 +118,8 @@ public class FakeTelephonyProvider extends MockContentProvider {
                    + Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS + " TEXT,"
                    + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING + " INTEGER DEFAULT 0,"
                    + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS + "TEXT,"
                    + Telephony.SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED + " INTEGER DEFAULT -1"
                    + Telephony.SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED + " INTEGER DEFAULT -1,"
                    + Telephony.SimInfo.COLUMN_PORT_INDEX + " INTEGER DEFAULT -1"
                    + ");";
        }

Loading