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

Commit 02de5290 authored by Thomas Stuart's avatar Thomas Stuart
Browse files

route dial out strings to the same number based on service state

VZ network noticed that 611 and *611 were dialing different
numbers that are meant for IVR when the phone service state
was the same(e.g ROMAING_DOMESTIC).  This is not the intended
behavior and the dial out string should be routed to the same
number remapping which is based on the service state. Dialer
handled this before but at some point stoppped.

A new carrier config bundle has been added to account for the
service state ROAMING_TYPE_INTERNATIONAL.

bug: 211116126
Test: 2 unit tests,
      manually tested by
          (1) setting the phone service state to roaming
	  (2) setting carrier config bundles
	  (3) overriding the country code (spoof location)
	  (4) placing calls and asserting the
	      correct devices were called (based on service state)
Change-Id: Ie65d837da9c169e1a9986e147222885909662344
parent 877810fc
Loading
Loading
Loading
Loading
+30 −2
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
import android.text.TextUtils;
import android.text.TextUtils;


import java.io.FileDescriptor;
import java.io.FileDescriptor;
@@ -177,8 +178,11 @@ public abstract class CallTracker extends Handler {
                phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
                phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
        PersistableBundle bundle = configManager.getConfigForSubId(phone.getSubId());
        PersistableBundle bundle = configManager.getConfigForSubId(phone.getSubId());
        if (bundle != null) {
        if (bundle != null) {
            convertMaps =
            convertMaps = (shouldPerformInternationalNumberRemapping(phone, bundle))
                    bundle.getStringArray(CarrierConfigManager.KEY_DIAL_STRING_REPLACE_STRING_ARRAY);
                    ? bundle.getStringArray(CarrierConfigManager
                            .KEY_INTERNATIONAL_ROAMING_DIAL_STRING_REPLACE_STRING_ARRAY)
                    : bundle.getStringArray(CarrierConfigManager
                            .KEY_DIAL_STRING_REPLACE_STRING_ARRAY);
        }
        }
        if (convertMaps == null) {
        if (convertMaps == null) {
            // By default no replacement is necessary
            // By default no replacement is necessary
@@ -233,6 +237,30 @@ public abstract class CallTracker extends Handler {


    }
    }


    /**
     * Helper function to determine if the phones service is in ROAMING_TYPE_INTERNATIONAL.
     * @param phone object that contains the service state.
     * @param bundle object that contains the bundle with mapped dial strings.
     * @return  true if the phone is in roaming state with a set bundle. Otherwise, false.
     */
    private boolean shouldPerformInternationalNumberRemapping(Phone phone,
            PersistableBundle bundle) {
        if (phone == null || phone.getDefaultPhone() == null) {
            log("shouldPerformInternationalNumberRemapping: phone was null");
            return false;
        }

        if (bundle.getStringArray(CarrierConfigManager
                .KEY_INTERNATIONAL_ROAMING_DIAL_STRING_REPLACE_STRING_ARRAY) == null) {
            log("shouldPerformInternationalNumberRemapping: did not set the "
                    + "KEY_INTERNATIONAL_ROAMING_DIAL_STRING_REPLACE_STRING_ARRAY");
            return false;
        }

        return phone.getDefaultPhone().getServiceState().getVoiceRoamingType()
                == ServiceState.ROAMING_TYPE_INTERNATIONAL;
    }

    private boolean compareGid1(Phone phone, String serviceGid1) {
    private boolean compareGid1(Phone phone, String serviceGid1) {
        String gid1 = phone.getGroupIdLevel1();
        String gid1 = phone.getGroupIdLevel1();
        int gid_length = serviceGid1.length();
        int gid_length = serviceGid1.length();
+11 −0
Original line number Original line Diff line number Diff line
@@ -176,6 +176,7 @@ public class LocaleTracker extends Handler {
                                    TelephonyManager.SIM_STATE_UNKNOWN), 0).sendToTarget();
                                    TelephonyManager.SIM_STATE_UNKNOWN), 0).sendToTarget();
                }
                }
            } else if (ACTION_COUNTRY_OVERRIDE.equals(intent.getAction())) {
            } else if (ACTION_COUNTRY_OVERRIDE.equals(intent.getAction())) {
                // note: need to set ServiceStateTracker#PROP_FORCE_ROAMING to force roaming.
                String countryOverride = intent.getStringExtra(EXTRA_COUNTRY);
                String countryOverride = intent.getStringExtra(EXTRA_COUNTRY);
                boolean reset = intent.getBooleanExtra(EXTRA_RESET, false);
                boolean reset = intent.getBooleanExtra(EXTRA_RESET, false);
                if (reset) countryOverride = null;
                if (reset) countryOverride = null;
@@ -654,4 +655,14 @@ public class LocaleTracker extends Handler {
        ipw.decreaseIndent();
        ipw.decreaseIndent();
        ipw.flush();
        ipw.flush();
    }
    }

    /**
     *  This getter should only be used for testing purposes in classes that wish to spoof the
     *  country ISO. An example of how this can be done is in ServiceStateTracker#InSameCountry
     * @return spoofed country iso.
     */
    @VisibleForTesting
    public String getCountryOverride() {
        return mCountryOverride;
    }
}
}
+7 −0
Original line number Original line Diff line number Diff line
@@ -5461,6 +5461,13 @@ public class ServiceStateTracker extends Handler {
        final String homeMCC = homeNumeric.substring(0, 3);
        final String homeMCC = homeNumeric.substring(0, 3);
        final String networkCountry = MccTable.countryCodeForMcc(networkMCC);
        final String networkCountry = MccTable.countryCodeForMcc(networkMCC);
        final String homeCountry = MccTable.countryCodeForMcc(homeMCC);
        final String homeCountry = MccTable.countryCodeForMcc(homeMCC);

        if (mLocaleTracker != null && !TextUtils.isEmpty(mLocaleTracker.getCountryOverride())) {
            log("inSameCountry:  countryOverride var set.  This should only be set for testing "
                    + "purposes to override the device location.");
            return mLocaleTracker.getCountryOverride().equals(homeCountry);
        }

        if (networkCountry.isEmpty() || homeCountry.isEmpty()) {
        if (networkCountry.isEmpty() || homeCountry.isEmpty()) {
            // Not a valid country
            // Not a valid country
            return false;
            return false;
+212 −0
Original line number Original line Diff line number Diff line
@@ -66,6 +66,7 @@ import android.telecom.VideoProfile;
import android.telephony.CarrierConfigManager;
import android.telephony.CarrierConfigManager;
import android.telephony.DisconnectCause;
import android.telephony.DisconnectCause;
import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneNumberUtils;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsCallSession;
import android.telephony.ims.ImsCallSession;
@@ -77,6 +78,7 @@ import android.telephony.ims.RtpHeaderExtensionType;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper;
@@ -1065,6 +1067,216 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
        Assert.assertEquals("*55", connection.getAddress());
        Assert.assertEquals("*55", connection.getAddress());
    }
    }



    /**
     * Tests carrier requirement to re-map certain dialstrings based on the phones service state.
     * Dial strings in a particular roaming state (ex. ROAMING_TYPE_INTERNATIONAL) can be mapped
     * to the number.  Ideally, dialstrings in different roaming states will be mapped to
     * different remappings.
     *
     * ex.
     *
     * dialstring --> remapping
     *
     * 611 --> 123 , *611 --> 123   when  ServiceState.ROAMING_TYPE_DOMESTIC
     *
     * 611 --> 456 , *611 --> 456   when  ServiceState.ROAMING_TYPE_INTERNATIONAL
     */
    @Test
    @MediumTest
    public void testRewriteOutgoingNumberBasedOnRoamingState() {
        // mock carrier [dialstring]:[remapping]
        final String dialString = "611";
        final String dialStringStar = "*611";
        final String remapping1 = "1111111111";
        final String remapping2 = "2222222222";

        // Create the re-mappings by getting the mock carrier bundle and inserting string arrays
        PersistableBundle bundle = mContextFixture.getCarrierConfigBundle();
        // insert domestic roaming bundle
        bundle.putStringArray(CarrierConfigManager
                        .KEY_DIAL_STRING_REPLACE_STRING_ARRAY,
                new String[]{(dialString + ":" + remapping1),
                        (dialStringStar + ":" + remapping1)});
        // insert international roaming bundle
        bundle.putStringArray(CarrierConfigManager
                        .KEY_INTERNATIONAL_ROAMING_DIAL_STRING_REPLACE_STRING_ARRAY,
                new String[]{(dialString + ":" + remapping2),
                        (dialStringStar + ":" + remapping2)});

        try {
            doAnswer(new Answer<ImsCall>() {
                @Override
                public ImsCall answer(InvocationOnMock invocation) throws Throwable {
                    mImsCallListener =
                            (ImsCall.Listener) invocation.getArguments()[2];
                    ImsCall imsCall = spy(new ImsCall(mContext, mImsCallProfile));
                    imsCall.setListener(mImsCallListener);
                    imsCallMocking(imsCall);
                    return imsCall;
                }
            }).when(mImsManager).makeCall(eq(mImsCallProfile), (String[]) any(),
                    (ImsCall.Listener) any());
        } catch (ImsException ie) {
        }

        // set mock call for helper function CallTracker#shouldPerformInternationalNumberRemapping
        doReturn(ServiceState.ROAMING_TYPE_INTERNATIONAL)
                .when(mServiceState).getVoiceRoamingType();

        // perform a call while service is state in roaming international
        ImsPhoneConnection connection = null;
        try {
            connection = (ImsPhoneConnection) mCTUT.dial(dialString,
                    ImsCallProfile.CALL_TYPE_VOICE, null);
        } catch (Exception ex) {
            ex.printStackTrace();
            Assert.fail("unexpected exception thrown" + ex.getMessage());
        }
        if (connection == null) {
            Assert.fail("connection is null");
        }

        Assert.assertEquals(dialString, connection.getAddress());
        Assert.assertEquals(remapping2, connection.getConvertedNumber());

        mCTUT.hangupAllOrphanedConnections(DisconnectCause.NORMAL);

        // perform a 2nd call while service state is in roaming international
        ImsPhoneConnection connection2 = null;
        try {
            connection2 = (ImsPhoneConnection) mCTUT.dial(dialStringStar,
                    ImsCallProfile.CALL_TYPE_VOICE, null);
        } catch (Exception ex) {
            ex.printStackTrace();
            Assert.fail("unexpected exception thrown" + ex.getMessage());
        }
        if (connection2 == null) {
            Assert.fail("connection is null");
        }

        Assert.assertEquals(dialStringStar, connection2.getAddress());
        Assert.assertEquals(remapping2, connection2.getConvertedNumber());

        mCTUT.hangupAllOrphanedConnections(DisconnectCause.NORMAL);


        // CHANGE THE SERVICE STATE: international --> domestic
        doReturn(ServiceState.ROAMING_TYPE_DOMESTIC)
                .when(mServiceState).getVoiceRoamingType();

        // perform 3rd call while service state is in roaming DOMESTIC
        ImsPhoneConnection connection3 = null;
        try {
            connection3 = (ImsPhoneConnection) mCTUT.dial(dialString,
                    ImsCallProfile.CALL_TYPE_VOICE, null);
        } catch (Exception ex) {
            ex.printStackTrace();
            Assert.fail("unexpected exception thrown" + ex.getMessage());
        }
        if (connection3 == null) {
            Assert.fail("connection is null");
        }

        Assert.assertEquals(dialString, connection3.getAddress());
        Assert.assertEquals(remapping1, connection3.getConvertedNumber());


        mCTUT.hangupAllOrphanedConnections(DisconnectCause.NORMAL);

        // perform 4th call while service state is in roaming DOMESTIC
        ImsPhoneConnection connection4 = null;
        try {
            connection4 = (ImsPhoneConnection) mCTUT.dial(dialStringStar,
                    ImsCallProfile.CALL_TYPE_VOICE, null);
        } catch (Exception ex) {
            ex.printStackTrace();
            Assert.fail("unexpected exception thrown" + ex.getMessage());
        }
        if (connection4 == null) {
            Assert.fail("connection is null");
        }

        Assert.assertEquals(dialStringStar, connection4.getAddress());
        Assert.assertEquals(remapping1, connection4.getConvertedNumber());

        mCTUT.hangupAllOrphanedConnections(DisconnectCause.NORMAL);
    }


    /**
     * Tests the edge case where the phone is in ServiceState.ROAMING_TYPE_INTERNATIONAL but the
     * Carrier never set the bundle for this ServiceState.  Always default to
     * CarrierConfigManager.KEY_DIAL_STRING_REPLACE_STRING_ARRAY.
     */
    @Test
    @SmallTest
    public void testRewriteOutgoingNumberInternationalButBundleNotSet() {
        // mock carrier [dialstring]:[remapping]
        final String dialString = "611";
        final String dialStringStar = "*611";
        final String remapping1 = "1111111111";

        // Create the re-mappings by getting the mock carrier bundle and inserting string arrays
        PersistableBundle bundle = mContextFixture.getCarrierConfigBundle();
        // insert domestic roaming bundle
        bundle.putStringArray(CarrierConfigManager
                        .KEY_DIAL_STRING_REPLACE_STRING_ARRAY,
                new String[]{(dialString + ":" + remapping1),
                        (dialStringStar + ":" + remapping1)});

        try {
            doAnswer(new Answer<ImsCall>() {
                @Override
                public ImsCall answer(InvocationOnMock invocation) throws Throwable {
                    mImsCallListener =
                            (ImsCall.Listener) invocation.getArguments()[2];
                    ImsCall imsCall = spy(new ImsCall(mContext, mImsCallProfile));
                    imsCall.setListener(mImsCallListener);
                    imsCallMocking(imsCall);
                    return imsCall;
                }
            }).when(mImsManager).makeCall(eq(mImsCallProfile), (String[]) any(),
                    (ImsCall.Listener) any());
        } catch (ImsException ie) {
        }

        doReturn(ServiceState.ROAMING_TYPE_INTERNATIONAL)
                .when(mServiceState).getVoiceRoamingType();

        Assert.assertNotNull(mImsPhone);
        Assert.assertNotNull(mImsPhone.getDefaultPhone());

        ImsPhoneConnection connection = null;
        try {
            connection = (ImsPhoneConnection) mCTUT.dial(dialString,
                    ImsCallProfile.CALL_TYPE_VOICE, null);
        } catch (Exception ex) {
            ex.printStackTrace();
            Assert.fail("unexpected exception thrown" + ex.getMessage());
        }
        if (connection == null) {
            Assert.fail("connection is null");
        }

        // helper function CallTracker#shouldPerformInternationalNumberRemapping early exists since
        // the KEY_INTERNATIONAL_ROAMING_DIAL_STRING_REPLACE_STRING_ARRAY bundle is null. Therefore,
        // we should never check the service state and default to
        // KEY_INTERNATIONAL_ROAMING_DIAL_STRING_REPLACE_STRING_ARRAY bundle
        verify(mServiceState, times(0)).getVoiceRoamingType();

        Assert.assertEquals(mImsPhone.getDefaultPhone().getServiceState().getVoiceRoamingType(),
                ServiceState.ROAMING_TYPE_INTERNATIONAL);

        Assert.assertNull(bundle.getStringArray(CarrierConfigManager
                .KEY_INTERNATIONAL_ROAMING_DIAL_STRING_REPLACE_STRING_ARRAY));

        Assert.assertEquals(dialString, connection.getAddress());
        Assert.assertEquals(remapping1, connection.getConvertedNumber());

        mCTUT.hangupAllOrphanedConnections(DisconnectCause.NORMAL);
    }

    /**
    /**
     * Test notification of handover from LTE to WIFI and WIFI to LTE and ensure that the expected
     * Test notification of handover from LTE to WIFI and WIFI to LTE and ensure that the expected
     * connection events are sent.
     * connection events are sent.