Loading src/java/com/android/internal/telephony/data/PhoneSwitcher.java +53 −68 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ import android.telephony.ims.RegistrationManager; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.ArrayMap; import android.util.LocalLog; import android.util.Log; import com.android.ims.ImsException; import com.android.ims.ImsManager; Loading Loading @@ -119,7 +120,7 @@ import java.util.concurrent.CompletableFuture; */ public class PhoneSwitcher extends Handler { private static final String LOG_TAG = "PhoneSwitcher"; protected static final boolean VDBG = false; protected static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE); /** Fragment "key" argument passed thru {@link #SETTINGS_EXTRA_SHOW_FRAGMENT_ARGUMENTS} */ private static final String SETTINGS_EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key"; Loading Loading @@ -469,36 +470,14 @@ public class PhoneSwitcher extends Handler { return sPhoneSwitcher; } /** * Whether this phone IMS registration is on its original network. This result impacts * whether we want to do DDS switch to the phone having voice call. * If it's registered on IWLAN or cross SIM in multi-SIM case, return false. Otherwise, * return true. */ private boolean isImsOnOriginalNetwork(Phone phone) { if (phone == null) return false; int phoneId = phone.getPhoneId(); if (!SubscriptionManager.isValidPhoneId(phoneId)) return false; int imsRegTech = mImsRegTechProvider.get(mContext, phoneId); // If IMS is registered on IWLAN or cross SIM, return false. boolean isOnOriginalNetwork = (imsRegTech != REGISTRATION_TECH_IWLAN) && (imsRegTech != REGISTRATION_TECH_CROSS_SIM); if (!isOnOriginalNetwork) { logl("IMS call on IWLAN or cross SIM. Call will be ignored for DDS switch"); } return isOnOriginalNetwork; } private boolean isPhoneInVoiceCallChanged() { private boolean updatesIfPhoneInVoiceCallChanged() { int oldPhoneIdInVoiceCall = mPhoneIdInVoiceCall; // If there's no active call, the value will become INVALID_PHONE_INDEX // and internet data will be switched back to system selected or user selected // subscription. mPhoneIdInVoiceCall = SubscriptionManager.INVALID_PHONE_INDEX; for (Phone phone : PhoneFactory.getPhones()) { if (isPhoneInVoiceCall(phone) || (isPhoneInVoiceCall(phone.getImsPhone()) && isImsOnOriginalNetwork(phone))) { if (isPhoneInVoiceCall(phone) || isPhoneInVoiceCall(phone.getImsPhone())) { mPhoneIdInVoiceCall = phone.getPhoneId(); break; } Loading Loading @@ -780,25 +759,25 @@ public class PhoneSwitcher extends Handler { onEvaluate(REQUESTS_UNCHANGED, EVALUATION_REASON_RADIO_ON); break; } case EVENT_IMS_RADIO_TECH_CHANGED: case EVENT_IMS_RADIO_TECH_CHANGED: { // register for radio tech change to listen to radio tech handover in case previous // attempt was not successful registerForImsRadioTechChange(); // If the phoneId in voice call didn't change, do nothing. if (!isPhoneInVoiceCallChanged()) { break; } // if voice call state changes or in voice call didn't change // but RAT changes(e.g. Iwlan -> cross sim), reevaluate for data switch. if (updatesIfPhoneInVoiceCallChanged() || isAnyVoiceCallActiveOnDevice()) { evaluateIfImmediateDataSwitchIsNeeded("Ims radio tech changed", DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); } break; } case EVENT_PRECISE_CALL_STATE_CHANGED: { // register for radio tech change to listen to radio tech handover in case previous // attempt was not successful registerForImsRadioTechChange(); // If the phoneId in voice call didn't change, do nothing. if (!isPhoneInVoiceCallChanged()) { if (!updatesIfPhoneInVoiceCallChanged()) { break; } Loading Loading @@ -1606,27 +1585,9 @@ public class PhoneSwitcher extends Handler { } } private int getSubIdForDefaultNetworkRequests() { if (isActiveSubId(mAutoSelectedDataSubId)) { return mAutoSelectedDataSubId; } else { return mPrimaryDataSubId; } } // This updates mPreferredDataPhoneId which decides which phone should handle default network // requests. protected void updatePreferredDataPhoneId() { Phone voicePhone = findPhoneById(mPhoneIdInVoiceCall); // check user enabled data on the default phone Phone defaultDataPhone = getPhoneBySubId(mPrimaryDataSubId); boolean isDataEnabled = false; if (voicePhone != null && defaultDataPhone != null && defaultDataPhone.isUserDataEnabled()) { // check voice during call feature is enabled isDataEnabled = voicePhone.isDataAllowed(); } if (mEmergencyOverride != null && findPhoneById(mEmergencyOverride.mPhoneId) != null) { // Override DDS for emergency even if user data is not enabled, since it is an // emergency. Loading @@ -1636,29 +1597,53 @@ public class PhoneSwitcher extends Handler { + " phoneId = " + mEmergencyOverride.mPhoneId); mPreferredDataPhoneId = mEmergencyOverride.mPhoneId; mLastSwitchPreferredDataReason = DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN; } else if (isDataEnabled) { // If a phone is in call and user enabled its mobile data, we // should switch internet connection to it. Because the other modem // will lose data connection anyway. mPreferredDataPhoneId = mPhoneIdInVoiceCall; mLastSwitchPreferredDataReason = DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL; } else { int subId = getSubIdForDefaultNetworkRequests(); int phoneId = SubscriptionManager.INVALID_PHONE_INDEX; if (SubscriptionManager.isUsableSubIdValue(subId)) { for (int i = 0; i < mActiveModemCount; i++) { if (mPhoneSubscriptions[i] == subId) { phoneId = i; break; int imsRegTech = mImsRegTechProvider.get(mContext, mPhoneIdInVoiceCall); if (isAnyVoiceCallActiveOnDevice() && imsRegTech != REGISTRATION_TECH_IWLAN) { if (imsRegTech != REGISTRATION_TECH_CROSS_SIM) { if (shouldSwitchDataDueToInCall()) mPreferredDataPhoneId = mPhoneIdInVoiceCall; } else { logl("IMS call on cross-SIM, skip switching data to phone " + mPhoneIdInVoiceCall); } } else { mPreferredDataPhoneId = getFallbackDataPhoneIdForInternetRequests(); } } mPreferredDataPhoneId = phoneId; mPreferredDataSubId.set(SubscriptionManager.getSubscriptionId(mPreferredDataPhoneId)); } mPreferredDataSubId.set(SubscriptionManager.getSubscriptionId(mPreferredDataPhoneId)); /** * @return the default data phone Id (or auto selected phone Id in auto data switch/CBRS case) */ private int getFallbackDataPhoneIdForInternetRequests() { int fallbackSubId = isActiveSubId(mAutoSelectedDataSubId) ? mAutoSelectedDataSubId : mPrimaryDataSubId; if (SubscriptionManager.isUsableSubIdValue(fallbackSubId)) { for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) { if (mPhoneSubscriptions[phoneId] == fallbackSubId) { return phoneId; } } } return SubscriptionManager.INVALID_PHONE_INDEX; } /** * If a phone is in call and user enabled its mobile data and auto data switch feature, we * should switch internet connectionto it because the other modem will lose data connection * anyway. * @return {@code true} if should switch data to the phone in voice call */ private boolean shouldSwitchDataDueToInCall() { Phone voicePhone = findPhoneById(mPhoneIdInVoiceCall); Phone defaultDataPhone = getPhoneBySubId(mPrimaryDataSubId); return defaultDataPhone != null // check user enabled data && defaultDataPhone.isUserDataEnabled() && voicePhone != null // check user enabled voice during call feature && voicePhone.isDataAllowed(); } protected void transitionToEmergencyPhone() { Loading tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +18 −7 Original line number Diff line number Diff line Loading @@ -95,7 +95,6 @@ import java.util.concurrent.LinkedBlockingQueue; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class PhoneSwitcherTest extends TelephonyTest { private static final int AUTO_DATA_SWITCH_NOTIFICATION = 1; private static final int ACTIVE_PHONE_SWITCH = 1; private static final int EVENT_RADIO_ON = 108; private static final int EVENT_MODEM_COMMAND_DONE = 112; Loading Loading @@ -1176,7 +1175,7 @@ public class PhoneSwitcherTest extends TelephonyTest { assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); // Phone2 has active call. So data switch to it. // Phone2 has active call, and data is on. So data switch to it. doReturn(true).when(mPhone).isUserDataEnabled(); notifyDataEnabled(true); verify(mMockRadioConfig).setPreferredDataModem(eq(1), any()); Loading @@ -1186,8 +1185,19 @@ public class PhoneSwitcherTest extends TelephonyTest { new TelephonyNetworkRequest(internetRequest, mPhone), 0)); clearInvocations(mMockRadioConfig); // Phone2 call ended. So data switch back to default data sub. // Phone2(nDDS) call ended. But Phone1 having cross-SIM call. Don't switch. mockImsRegTech(1, REGISTRATION_TECH_CROSS_SIM); notifyPhoneAsInIncomingCall(mPhone); notifyPhoneAsInactive(mPhone2); verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any()); assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); // Phone1(DDS) call ended. So data switch back to default data sub. mockImsRegTech(0, REGISTRATION_TECH_IWLAN); notifyPhoneAsInactive(mPhone); verify(mMockRadioConfig).setPreferredDataModem(eq(0), any()); assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); Loading @@ -1195,13 +1205,14 @@ public class PhoneSwitcherTest extends TelephonyTest { new TelephonyNetworkRequest(internetRequest, mPhone), 1)); clearInvocations(mMockRadioConfig); // Phone2 has holding call, but data is turned off. So no data switching should happen. // Phone2 has holding call on VoWifi, no need to switch data mockImsRegTech(1, REGISTRATION_TECH_IWLAN); notifyPhoneAsInHoldingCall(mPhone2); verify(mMockRadioConfig).setPreferredDataModem(eq(1), any()); verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any()); assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); } Loading Loading
src/java/com/android/internal/telephony/data/PhoneSwitcher.java +53 −68 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ import android.telephony.ims.RegistrationManager; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.ArrayMap; import android.util.LocalLog; import android.util.Log; import com.android.ims.ImsException; import com.android.ims.ImsManager; Loading Loading @@ -119,7 +120,7 @@ import java.util.concurrent.CompletableFuture; */ public class PhoneSwitcher extends Handler { private static final String LOG_TAG = "PhoneSwitcher"; protected static final boolean VDBG = false; protected static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE); /** Fragment "key" argument passed thru {@link #SETTINGS_EXTRA_SHOW_FRAGMENT_ARGUMENTS} */ private static final String SETTINGS_EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key"; Loading Loading @@ -469,36 +470,14 @@ public class PhoneSwitcher extends Handler { return sPhoneSwitcher; } /** * Whether this phone IMS registration is on its original network. This result impacts * whether we want to do DDS switch to the phone having voice call. * If it's registered on IWLAN or cross SIM in multi-SIM case, return false. Otherwise, * return true. */ private boolean isImsOnOriginalNetwork(Phone phone) { if (phone == null) return false; int phoneId = phone.getPhoneId(); if (!SubscriptionManager.isValidPhoneId(phoneId)) return false; int imsRegTech = mImsRegTechProvider.get(mContext, phoneId); // If IMS is registered on IWLAN or cross SIM, return false. boolean isOnOriginalNetwork = (imsRegTech != REGISTRATION_TECH_IWLAN) && (imsRegTech != REGISTRATION_TECH_CROSS_SIM); if (!isOnOriginalNetwork) { logl("IMS call on IWLAN or cross SIM. Call will be ignored for DDS switch"); } return isOnOriginalNetwork; } private boolean isPhoneInVoiceCallChanged() { private boolean updatesIfPhoneInVoiceCallChanged() { int oldPhoneIdInVoiceCall = mPhoneIdInVoiceCall; // If there's no active call, the value will become INVALID_PHONE_INDEX // and internet data will be switched back to system selected or user selected // subscription. mPhoneIdInVoiceCall = SubscriptionManager.INVALID_PHONE_INDEX; for (Phone phone : PhoneFactory.getPhones()) { if (isPhoneInVoiceCall(phone) || (isPhoneInVoiceCall(phone.getImsPhone()) && isImsOnOriginalNetwork(phone))) { if (isPhoneInVoiceCall(phone) || isPhoneInVoiceCall(phone.getImsPhone())) { mPhoneIdInVoiceCall = phone.getPhoneId(); break; } Loading Loading @@ -780,25 +759,25 @@ public class PhoneSwitcher extends Handler { onEvaluate(REQUESTS_UNCHANGED, EVALUATION_REASON_RADIO_ON); break; } case EVENT_IMS_RADIO_TECH_CHANGED: case EVENT_IMS_RADIO_TECH_CHANGED: { // register for radio tech change to listen to radio tech handover in case previous // attempt was not successful registerForImsRadioTechChange(); // If the phoneId in voice call didn't change, do nothing. if (!isPhoneInVoiceCallChanged()) { break; } // if voice call state changes or in voice call didn't change // but RAT changes(e.g. Iwlan -> cross sim), reevaluate for data switch. if (updatesIfPhoneInVoiceCallChanged() || isAnyVoiceCallActiveOnDevice()) { evaluateIfImmediateDataSwitchIsNeeded("Ims radio tech changed", DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); } break; } case EVENT_PRECISE_CALL_STATE_CHANGED: { // register for radio tech change to listen to radio tech handover in case previous // attempt was not successful registerForImsRadioTechChange(); // If the phoneId in voice call didn't change, do nothing. if (!isPhoneInVoiceCallChanged()) { if (!updatesIfPhoneInVoiceCallChanged()) { break; } Loading Loading @@ -1606,27 +1585,9 @@ public class PhoneSwitcher extends Handler { } } private int getSubIdForDefaultNetworkRequests() { if (isActiveSubId(mAutoSelectedDataSubId)) { return mAutoSelectedDataSubId; } else { return mPrimaryDataSubId; } } // This updates mPreferredDataPhoneId which decides which phone should handle default network // requests. protected void updatePreferredDataPhoneId() { Phone voicePhone = findPhoneById(mPhoneIdInVoiceCall); // check user enabled data on the default phone Phone defaultDataPhone = getPhoneBySubId(mPrimaryDataSubId); boolean isDataEnabled = false; if (voicePhone != null && defaultDataPhone != null && defaultDataPhone.isUserDataEnabled()) { // check voice during call feature is enabled isDataEnabled = voicePhone.isDataAllowed(); } if (mEmergencyOverride != null && findPhoneById(mEmergencyOverride.mPhoneId) != null) { // Override DDS for emergency even if user data is not enabled, since it is an // emergency. Loading @@ -1636,29 +1597,53 @@ public class PhoneSwitcher extends Handler { + " phoneId = " + mEmergencyOverride.mPhoneId); mPreferredDataPhoneId = mEmergencyOverride.mPhoneId; mLastSwitchPreferredDataReason = DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN; } else if (isDataEnabled) { // If a phone is in call and user enabled its mobile data, we // should switch internet connection to it. Because the other modem // will lose data connection anyway. mPreferredDataPhoneId = mPhoneIdInVoiceCall; mLastSwitchPreferredDataReason = DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL; } else { int subId = getSubIdForDefaultNetworkRequests(); int phoneId = SubscriptionManager.INVALID_PHONE_INDEX; if (SubscriptionManager.isUsableSubIdValue(subId)) { for (int i = 0; i < mActiveModemCount; i++) { if (mPhoneSubscriptions[i] == subId) { phoneId = i; break; int imsRegTech = mImsRegTechProvider.get(mContext, mPhoneIdInVoiceCall); if (isAnyVoiceCallActiveOnDevice() && imsRegTech != REGISTRATION_TECH_IWLAN) { if (imsRegTech != REGISTRATION_TECH_CROSS_SIM) { if (shouldSwitchDataDueToInCall()) mPreferredDataPhoneId = mPhoneIdInVoiceCall; } else { logl("IMS call on cross-SIM, skip switching data to phone " + mPhoneIdInVoiceCall); } } else { mPreferredDataPhoneId = getFallbackDataPhoneIdForInternetRequests(); } } mPreferredDataPhoneId = phoneId; mPreferredDataSubId.set(SubscriptionManager.getSubscriptionId(mPreferredDataPhoneId)); } mPreferredDataSubId.set(SubscriptionManager.getSubscriptionId(mPreferredDataPhoneId)); /** * @return the default data phone Id (or auto selected phone Id in auto data switch/CBRS case) */ private int getFallbackDataPhoneIdForInternetRequests() { int fallbackSubId = isActiveSubId(mAutoSelectedDataSubId) ? mAutoSelectedDataSubId : mPrimaryDataSubId; if (SubscriptionManager.isUsableSubIdValue(fallbackSubId)) { for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) { if (mPhoneSubscriptions[phoneId] == fallbackSubId) { return phoneId; } } } return SubscriptionManager.INVALID_PHONE_INDEX; } /** * If a phone is in call and user enabled its mobile data and auto data switch feature, we * should switch internet connectionto it because the other modem will lose data connection * anyway. * @return {@code true} if should switch data to the phone in voice call */ private boolean shouldSwitchDataDueToInCall() { Phone voicePhone = findPhoneById(mPhoneIdInVoiceCall); Phone defaultDataPhone = getPhoneBySubId(mPrimaryDataSubId); return defaultDataPhone != null // check user enabled data && defaultDataPhone.isUserDataEnabled() && voicePhone != null // check user enabled voice during call feature && voicePhone.isDataAllowed(); } protected void transitionToEmergencyPhone() { Loading
tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +18 −7 Original line number Diff line number Diff line Loading @@ -95,7 +95,6 @@ import java.util.concurrent.LinkedBlockingQueue; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class PhoneSwitcherTest extends TelephonyTest { private static final int AUTO_DATA_SWITCH_NOTIFICATION = 1; private static final int ACTIVE_PHONE_SWITCH = 1; private static final int EVENT_RADIO_ON = 108; private static final int EVENT_MODEM_COMMAND_DONE = 112; Loading Loading @@ -1176,7 +1175,7 @@ public class PhoneSwitcherTest extends TelephonyTest { assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); // Phone2 has active call. So data switch to it. // Phone2 has active call, and data is on. So data switch to it. doReturn(true).when(mPhone).isUserDataEnabled(); notifyDataEnabled(true); verify(mMockRadioConfig).setPreferredDataModem(eq(1), any()); Loading @@ -1186,8 +1185,19 @@ public class PhoneSwitcherTest extends TelephonyTest { new TelephonyNetworkRequest(internetRequest, mPhone), 0)); clearInvocations(mMockRadioConfig); // Phone2 call ended. So data switch back to default data sub. // Phone2(nDDS) call ended. But Phone1 having cross-SIM call. Don't switch. mockImsRegTech(1, REGISTRATION_TECH_CROSS_SIM); notifyPhoneAsInIncomingCall(mPhone); notifyPhoneAsInactive(mPhone2); verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any()); assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); // Phone1(DDS) call ended. So data switch back to default data sub. mockImsRegTech(0, REGISTRATION_TECH_IWLAN); notifyPhoneAsInactive(mPhone); verify(mMockRadioConfig).setPreferredDataModem(eq(0), any()); assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); Loading @@ -1195,13 +1205,14 @@ public class PhoneSwitcherTest extends TelephonyTest { new TelephonyNetworkRequest(internetRequest, mPhone), 1)); clearInvocations(mMockRadioConfig); // Phone2 has holding call, but data is turned off. So no data switching should happen. // Phone2 has holding call on VoWifi, no need to switch data mockImsRegTech(1, REGISTRATION_TECH_IWLAN); notifyPhoneAsInHoldingCall(mPhone2); verify(mMockRadioConfig).setPreferredDataModem(eq(1), any()); verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any()); assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); } Loading