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

Commit 43f9aee4 authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "Add USSD codes over IMS feature" am: 3e6b6829

Change-Id: Ibf43ee6f45484950b5cc3032b12a7123f28072de
parents 91d9579e 3e6b6829
Loading
Loading
Loading
Loading
+18 −9
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ import com.android.internal.telephony.uicc.UiccProfile;
import com.android.internal.telephony.uicc.UiccSlot;
import com.android.internal.telephony.util.ArrayUtils;
import com.android.telephony.Rlog;
import com.android.internal.telephony.imsphone.ImsPhoneMmiCode;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -1278,9 +1279,6 @@ public class GsmCdmaPhone extends Phone {
        boolean allowWpsOverIms = configManager.getConfigForSubId(getSubId())
                .getBoolean(CarrierConfigManager.KEY_SUPPORT_WPS_OVER_IMS_BOOL);

        boolean useImsForCall = useImsForCall(dialArgs)
                 && (isWpsCall ? allowWpsOverIms : true);

        boolean useImsForEmergency = imsPhone != null
                && isEmergency
                && alwaysTryImsForEmergencyCarrierConfig
@@ -1289,16 +1287,21 @@ public class GsmCdmaPhone extends Phone {

        String dialPart = PhoneNumberUtils.extractNetworkPortionAlt(PhoneNumberUtils.
                stripSeparators(dialString));
        boolean isUt = (dialPart.startsWith("*") || dialPart.startsWith("#"))
        boolean isMmiCode = (dialPart.startsWith("*") || dialPart.startsWith("#"))
                && dialPart.endsWith("#");

        boolean isSuppServiceCode = ImsPhoneMmiCode.isSuppServiceCodes(dialPart, this);
        boolean isPotentialUssdCode = isMmiCode && !isSuppServiceCode;
        boolean useImsForUt = imsPhone != null && imsPhone.isUtEnabled();
        boolean useImsForCall = useImsForCall(dialArgs)
                && (isWpsCall ? allowWpsOverIms : true);

        if (DBG) {
            logd("useImsForCall=" + useImsForCall
                    + ", useImsForEmergency=" + useImsForEmergency
                    + ", useImsForUt=" + useImsForUt
                    + ", isUt=" + isUt
                    + ", isUt=" + isMmiCode
                    + ", isSuppServiceCode=" + isSuppServiceCode
                    + ", isPotentialUssdCode=" + isPotentialUssdCode
                    + ", isWpsCall=" + isWpsCall
                    + ", allowWpsOverIms=" + allowWpsOverIms
                    + ", imsPhone=" + imsPhone
@@ -1314,7 +1317,9 @@ public class GsmCdmaPhone extends Phone {

        Phone.checkWfcWifiOnlyModeBeforeDial(mImsPhone, mPhoneId, mContext);

        if ((useImsForCall && !isUt) || (isUt && useImsForUt) || useImsForEmergency) {
        if ((useImsForCall && (!isMmiCode || isPotentialUssdCode))
                || (isMmiCode && useImsForUt)
                || useImsForEmergency) {
            try {
                if (DBG) logd("Trying IMS PS call");
                return imsPhone.dial(dialString, dialArgs);
@@ -1343,7 +1348,9 @@ public class GsmCdmaPhone extends Phone {
        if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_POWER_OFF /* CS POWER_OFF */
                && !VideoProfile.isVideo(dialArgs.videoState) /* voice call */
                && !isEmergency /* non-emergency call */
                && !(isUt && useImsForUt) /* not UT */) {
                && !(isMmiCode && useImsForUt) /* not UT */
                /* If config_allow_ussd_over_ims is false, USSD is sent over the CS pipe instead */
                && !isPotentialUssdCode) {
            throw new CallStateException(
                CallStateException.ERROR_POWER_OFF,
                "cannot dial voice call in airplane mode");
@@ -1356,7 +1363,9 @@ public class GsmCdmaPhone extends Phone {
                && ServiceState.isPsOnlyTech(
                        mSST.mSS.getRilDataRadioTechnology())) /* PS not in LTE/NR */
                && !VideoProfile.isVideo(dialArgs.videoState) /* voice call */
                && !isEmergency /* non-emergency call */) {
                && !isEmergency /* non-emergency call */
                /* If config_allow_ussd_over_ims is false, USSD is sent over the CS pipe instead */
                && !isPotentialUssdCode) {
            throw new CallStateException(
                CallStateException.ERROR_OUT_OF_SERVICE,
                "cannot dial voice call in out of service");
+79 −7
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.internal.telephony.imsphone;

import static android.telephony.ServiceState.STATE_IN_SERVICE;

import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_DATA;
import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_DATA_ASYNC;
import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_DATA_SYNC;
@@ -478,6 +480,60 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode {
        return false;
    }

    static boolean isPinPukCommand(String sc) {
        return sc != null && (sc.equals(SC_PIN) || sc.equals(SC_PIN2)
                || sc.equals(SC_PUK) || sc.equals(SC_PUK2));
    }

    /**
     * Whether the dial string is supplementary service code.
     *
     * @param dialString The dial string.
     * @return true if the dial string is supplementary service code, and {@code false} otherwise.
     */
    public static boolean isSuppServiceCodes(String dialString, Phone phone) {
        if (phone != null && phone.getServiceState().getVoiceRoaming()
                && phone.getDefaultPhone().supportsConversionOfCdmaCallerIdMmiCodesWhileRoaming()) {
            /* The CDMA MMI coded dialString will be converted to a 3GPP MMI Coded dialString
               so that it can be processed by the matcher and code below
             */
            dialString = convertCdmaMmiCodesTo3gppMmiCodes(dialString);
        }

        Matcher m = sPatternSuppService.matcher(dialString);
        if (m.matches()) {
            String sc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE));
            if (isServiceCodeCallForwarding(sc)) {
                return true;
            } else if (isServiceCodeCallBarring(sc)) {
                return true;
            } else if (sc != null && sc.equals(SC_CFUT)) {
                return true;
            } else if (sc != null && sc.equals(SC_CLIP)) {
                return true;
            } else if (sc != null && sc.equals(SC_CLIR)) {
                return true;
            } else if (sc != null && sc.equals(SC_COLP)) {
                return true;
            } else if (sc != null && sc.equals(SC_COLR)) {
                return true;
            } else if (sc != null && sc.equals(SC_CNAP)) {
                return true;
            } else if (sc != null && sc.equals(SC_BS_MT)) {
                return true;
            } else if (sc != null && sc.equals(SC_BAICa)) {
                return true;
            } else if (sc != null && sc.equals(SC_PWD)) {
                return true;
            } else if (sc != null && sc.equals(SC_WAIT)) {
                return true;
            } else if (isPinPukCommand(sc)) {
                return true;
            }
        }
        return false;
    }

    static String
    scToBarringFacility(String sc) {
        if (sc == null) {
@@ -665,8 +721,7 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode {
     * @return true if the Service Code is PIN/PIN2/PUK/PUK2-related
     */
    public boolean isPinPukCommand() {
        return mSc != null && (mSc.equals(SC_PIN) || mSc.equals(SC_PIN2)
                              || mSc.equals(SC_PUK) || mSc.equals(SC_PUK2));
        return isPinPukCommand(mSc);
    }

    /**
@@ -1021,11 +1076,28 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode {
                    throw new RuntimeException ("Invalid or Unsupported MMI Code");
                }
            } else if (mPoundString != null) {
                // USSD codes are not supported over IMS due to modem limitations; send over the CS
                // pipe instead.  This should be fixed in the future.
                if (mContext.getResources().getBoolean(
                        com.android.internal.R.bool.config_allow_ussd_over_ims)) {
                    // We'll normally send USSD over the CS pipe, but if it happens that
                    // the CS phone is out of service, we'll just try over IMS instead.
                    if (mPhone.getDefaultPhone().getServiceStateTracker().mSS.getState()
                            == STATE_IN_SERVICE) {
                        Rlog.i(LOG_TAG, "processCode: Sending ussd string '"
                                + Rlog.pii(LOG_TAG, mPoundString) + "' over CS pipe "
                                + "(allowed over ims).");
                        throw new CallStateException(Phone.CS_FALLBACK);
                    } else {
                        Rlog.i(LOG_TAG, "processCode: CS is out of service, sending ussd string '"
                                + Rlog.pii(LOG_TAG, mPoundString) + "' over IMS pipe.");
                        sendUssd(mPoundString);
                    }
                } else {
                    // USSD codes are not supported over IMS due to modem limitations; send over
                    // the CS pipe instead.  This should be fixed in the future.
                    Rlog.i(LOG_TAG, "processCode: Sending ussd string '"
                            + Rlog.pii(LOG_TAG, mPoundString) + "' over CS pipe.");
                    throw new CallStateException(Phone.CS_FALLBACK);
                }
            } else {
                Rlog.d(LOG_TAG, "processCode: invalid or unsupported MMI");
                throw new RuntimeException ("Invalid or Unsupported MMI Code");
+73 −1
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
@@ -53,6 +54,7 @@ import android.os.Message;
import android.os.Process;
import android.os.WorkSource;
import android.preference.PreferenceManager;
import android.telecom.VideoProfile;
import android.telephony.AccessNetworkConstants;
import android.telephony.CarrierConfigManager;
import android.telephony.CellIdentity;
@@ -471,7 +473,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest {

    @Test
    @SmallTest
    public void testDial() {
    public void testDial() throws Exception {
        try {
            mSST.mSS = mServiceState;
            doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState();
@@ -481,6 +483,8 @@ public class GsmCdmaPhoneTest extends TelephonyTest {
            mCT.mRingingCall = mGsmCdmaCall;
            doReturn(GsmCdmaCall.State.IDLE).when(mGsmCdmaCall).getState();

            replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone);

            Connection connection = mPhoneUT.dial("1234567890",
                    new PhoneInternalInterface.DialArgs.Builder().build());
            verify(mCT).dialGsm("1234567890", null, null);
@@ -1337,4 +1341,72 @@ public class GsmCdmaPhoneTest extends TelephonyTest {
//        processAllMessages();
//        verify(mMockCi, never()).enableUiccApplications(eq(true), messageCaptor.capture());
//    }

    @Test
    @SmallTest
    public void testSendUssdInService() throws Exception {
        PhoneInternalInterface.DialArgs dialArgs = new PhoneInternalInterface.DialArgs
                .Builder().setVideoState(VideoProfile.STATE_AUDIO_ONLY).build();

        setupTestSendUssd(dialArgs);

        // ServiceState is in service.
        doReturn(ServiceState.STATE_IN_SERVICE).when(mSST.mSS).getState();
        mPhoneUT.dial("*135#", dialArgs);
        verify(mMockCi).sendUSSD(eq("*135#"), any());
    }

    @Test
    @SmallTest
    public void testSendUssdInOutOfService() throws Exception {
        PhoneInternalInterface.DialArgs dialArgs = new PhoneInternalInterface.DialArgs
                .Builder().setVideoState(VideoProfile.STATE_AUDIO_ONLY).build();

        setupTestSendUssd(dialArgs);

        // ServiceState is out of service
        doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mSST.mSS)
                .getState(); /* CS out of service */
        doReturn(ServiceState.STATE_IN_SERVICE).when(mSST.mSS).getDataRegState();
        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_GSM).when(mSST.mSS)
                .getRilDataRadioTechnology(); /* PS not in LTE */
        mPhoneUT.dial("*135#", dialArgs);
        verify(mMockCi).sendUSSD(eq("*135#"), any());
    }

    @Test
    @SmallTest
    public void testSendUssdInAirplaneMode() throws Exception {
        PhoneInternalInterface.DialArgs dialArgs = new PhoneInternalInterface.DialArgs
                .Builder().setVideoState(VideoProfile.STATE_AUDIO_ONLY).build();

        setupTestSendUssd(dialArgs);

        // ServiceState is airplane mode.
        doReturn(ServiceState.STATE_POWER_OFF).when(mSST.mSS).getState(); /* CS POWER_OFF */
        mPhoneUT.dial("*135#", dialArgs);
        verify(mMockCi).sendUSSD(eq("*135#"), any());
    }

    private void setupTestSendUssd(PhoneInternalInterface.DialArgs dialArgs) throws Exception {
        mPhoneUT.mCi = mMockCi;
        ServiceState mImsServiceState = Mockito.mock(ServiceState.class);
        CallStateException callStateException = Mockito.mock(CallStateException.class);

        // Enable VoWiFi
        doReturn(true).when(mImsManager).isVolteEnabledByPlatform();
        doReturn(true).when(mImsManager).isEnhanced4gLteModeSettingEnabledByUser();
        doReturn(mImsServiceState).when(mImsPhone).getServiceState();
        doReturn(ServiceState.STATE_IN_SERVICE).when(mImsServiceState).getState();
        doReturn(true).when(mImsPhone).isWifiCallingEnabled();

        // Disable UT/XCAP
        doReturn(false).when(mImsPhone).isUtEnabled();

        // Throw CallStateException(Phone.CS_FALLBACK) from ImsPhone.dial().
        doReturn(Phone.CS_FALLBACK).when(callStateException).getMessage();
        doThrow(callStateException).when(mImsPhone).dial("*135#", dialArgs);

        replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone);
    }
}
+49 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import android.app.IApplicationThread;
import android.content.BroadcastReceiver;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.res.Resources;
import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Handler;
@@ -845,6 +846,54 @@ public class ImsPhoneTest extends TelephonyTest {
        assertNotNull(mImsPhoneUT.getServiceStateTracker());
    }

    @Test
    @SmallTest
    public void testSendUssdAllowUssdOverImsInOutOfService() throws Exception {
        Resources resources = mContext.getResources();

        doReturn(true).when(resources).getBoolean(
                com.android.internal.R.bool.config_allow_ussd_over_ims);
        doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mSST.mSS).getState();

        mImsPhoneUT.dial("*135#", new ImsPhone.ImsDialArgs.Builder().build());
        verify(mImsCT).sendUSSD(eq("*135#"), any());
    }

    @Test
    @SmallTest
    public void testSendUssdAllowUssdOverImsInService() throws Exception {
        String errorCode = "";
        Resources resources = mContext.getResources();

        doReturn(true).when(resources).getBoolean(
                com.android.internal.R.bool.config_allow_ussd_over_ims);
        doReturn(ServiceState.STATE_IN_SERVICE).when(mSST.mSS).getState();

        try {
            mImsPhoneUT.dial("*135#", new ImsPhone.ImsDialArgs.Builder().build());
        } catch (CallStateException e) {
            errorCode = e.getMessage();
        }
        assertEquals(Phone.CS_FALLBACK, errorCode);
    }

    @Test
    @SmallTest
    public void testSendUssdNotAllowUssdOverIms() throws Exception {
        String errorCode = "";
        Resources resources = mContext.getResources();

        doReturn(false).when(resources).getBoolean(
                com.android.internal.R.bool.config_allow_ussd_over_ims);

        try {
            mImsPhoneUT.dial("*135#", new ImsPhone.ImsDialArgs.Builder().build());
        } catch (CallStateException e) {
            errorCode = e.getMessage();
        }
        assertEquals(Phone.CS_FALLBACK, errorCode);
    }

    private ServiceState getServiceStateDataAndVoice(int rat, int regState, boolean isRoaming) {
        ServiceState ss = new ServiceState();
        ss.setStateOutOfService();