Loading src/java/com/android/internal/telephony/CellularNetworkValidator.java +1 −1 Original line number Diff line number Diff line Loading @@ -94,7 +94,7 @@ public class CellularNetworkValidator { /** * Check whether this feature is supported or not. */ public static boolean isValidationFeatureSupported() { public boolean isValidationFeatureSupported() { return PhoneConfigurationManager.getInstance().getCurrentPhoneCapability() .validationBeforeSwitchSupported; } Loading src/java/com/android/internal/telephony/PhoneSwitcher.java +52 −30 Original line number Diff line number Diff line Loading @@ -104,7 +104,8 @@ public class PhoneSwitcher extends Handler { @VisibleForTesting public final PhoneStateListener mPhoneStateListener; private final CellularNetworkValidator mValidator; private final CellularNetworkValidator.ValidationCallback mValidationCallback = @VisibleForTesting public final CellularNetworkValidator.ValidationCallback mValidationCallback = (validated, subId) -> Message.obtain(PhoneSwitcher.this, EVENT_NETWORK_VALIDATION_DONE, subId, validated ? 1 : 0).sendToTarget(); @UnsupportedAppUsage Loading Loading @@ -405,11 +406,7 @@ public class PhoneSwitcher extends Handler { boolean needValidation = (msg.arg2 == 1); ISetOpportunisticDataCallback callback = (ISetOpportunisticDataCallback) msg.obj; if (SubscriptionManager.isUsableSubscriptionId(subId)) { setOpportunisticDataSubscription(subId, needValidation, callback); } else { unsetOpportunisticDataSubscription(callback); } break; } case EVENT_RADIO_AVAILABLE: { Loading Loading @@ -909,18 +906,31 @@ public class PhoneSwitcher extends Handler { /** * Set opportunistic data subscription. It's an indication to switch Internet data to this * subscription. It has to be an active subscription, and PhoneSwitcher will try to validate * it first if needed. * it first if needed. If subId is DEFAULT_SUBSCRIPTION_ID, it means we are un-setting * opportunistic data sub and switch data back to primary sub. * * @param subId the opportunistic data subscription to switch to. pass DEFAULT_SUBSCRIPTION_ID * if un-setting it. * @param needValidation whether Telephony will wait until the network is validated by * connectivity service before switching data to it. More details see * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}. * @param callback Callback will be triggered once it succeeds or failed. * Pass null if don't care about the result. */ private void setOpportunisticDataSubscription(int subId, boolean needValidation, ISetOpportunisticDataCallback callback) { if (!mSubscriptionController.isActiveSubId(subId)) { if (!mSubscriptionController.isActiveSubId(subId) && subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { log("Can't switch data to inactive subId " + subId); sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION); return; } int subIdToValidate = (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) ? mPrimaryDataSubId : subId; if (mValidator.isValidating() && (!needValidation || subId != mValidator.getSubIdInValidation())) { && (!needValidation || subIdToValidate != mValidator.getSubIdInValidation())) { mValidator.stopValidation(); } Loading @@ -931,11 +941,11 @@ public class PhoneSwitcher extends Handler { // If validation feature is not supported, set it directly. Otherwise, // start validation on the subscription first. if (CellularNetworkValidator.isValidationFeatureSupported() && needValidation) { if (mValidator.isValidationFeatureSupported() && needValidation) { logDataSwitchEvent(subId, TelephonyEvent.EventState.EVENT_STATE_START, DataSwitch.Reason.DATA_SWITCH_REASON_CBRS); mSetOpptSubCallback = callback; mValidator.validate(subId, DEFAULT_VALIDATION_EXPIRATION_TIME, mValidator.validate(subIdToValidate, DEFAULT_VALIDATION_EXPIRATION_TIME, false, mValidationCallback); } else { setOpportunisticSubscriptionInternal(subId); Loading @@ -943,21 +953,6 @@ public class PhoneSwitcher extends Handler { } } /** * Unset opportunistic data subscription. It's an indication to switch Internet data back * from opportunistic subscription to primary subscription. */ private void unsetOpportunisticDataSubscription(ISetOpportunisticDataCallback callback) { if (mValidator.isValidating()) { mValidator.stopValidation(); } // Set mOpptDataSubId back to DEFAULT_SUBSCRIPTION_ID. This will trigger // data switch to mPrimaryDataSubId. setOpportunisticSubscriptionInternal(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS); } private void sendSetOpptCallbackHelper(ISetOpportunisticDataCallback callback, int result) { if (callback == null) return; try { Loading @@ -983,18 +978,45 @@ public class PhoneSwitcher extends Handler { } private void onValidationDone(int subId, boolean passed) { log("Network validation " + (passed ? "passed" : "failed") log("onValidationDone: " + (passed ? "passed" : "failed") + " on subId " + subId); if (passed) setOpportunisticSubscriptionInternal(subId); int resultForCallBack; if (!mSubscriptionController.isActiveSubId(subId)) { log("onValidationDone: subId " + subId + " is no longer active"); resultForCallBack = SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION; } else if (!passed) { resultForCallBack = SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED; } else { if (mSubscriptionController.isOpportunistic(subId)) { setOpportunisticSubscriptionInternal(subId); } else { // Switching data back to primary subscription. setOpportunisticSubscriptionInternal(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); } resultForCallBack = SET_OPPORTUNISTIC_SUB_SUCCESS; } // Trigger callback if needed sendSetOpptCallbackHelper(mSetOpptSubCallback, passed ? SET_OPPORTUNISTIC_SUB_SUCCESS : SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED); sendSetOpptCallbackHelper(mSetOpptSubCallback, resultForCallBack); mSetOpptSubCallback = null; } /** * Notify PhoneSwitcher to try to switch data to an opportunistic subscription. * * Set opportunistic data subscription. It's an indication to switch Internet data to this * subscription. It has to be an active subscription, and PhoneSwitcher will try to validate * it first if needed. If subId is DEFAULT_SUBSCRIPTION_ID, it means we are un-setting * opportunistic data sub and switch data back to primary sub. * * @param subId the opportunistic data subscription to switch to. pass DEFAULT_SUBSCRIPTION_ID * if un-setting it. * @param needValidation whether Telephony will wait until the network is validated by * connectivity service before switching data to it. More details see * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}. * @param callback Callback will be triggered once it succeeds or failed. * Pass null if don't care about the result. */ public void trySetOpportunisticDataSubscription(int subId, boolean needValidation, ISetOpportunisticDataCallback callback) { Loading tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java +51 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.internal.telephony; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; Loading Loading @@ -472,6 +473,56 @@ public class PhoneSwitcherTest extends TelephonyTest { } @Test @SmallTest public void testSetPreferredDataWithValidation() throws Exception { final int numPhones = 2; final int maxActivePhones = 1; doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported(); initialize(numPhones, maxActivePhones); // Phone 0 has sub 1, phone 1 has sub 2. // Sub 1 is default data sub. // Both are active subscriptions are active sub, as they are in both active slots. setSlotIndexToSubId(0, 1); setSlotIndexToSubId(1, 2); setDefaultDataSubId(1); // Mark sub 2 as opportunistic. doReturn(true).when(mSubscriptionController).isOpportunistic(2); // Phone 0 (sub 1) should be activated as it has default data sub. assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); // Set sub 2 as preferred sub should make phone 1 activated and phone 0 deactivated. mPhoneSwitcher.trySetOpportunisticDataSubscription(2, true, null); waitABit(); verify(mCellularNetworkValidator).validate(eq(2), anyInt(), eq(false), eq(mPhoneSwitcher.mValidationCallback)); // Validation failed. Preferred data sub should remain 1, data phone should remain 0. mPhoneSwitcher.mValidationCallback.onValidationResult(false, 2); waitABit(); assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); // Validation succeeds. Preferred data sub changes to 2, data phone changes to 1. mPhoneSwitcher.trySetOpportunisticDataSubscription(2, true, null); waitABit(); mPhoneSwitcher.mValidationCallback.onValidationResult(true, 2); waitABit(); assertEquals(1, mPhoneSwitcher.getPreferredDataPhoneId()); // Switching data back to primary (subId 1). mPhoneSwitcher.trySetOpportunisticDataSubscription( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true, null); waitABit(); verify(mCellularNetworkValidator).validate(eq(1), anyInt(), eq(false), eq(mPhoneSwitcher.mValidationCallback)); mPhoneSwitcher.mValidationCallback.onValidationResult(true, 1); waitABit(); assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); mHandlerThread.quit(); } @Test @SmallTest public void testNonDefaultDataPhoneInCall() throws Exception { Loading tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +1 −0 Original line number Diff line number Diff line Loading @@ -527,6 +527,7 @@ public abstract class TelephonyTest { // CellularNetworkValidator doReturn(SubscriptionManager.INVALID_PHONE_INDEX) .when(mCellularNetworkValidator).getSubIdInValidation(); doReturn(true).when(mCellularNetworkValidator).isValidationFeatureSupported(); //Use reflection to mock singletons replaceInstance(CallManager.class, "INSTANCE", null, mCallManager); Loading Loading
src/java/com/android/internal/telephony/CellularNetworkValidator.java +1 −1 Original line number Diff line number Diff line Loading @@ -94,7 +94,7 @@ public class CellularNetworkValidator { /** * Check whether this feature is supported or not. */ public static boolean isValidationFeatureSupported() { public boolean isValidationFeatureSupported() { return PhoneConfigurationManager.getInstance().getCurrentPhoneCapability() .validationBeforeSwitchSupported; } Loading
src/java/com/android/internal/telephony/PhoneSwitcher.java +52 −30 Original line number Diff line number Diff line Loading @@ -104,7 +104,8 @@ public class PhoneSwitcher extends Handler { @VisibleForTesting public final PhoneStateListener mPhoneStateListener; private final CellularNetworkValidator mValidator; private final CellularNetworkValidator.ValidationCallback mValidationCallback = @VisibleForTesting public final CellularNetworkValidator.ValidationCallback mValidationCallback = (validated, subId) -> Message.obtain(PhoneSwitcher.this, EVENT_NETWORK_VALIDATION_DONE, subId, validated ? 1 : 0).sendToTarget(); @UnsupportedAppUsage Loading Loading @@ -405,11 +406,7 @@ public class PhoneSwitcher extends Handler { boolean needValidation = (msg.arg2 == 1); ISetOpportunisticDataCallback callback = (ISetOpportunisticDataCallback) msg.obj; if (SubscriptionManager.isUsableSubscriptionId(subId)) { setOpportunisticDataSubscription(subId, needValidation, callback); } else { unsetOpportunisticDataSubscription(callback); } break; } case EVENT_RADIO_AVAILABLE: { Loading Loading @@ -909,18 +906,31 @@ public class PhoneSwitcher extends Handler { /** * Set opportunistic data subscription. It's an indication to switch Internet data to this * subscription. It has to be an active subscription, and PhoneSwitcher will try to validate * it first if needed. * it first if needed. If subId is DEFAULT_SUBSCRIPTION_ID, it means we are un-setting * opportunistic data sub and switch data back to primary sub. * * @param subId the opportunistic data subscription to switch to. pass DEFAULT_SUBSCRIPTION_ID * if un-setting it. * @param needValidation whether Telephony will wait until the network is validated by * connectivity service before switching data to it. More details see * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}. * @param callback Callback will be triggered once it succeeds or failed. * Pass null if don't care about the result. */ private void setOpportunisticDataSubscription(int subId, boolean needValidation, ISetOpportunisticDataCallback callback) { if (!mSubscriptionController.isActiveSubId(subId)) { if (!mSubscriptionController.isActiveSubId(subId) && subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { log("Can't switch data to inactive subId " + subId); sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION); return; } int subIdToValidate = (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) ? mPrimaryDataSubId : subId; if (mValidator.isValidating() && (!needValidation || subId != mValidator.getSubIdInValidation())) { && (!needValidation || subIdToValidate != mValidator.getSubIdInValidation())) { mValidator.stopValidation(); } Loading @@ -931,11 +941,11 @@ public class PhoneSwitcher extends Handler { // If validation feature is not supported, set it directly. Otherwise, // start validation on the subscription first. if (CellularNetworkValidator.isValidationFeatureSupported() && needValidation) { if (mValidator.isValidationFeatureSupported() && needValidation) { logDataSwitchEvent(subId, TelephonyEvent.EventState.EVENT_STATE_START, DataSwitch.Reason.DATA_SWITCH_REASON_CBRS); mSetOpptSubCallback = callback; mValidator.validate(subId, DEFAULT_VALIDATION_EXPIRATION_TIME, mValidator.validate(subIdToValidate, DEFAULT_VALIDATION_EXPIRATION_TIME, false, mValidationCallback); } else { setOpportunisticSubscriptionInternal(subId); Loading @@ -943,21 +953,6 @@ public class PhoneSwitcher extends Handler { } } /** * Unset opportunistic data subscription. It's an indication to switch Internet data back * from opportunistic subscription to primary subscription. */ private void unsetOpportunisticDataSubscription(ISetOpportunisticDataCallback callback) { if (mValidator.isValidating()) { mValidator.stopValidation(); } // Set mOpptDataSubId back to DEFAULT_SUBSCRIPTION_ID. This will trigger // data switch to mPrimaryDataSubId. setOpportunisticSubscriptionInternal(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS); } private void sendSetOpptCallbackHelper(ISetOpportunisticDataCallback callback, int result) { if (callback == null) return; try { Loading @@ -983,18 +978,45 @@ public class PhoneSwitcher extends Handler { } private void onValidationDone(int subId, boolean passed) { log("Network validation " + (passed ? "passed" : "failed") log("onValidationDone: " + (passed ? "passed" : "failed") + " on subId " + subId); if (passed) setOpportunisticSubscriptionInternal(subId); int resultForCallBack; if (!mSubscriptionController.isActiveSubId(subId)) { log("onValidationDone: subId " + subId + " is no longer active"); resultForCallBack = SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION; } else if (!passed) { resultForCallBack = SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED; } else { if (mSubscriptionController.isOpportunistic(subId)) { setOpportunisticSubscriptionInternal(subId); } else { // Switching data back to primary subscription. setOpportunisticSubscriptionInternal(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); } resultForCallBack = SET_OPPORTUNISTIC_SUB_SUCCESS; } // Trigger callback if needed sendSetOpptCallbackHelper(mSetOpptSubCallback, passed ? SET_OPPORTUNISTIC_SUB_SUCCESS : SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED); sendSetOpptCallbackHelper(mSetOpptSubCallback, resultForCallBack); mSetOpptSubCallback = null; } /** * Notify PhoneSwitcher to try to switch data to an opportunistic subscription. * * Set opportunistic data subscription. It's an indication to switch Internet data to this * subscription. It has to be an active subscription, and PhoneSwitcher will try to validate * it first if needed. If subId is DEFAULT_SUBSCRIPTION_ID, it means we are un-setting * opportunistic data sub and switch data back to primary sub. * * @param subId the opportunistic data subscription to switch to. pass DEFAULT_SUBSCRIPTION_ID * if un-setting it. * @param needValidation whether Telephony will wait until the network is validated by * connectivity service before switching data to it. More details see * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}. * @param callback Callback will be triggered once it succeeds or failed. * Pass null if don't care about the result. */ public void trySetOpportunisticDataSubscription(int subId, boolean needValidation, ISetOpportunisticDataCallback callback) { Loading
tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java +51 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.internal.telephony; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; Loading Loading @@ -472,6 +473,56 @@ public class PhoneSwitcherTest extends TelephonyTest { } @Test @SmallTest public void testSetPreferredDataWithValidation() throws Exception { final int numPhones = 2; final int maxActivePhones = 1; doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported(); initialize(numPhones, maxActivePhones); // Phone 0 has sub 1, phone 1 has sub 2. // Sub 1 is default data sub. // Both are active subscriptions are active sub, as they are in both active slots. setSlotIndexToSubId(0, 1); setSlotIndexToSubId(1, 2); setDefaultDataSubId(1); // Mark sub 2 as opportunistic. doReturn(true).when(mSubscriptionController).isOpportunistic(2); // Phone 0 (sub 1) should be activated as it has default data sub. assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); // Set sub 2 as preferred sub should make phone 1 activated and phone 0 deactivated. mPhoneSwitcher.trySetOpportunisticDataSubscription(2, true, null); waitABit(); verify(mCellularNetworkValidator).validate(eq(2), anyInt(), eq(false), eq(mPhoneSwitcher.mValidationCallback)); // Validation failed. Preferred data sub should remain 1, data phone should remain 0. mPhoneSwitcher.mValidationCallback.onValidationResult(false, 2); waitABit(); assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); // Validation succeeds. Preferred data sub changes to 2, data phone changes to 1. mPhoneSwitcher.trySetOpportunisticDataSubscription(2, true, null); waitABit(); mPhoneSwitcher.mValidationCallback.onValidationResult(true, 2); waitABit(); assertEquals(1, mPhoneSwitcher.getPreferredDataPhoneId()); // Switching data back to primary (subId 1). mPhoneSwitcher.trySetOpportunisticDataSubscription( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true, null); waitABit(); verify(mCellularNetworkValidator).validate(eq(1), anyInt(), eq(false), eq(mPhoneSwitcher.mValidationCallback)); mPhoneSwitcher.mValidationCallback.onValidationResult(true, 1); waitABit(); assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); mHandlerThread.quit(); } @Test @SmallTest public void testNonDefaultDataPhoneInCall() throws Exception { Loading
tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +1 −0 Original line number Diff line number Diff line Loading @@ -527,6 +527,7 @@ public abstract class TelephonyTest { // CellularNetworkValidator doReturn(SubscriptionManager.INVALID_PHONE_INDEX) .when(mCellularNetworkValidator).getSubIdInValidation(); doReturn(true).when(mCellularNetworkValidator).isValidationFeatureSupported(); //Use reflection to mock singletons replaceInstance(CallManager.class, "INSTANCE", null, mCallManager); Loading