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

Commit a5a32bc6 authored by Brad Ebinger's avatar Brad Ebinger Committed by Gerrit Code Review
Browse files

Merge "Ignore IWLAN RAT roaming mode in legacy mode"

parents 31849a00 22bcfbed
Loading
Loading
Loading
Loading
+72 −32
Original line number Original line Diff line number Diff line
@@ -60,6 +60,7 @@ import android.os.RegistrantList;
import android.os.ResultReceiver;
import android.os.ResultReceiver;
import android.os.SystemProperties;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserHandle;
import android.telephony.AccessNetworkConstants;
import android.telephony.CarrierConfigManager;
import android.telephony.CarrierConfigManager;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneNumberUtils;
@@ -92,9 +93,11 @@ import com.android.internal.telephony.MmiCode;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.PhoneNotifier;
import com.android.internal.telephony.PhoneNotifier;
import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.TelephonyComponentFactory;
import com.android.internal.telephony.TelephonyComponentFactory;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.telephony.dataconnection.TransportManager;
import com.android.internal.telephony.gsm.GsmMmiCode;
import com.android.internal.telephony.gsm.GsmMmiCode;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.uicc.IccRecords;
@@ -120,7 +123,8 @@ public class ImsPhone extends ImsPhoneBase {
    private static final int EVENT_SET_CLIR_DONE                     = EVENT_LAST + 5;
    private static final int EVENT_SET_CLIR_DONE                     = EVENT_LAST + 5;
    private static final int EVENT_GET_CLIR_DONE                     = EVENT_LAST + 6;
    private static final int EVENT_GET_CLIR_DONE                     = EVENT_LAST + 6;
    private static final int EVENT_DEFAULT_PHONE_DATA_STATE_CHANGED  = EVENT_LAST + 7;
    private static final int EVENT_DEFAULT_PHONE_DATA_STATE_CHANGED  = EVENT_LAST + 7;
    private static final int EVENT_SERVICE_STATE_CHANGED             = EVENT_LAST + 8;
    @VisibleForTesting
    public static final int EVENT_SERVICE_STATE_CHANGED             = EVENT_LAST + 8;
    private static final int EVENT_VOICE_CALL_ENDED                  = EVENT_LAST + 9;
    private static final int EVENT_VOICE_CALL_ENDED                  = EVENT_LAST + 9;


    static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
    static final int RESTART_ECM_TIMER = 0; // restart Ecm timer
@@ -1497,25 +1501,16 @@ public class ImsPhone extends ImsPhoneBase {
                if (VDBG) logd("EVENT_SERVICE_STATE_CHANGED");
                if (VDBG) logd("EVENT_SERVICE_STATE_CHANGED");
                ar = (AsyncResult) msg.obj;
                ar = (AsyncResult) msg.obj;
                ServiceState newServiceState = (ServiceState) ar.result;
                ServiceState newServiceState = (ServiceState) ar.result;
                // only update if roaming status changed
                updateRoamingState(newServiceState);
                if (mRoaming != newServiceState.getRoaming()) {
                    if (DBG) logd("Roaming state changed - " + mRoaming);
                    // Update WFC mode only if voice or data is in service.
                    // The STATE_IN_SERVICE is checked to prevent wifi calling mode change
                    // when phone moves from roaming to no service.
                    boolean isInService =
                            (newServiceState.getVoiceRegState() == ServiceState.STATE_IN_SERVICE ||
                            newServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE);
                    updateRoamingState(newServiceState.getRoaming(), isInService);
                }
                break;
                break;
            case EVENT_VOICE_CALL_ENDED:
            case EVENT_VOICE_CALL_ENDED:
                if (DBG) logd("Voice call ended. Handle pending updateRoamingState.");
                if (DBG) logd("Voice call ended. Handle pending updateRoamingState.");
                mCT.unregisterForVoiceCallEnded(this);
                mCT.unregisterForVoiceCallEnded(this);
                // only update if roaming status changed
                // Get the current unmodified ServiceState from the tracker, as it has more info
                boolean newRoaming = getCurrentRoaming();
                // about the cell roaming state.
                if (mRoaming != newRoaming) {
                ServiceStateTracker sst = getDefaultPhone().getServiceStateTracker();
                    updateRoamingState(newRoaming, true);
                if (sst != null) {
                    updateRoamingState(sst.mSS);
                }
                }
                break;
                break;


@@ -1888,27 +1883,72 @@ public class ImsPhone extends ImsPhoneBase {
        return mCT.getVtDataUsage(perUidStats);
        return mCT.getVtDataUsage(perUidStats);
    }
    }


    private void updateRoamingState(boolean newRoaming, boolean isInService) {
    /**
     * Update roaming state and WFC mode in the following situations:
     *     1) voice is in service.
     *     2) data is in service and it is not IWLAN (if in legacy mode).
     * @param ss non-null ServiceState
     */
    private void updateRoamingState(ServiceState ss) {
        if (ss == null) {
            loge("updateRoamingState: null ServiceState!");
            return;
        }
        boolean newRoamingState = ss.getRoaming();
        // Do not recalculate if there is no change to state.
        if (mRoaming == newRoamingState) {
            return;
        }
        boolean isInService = (ss.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
                || ss.getDataRegState() == ServiceState.STATE_IN_SERVICE);
        // If we are not IN_SERVICE for voice or data, ignore change roaming state, as we always
        // move to home in this case.
        if (!isInService) {
            logi("updateRoamingState: we are OUT_OF_SERVICE, ignoring roaming change.");
            return;
        }
        // We ignore roaming changes when moving to IWLAN because it always sets the roaming
        // mode to home and masks the actual cellular roaming status if voice is not registered. If
        // we just moved to IWLAN because WFC roaming mode is IWLAN preferred and WFC home mode is
        // cell preferred, we can get into a condition where the modem keeps bouncing between
        // IWLAN->cell->IWLAN->cell...
        if (isCsNotInServiceAndPsWwanReportingWlan(ss)) {
            logi("updateRoamingState: IWLAN masking roaming, ignore roaming change.");
            return;
        }
        if (mCT.getState() == PhoneConstants.State.IDLE) {
        if (mCT.getState() == PhoneConstants.State.IDLE) {
            if (DBG) logd("updateRoamingState now: " + newRoaming);
            if (DBG) logd("updateRoamingState now: " + newRoamingState);
            mRoaming = newRoaming;
            mRoaming = newRoamingState;
            if (isInService) {
            ImsManager imsManager = ImsManager.getInstance(mContext, mPhoneId);
            ImsManager imsManager = ImsManager.getInstance(mContext, mPhoneId);
                imsManager.setWfcMode(imsManager.getWfcMode(newRoaming), newRoaming);
            imsManager.setWfcMode(imsManager.getWfcMode(newRoamingState), newRoamingState);
        } else {
        } else {
                if (DBG) Rlog.d(LOG_TAG, "updateRoamingState service state is OUT_OF_SERVICE");
            if (DBG) logd("updateRoamingState postponed: " + newRoamingState);
            }
            mCT.registerForVoiceCallEnded(this, EVENT_VOICE_CALL_ENDED, null);
        } else {
            if (DBG) logd("updateRoamingState postponed: " + newRoaming);
            mCT.registerForVoiceCallEnded(this,
                    EVENT_VOICE_CALL_ENDED, null);
        }
        }
    }
    }


    private boolean getCurrentRoaming() {
    /**
        TelephonyManager tm = (TelephonyManager) mContext
     * In legacy mode, data registration will report IWLAN when we are using WLAN for data,
                .getSystemService(Context.TELEPHONY_SERVICE);
     * effectively masking the true roaming state of the device if voice is not registered.
        return tm.isNetworkRoaming(getSubId());
     *
     * @return true if we are reporting not in service for CS domain over WWAN transport and WLAN
     * for PS domain over WWAN transport.
     */
    private boolean isCsNotInServiceAndPsWwanReportingWlan(ServiceState ss) {
        TransportManager tm = mDefaultPhone.getTransportManager();
        // We can not get into this condition if we are in AP-Assisted mode.
        if (tm == null || !tm.isInLegacyMode()) {
            return false;
        }
        NetworkRegistrationInfo csInfo = ss.getNetworkRegistrationInfo(
                NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
        NetworkRegistrationInfo psInfo = ss.getNetworkRegistrationInfo(
                NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
        // We will return roaming state correctly if the CS domain is in service because
        // ss.getRoaming() returns isVoiceRoaming||isDataRoaming result and isDataRoaming==false
        // when the modem reports IWLAN RAT.
        return psInfo != null && csInfo != null && !csInfo.isInService()
                && psInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_IWLAN;
    }
    }


    @Override
    @Override
+164 −0
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyChar;
import static org.mockito.Matchers.anyChar;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyInt;
@@ -643,4 +644,167 @@ public class ImsPhoneTest extends TelephonyTest {
        assertEquals(messageNotification,
        assertEquals(messageNotification,
                intent.getValue().getStringExtra(Phone.EXTRA_KEY_NOTIFICATION_MESSAGE));
                intent.getValue().getStringExtra(Phone.EXTRA_KEY_NOTIFICATION_MESSAGE));
    }
    }

    @Test
    @SmallTest
    public void testRoamingDuplicateMessages() throws Exception {
        doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState();

        //roaming - data registration only on LTE
        Message m = getServiceStateChangedMessage(getServiceStateDataOnly(
                ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, true));
        // Inject the message synchronously instead of waiting for the thread to do it.
        mImsPhoneUT.handleMessage(m);

        verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(true));

        // Send a duplicate message
        mImsPhoneUT.handleMessage(m);
        m.recycle();

        // setWfcMode should not be called again.
        verify(mImsManager, times(1)).setWfcMode(anyInt(), anyBoolean());
    }


    @Test
    @SmallTest
    public void testRoamingToOutOfService() throws Exception {
        doReturn(true).when(mTransportManager).isInLegacyMode();
        doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState();

        //roaming - data registration only on LTE
        Message m = getServiceStateChangedMessage(getServiceStateDataOnly(
                ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, true));
        // Inject the message synchronously instead of waiting for the thread to do it.
        mImsPhoneUT.handleMessage(m);
        m.recycle();

        verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(true));

        // move to out of service
        m = getServiceStateChangedMessage(getServiceStateOutOfService());
        mImsPhoneUT.handleMessage(m);
        m.recycle();

        // setWfcMode should not be called again, out_of_service should not trigger move out of
        // roaming.
        verify(mImsManager, times(1)).setWfcMode(anyInt(), anyBoolean());
    }

    @Test
    @SmallTest
    public void testRoamingChangeForLteInLegacyMode() throws Exception {
        doReturn(true).when(mTransportManager).isInLegacyMode();
        doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState();

        //roaming - data registration only on LTE
        Message m = getServiceStateChangedMessage(getServiceStateDataOnly(
                ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, true));
        // Inject the message synchronously instead of waiting for the thread to do it.
        mImsPhoneUT.handleMessage(m);
        m.recycle();

        verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(true));

        // not roaming - data registration on LTE
        m = getServiceStateChangedMessage(getServiceStateDataOnly(
                ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, false));
        mImsPhoneUT.handleMessage(m);
        m.recycle();

        verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(false));
    }

    @Test
    @SmallTest
    public void testDataOnlyRoamingCellToIWlanInLegacyMode() throws Exception {
        doReturn(true).when(mTransportManager).isInLegacyMode();
        doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState();

        //roaming - data registration only on LTE
        Message m = getServiceStateChangedMessage(getServiceStateDataOnly(
                ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, true));
        // Inject the message synchronously instead of waiting for the thread to do it.
        mImsPhoneUT.handleMessage(m);
        m.recycle();

        verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(true));

        // not roaming - data registration onto IWLAN
        m = getServiceStateChangedMessage(getServiceStateDataOnly(
                ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, ServiceState.STATE_IN_SERVICE, false));
        mImsPhoneUT.handleMessage(m);
        m.recycle();

        // Verify that it hasn't been called again.
        verify(mImsManager, times(1)).setWfcMode(anyInt(), anyBoolean());
    }

    @Test
    @SmallTest
    public void testCellVoiceDataChangeToWlanInLegacyMode() throws Exception {
        doReturn(true).when(mTransportManager).isInLegacyMode();
        doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState();

        //roaming - voice/data registration on LTE
        ServiceState ss = getServiceStateDataAndVoice(
                ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, true);
        Message m = getServiceStateChangedMessage(ss);
        // Inject the message synchronously instead of waiting for the thread to do it.
        mImsPhoneUT.handleMessage(m);

        verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(true));

        // roaming - voice LTE, data registration onto IWLAN
        modifyServiceStateData(ss, ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN,
                ServiceState.STATE_IN_SERVICE, false);
        mImsPhoneUT.handleMessage(m);
        m.recycle();

        // Verify that it hasn't been called again.
        verify(mImsManager, times(1)).setWfcMode(anyInt(), anyBoolean());
    }

    private ServiceState getServiceStateDataAndVoice(int rat, int regState, boolean isRoaming) {
        ServiceState ss = new ServiceState();
        ss.setStateOutOfService();
        ss.setDataRegState(regState);
        ss.setDataRoaming(isRoaming);
        ss.setRilDataRadioTechnology(rat);
        ss.setVoiceRegState(regState);
        ss.setVoiceRoaming(isRoaming);
        ss.setRilVoiceRadioTechnology(rat);
        return ss;
    }

    private ServiceState getServiceStateDataOnly(int rat, int regState, boolean isRoaming) {
        ServiceState ss = new ServiceState();
        ss.setStateOutOfService();
        ss.setDataRegState(regState);
        ss.setDataRoaming(isRoaming);
        ss.setRilDataRadioTechnology(rat);
        return ss;
    }

    private ServiceState modifyServiceStateData(ServiceState ss, int rat, int regState,
            boolean isRoaming) {
        ss.setStateOutOfService();
        ss.setDataRegState(regState);
        ss.setDataRoaming(isRoaming);
        ss.setRilDataRadioTechnology(rat);
        return ss;
    }

    private ServiceState getServiceStateOutOfService() {
        ServiceState ss = new ServiceState();
        ss.setStateOutOfService();
        return ss;
    }

    private Message getServiceStateChangedMessage(ServiceState ss) {
        Message m = Message.obtain(mImsPhoneUT.getHandler(), ImsPhone.EVENT_SERVICE_STATE_CHANGED);
        m.obj = AsyncResult.forMessage(m, ss, null);
        return m;
    }
}
}