Loading src/java/com/android/internal/telephony/PhoneConfigurationManager.java +18 −0 Original line number Diff line number Diff line Loading @@ -397,6 +397,24 @@ public class PhoneConfigurationManager { registerForRadioState(phone); phone.mCi.onSlotActiveStatusChange(SubscriptionManager.isValidPhoneId(phoneId)); } // When the user enables DSDS mode, the default VOICE and SMS subId should be switched // to "No Preference". Doing so will sync the network/sim settings and telephony. // (see b/198123192) if (numOfActiveModems > oldNumOfActiveModems && numOfActiveModems == 2) { Log.i(LOG_TAG, " onMultiSimConfigChanged: DSDS mode enabled; " + "setting VOICE & SMS subId to -1 (No Preference)"); //Set the default VOICE subId to -1 ("No Preference") SubscriptionController.getInstance().setDefaultVoiceSubId( SubscriptionManager.INVALID_SUBSCRIPTION_ID); //TODO:: Set the default SMS sub to "No Preference". Tracking this bug (b/227386042) } else { Log.i(LOG_TAG, "onMultiSimConfigChanged: DSDS mode NOT detected. NOT setting the " + "default VOICE and SMS subId to -1 (No Preference)"); } } } Loading tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java +101 −45 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; Loading @@ -37,6 +38,7 @@ import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.telephony.PhoneCapability; import android.telephony.SubscriptionManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; Loading @@ -46,6 +48,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper Loading Loading @@ -148,29 +151,27 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { @SmallTest public void testSwitchMultiSimConfig_dsdsCapable_noRebootRequired() throws Exception { init(1); testSwitchFromSingleToDualSimModeNoReboot(); } @Test @SmallTest public void testSwitchMultiSimConfig_multiSimToSingleSim() throws Exception { mPhones = new Phone[]{mPhone, mPhone1}; replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); init(2); verify(mMockCi0, times(1)).registerForAvailable(any(), anyInt(), any()); verify(mMockCi1, times(1)).registerForAvailable(any(), anyInt(), any()); // Register for multi SIM config change. mPcm.registerForMultiSimConfigChange(mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null); verify(mHandler, never()).sendMessageAtTime(any(), anyLong()); // Try switching to dual SIM. Shouldn't work as we haven't indicated DSDS is supported. mPcm.switchMultiSimConfig(2); verify(mMockRadioConfig, never()).setNumOfLiveModems(anyInt(), any()); // Send static capability back to indicate DSDS is supported. clearInvocations(mMockRadioConfig); testGetDsdsCapability(); // testGetDsdsCapability leads to another call to registerForAvailable() verify(mMockCi0, times(2)).registerForAvailable(any(), anyInt(), any()); // Try to switch to DSDS. // Switch to single sim. setRebootRequiredForConfigSwitch(false); mPhones = new Phone[]{mPhone, mPhone1}; replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); mPcm.switchMultiSimConfig(2); mPcm.switchMultiSimConfig(1); ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class); verify(mMockRadioConfig).setNumOfLiveModems(eq(2), captor.capture()); verify(mMockRadioConfig).setNumOfLiveModems(eq(1), captor.capture()); // Send message back to indicate switch success. Message message = captor.getValue(); Loading @@ -179,50 +180,107 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { processAllMessages(); // Verify set system property being called. verify(mMi).setMultiSimProperties(2); verify(mMi).notifyPhoneFactoryOnMultiSimConfigChanged(any(), eq(2)); verify(mMi).setMultiSimProperties(1); verify(mMi).notifyPhoneFactoryOnMultiSimConfigChanged(any(), eq(1)); // Capture and verify registration notification. verify(mHandler).sendMessageAtTime(captor.capture(), anyLong()); message = captor.getValue(); assertEquals(EVENT_MULTI_SIM_CONFIG_CHANGED, message.what); assertEquals(2, ((AsyncResult) message.obj).result); assertEquals(1, ((AsyncResult) message.obj).result); // Capture and verify broadcast. ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext).sendBroadcast(intentCaptor.capture()); Intent intent = intentCaptor.getValue(); assertEquals(ACTION_MULTI_SIM_CONFIG_CHANGED, intent.getAction()); assertEquals(2, intent.getIntExtra( assertEquals(1, intent.getIntExtra( EXTRA_ACTIVE_SIM_SUPPORTED_COUNT, 0)); // Verify registerForAvailable() and onSlotActiveStatusChange() are called for the second // phone, and not for the first phone (registerForAvailable() was already called twice // earlier so verify that the count is still at 2) verify(mMockCi0, times(2)).registerForAvailable(any(), anyInt(), any()); // Verify clearSubInfoRecord() and onSlotActiveStatusChange() are called for second phone, // and not for the first one verify(mSubscriptionController).clearSubInfoRecord(1); verify(mMockCi1).onSlotActiveStatusChange(anyBoolean()); verify(mSubscriptionController, never()).clearSubInfoRecord(0); verify(mMockCi0, never()).onSlotActiveStatusChange(anyBoolean()); verify(mMockCi1, times(1)).registerForAvailable(any(), anyInt(), any()); verify(mMockCi1, times(1)).onSlotActiveStatusChange(anyBoolean()); // Verify onPhoneRemoved() gets called on MultiSimSettingController phone verify(mMultiSimSettingController).onPhoneRemoved(); } @Test @SmallTest public void testSwitchMultiSimConfig_multiSimToSingleSim() throws Exception { mPhones = new Phone[]{mPhone, mPhone1}; replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); init(2); public void testNoCallPreferenceIsSetAfterSwitchToDsdsMode() throws Exception { final int startingDefaultSubscriptionId = 2; // arbitrary value (can't be -1 which // represents the "No Call Preference" value) /* TL;DR: the following mockito code block dynamically changes the last call to the getter doAnswer(invocation -> { Integer value = (Integer) invocation.getArguments()[0]; Mockito.when(object.getter()).thenReturn(value); return null; }).when(object).setter(anyInt()); read the code block as, whenever we call the setter, change the Mock call of the getter to whatever argument value we last passed to the setter. ex.) object.set( 2 ) --> next call to object.get() will return 2 */ // setup mocks for VOICE mSubscriptionController. getter/setter doAnswer(invocation -> { Integer value = (Integer) invocation.getArguments()[0]; Mockito.when(mSubscriptionController.getDefaultVoiceSubId()).thenReturn(value); return null; }).when(mSubscriptionController).setDefaultVoiceSubId(anyInt()); // start off the phone stat with 1 active sim. reset values for new test. init(1); mSubscriptionController.setDefaultVoiceSubId(startingDefaultSubscriptionId); // assert the mSubscriptionController registers the change assertEquals(startingDefaultSubscriptionId, mSubscriptionController.getDefaultVoiceSubId()); // Perform the switch to DSDS mode and ensure all existing checks are not altered testSwitchFromSingleToDualSimModeNoReboot(); // VOICE check assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID /* No CALL Preference value */, mSubscriptionController.getDefaultVoiceSubId()); // Now, when the user goes to // place a CALL, they will be prompted on which sim to use. } /** * must call init(1) from the parent test before calling this helper test * @throws Exception */ public void testSwitchFromSingleToDualSimModeNoReboot() throws Exception { verify(mMockCi0, times(1)).registerForAvailable(any(), anyInt(), any()); verify(mMockCi1, times(1)).registerForAvailable(any(), anyInt(), any()); // Register for multi SIM config change. mPcm.registerForMultiSimConfigChange(mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null); verify(mHandler, never()).sendMessageAtTime(any(), anyLong()); // Switch to single sim. // Try switching to dual SIM. Shouldn't work as we haven't indicated DSDS is supported. mPcm.switchMultiSimConfig(2); verify(mMockRadioConfig, never()).setNumOfLiveModems(anyInt(), any()); // Send static capability back to indicate DSDS is supported. clearInvocations(mMockRadioConfig); testGetDsdsCapability(); // testGetDsdsCapability leads to another call to registerForAvailable() verify(mMockCi0, times(2)).registerForAvailable(any(), anyInt(), any()); // Try to switch to DSDS. setRebootRequiredForConfigSwitch(false); mPcm.switchMultiSimConfig(1); mPhones = new Phone[]{mPhone, mPhone1}; replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); mPcm.switchMultiSimConfig(2); ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class); verify(mMockRadioConfig).setNumOfLiveModems(eq(1), captor.capture()); verify(mMockRadioConfig).setNumOfLiveModems(eq(2), captor.capture()); // Send message back to indicate switch success. Message message = captor.getValue(); Loading @@ -231,31 +289,29 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { processAllMessages(); // Verify set system property being called. verify(mMi).setMultiSimProperties(1); verify(mMi).notifyPhoneFactoryOnMultiSimConfigChanged(any(), eq(1)); verify(mMi).setMultiSimProperties(2); verify(mMi).notifyPhoneFactoryOnMultiSimConfigChanged(any(), eq(2)); // Capture and verify registration notification. verify(mHandler).sendMessageAtTime(captor.capture(), anyLong()); message = captor.getValue(); assertEquals(EVENT_MULTI_SIM_CONFIG_CHANGED, message.what); assertEquals(1, ((AsyncResult) message.obj).result); assertEquals(2, ((AsyncResult) message.obj).result); // Capture and verify broadcast. ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext).sendBroadcast(intentCaptor.capture()); Intent intent = intentCaptor.getValue(); assertEquals(ACTION_MULTI_SIM_CONFIG_CHANGED, intent.getAction()); assertEquals(1, intent.getIntExtra( assertEquals(2, intent.getIntExtra( EXTRA_ACTIVE_SIM_SUPPORTED_COUNT, 0)); // Verify clearSubInfoRecord() and onSlotActiveStatusChange() are called for second phone, // and not for the first one verify(mSubscriptionController).clearSubInfoRecord(1); verify(mMockCi1).onSlotActiveStatusChange(anyBoolean()); verify(mSubscriptionController, never()).clearSubInfoRecord(0); // Verify registerForAvailable() and onSlotActiveStatusChange() are called for the second // phone, and not for the first phone (registerForAvailable() was already called twice // earlier so verify that the count is still at 2) verify(mMockCi0, times(2)).registerForAvailable(any(), anyInt(), any()); verify(mMockCi0, never()).onSlotActiveStatusChange(anyBoolean()); // Verify onPhoneRemoved() gets called on MultiSimSettingController phone verify(mMultiSimSettingController).onPhoneRemoved(); verify(mMockCi1, times(1)).registerForAvailable(any(), anyInt(), any()); verify(mMockCi1, times(1)).onSlotActiveStatusChange(anyBoolean()); } } Loading
src/java/com/android/internal/telephony/PhoneConfigurationManager.java +18 −0 Original line number Diff line number Diff line Loading @@ -397,6 +397,24 @@ public class PhoneConfigurationManager { registerForRadioState(phone); phone.mCi.onSlotActiveStatusChange(SubscriptionManager.isValidPhoneId(phoneId)); } // When the user enables DSDS mode, the default VOICE and SMS subId should be switched // to "No Preference". Doing so will sync the network/sim settings and telephony. // (see b/198123192) if (numOfActiveModems > oldNumOfActiveModems && numOfActiveModems == 2) { Log.i(LOG_TAG, " onMultiSimConfigChanged: DSDS mode enabled; " + "setting VOICE & SMS subId to -1 (No Preference)"); //Set the default VOICE subId to -1 ("No Preference") SubscriptionController.getInstance().setDefaultVoiceSubId( SubscriptionManager.INVALID_SUBSCRIPTION_ID); //TODO:: Set the default SMS sub to "No Preference". Tracking this bug (b/227386042) } else { Log.i(LOG_TAG, "onMultiSimConfigChanged: DSDS mode NOT detected. NOT setting the " + "default VOICE and SMS subId to -1 (No Preference)"); } } } Loading
tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java +101 −45 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; Loading @@ -37,6 +38,7 @@ import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.telephony.PhoneCapability; import android.telephony.SubscriptionManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; Loading @@ -46,6 +48,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper Loading Loading @@ -148,29 +151,27 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { @SmallTest public void testSwitchMultiSimConfig_dsdsCapable_noRebootRequired() throws Exception { init(1); testSwitchFromSingleToDualSimModeNoReboot(); } @Test @SmallTest public void testSwitchMultiSimConfig_multiSimToSingleSim() throws Exception { mPhones = new Phone[]{mPhone, mPhone1}; replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); init(2); verify(mMockCi0, times(1)).registerForAvailable(any(), anyInt(), any()); verify(mMockCi1, times(1)).registerForAvailable(any(), anyInt(), any()); // Register for multi SIM config change. mPcm.registerForMultiSimConfigChange(mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null); verify(mHandler, never()).sendMessageAtTime(any(), anyLong()); // Try switching to dual SIM. Shouldn't work as we haven't indicated DSDS is supported. mPcm.switchMultiSimConfig(2); verify(mMockRadioConfig, never()).setNumOfLiveModems(anyInt(), any()); // Send static capability back to indicate DSDS is supported. clearInvocations(mMockRadioConfig); testGetDsdsCapability(); // testGetDsdsCapability leads to another call to registerForAvailable() verify(mMockCi0, times(2)).registerForAvailable(any(), anyInt(), any()); // Try to switch to DSDS. // Switch to single sim. setRebootRequiredForConfigSwitch(false); mPhones = new Phone[]{mPhone, mPhone1}; replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); mPcm.switchMultiSimConfig(2); mPcm.switchMultiSimConfig(1); ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class); verify(mMockRadioConfig).setNumOfLiveModems(eq(2), captor.capture()); verify(mMockRadioConfig).setNumOfLiveModems(eq(1), captor.capture()); // Send message back to indicate switch success. Message message = captor.getValue(); Loading @@ -179,50 +180,107 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { processAllMessages(); // Verify set system property being called. verify(mMi).setMultiSimProperties(2); verify(mMi).notifyPhoneFactoryOnMultiSimConfigChanged(any(), eq(2)); verify(mMi).setMultiSimProperties(1); verify(mMi).notifyPhoneFactoryOnMultiSimConfigChanged(any(), eq(1)); // Capture and verify registration notification. verify(mHandler).sendMessageAtTime(captor.capture(), anyLong()); message = captor.getValue(); assertEquals(EVENT_MULTI_SIM_CONFIG_CHANGED, message.what); assertEquals(2, ((AsyncResult) message.obj).result); assertEquals(1, ((AsyncResult) message.obj).result); // Capture and verify broadcast. ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext).sendBroadcast(intentCaptor.capture()); Intent intent = intentCaptor.getValue(); assertEquals(ACTION_MULTI_SIM_CONFIG_CHANGED, intent.getAction()); assertEquals(2, intent.getIntExtra( assertEquals(1, intent.getIntExtra( EXTRA_ACTIVE_SIM_SUPPORTED_COUNT, 0)); // Verify registerForAvailable() and onSlotActiveStatusChange() are called for the second // phone, and not for the first phone (registerForAvailable() was already called twice // earlier so verify that the count is still at 2) verify(mMockCi0, times(2)).registerForAvailable(any(), anyInt(), any()); // Verify clearSubInfoRecord() and onSlotActiveStatusChange() are called for second phone, // and not for the first one verify(mSubscriptionController).clearSubInfoRecord(1); verify(mMockCi1).onSlotActiveStatusChange(anyBoolean()); verify(mSubscriptionController, never()).clearSubInfoRecord(0); verify(mMockCi0, never()).onSlotActiveStatusChange(anyBoolean()); verify(mMockCi1, times(1)).registerForAvailable(any(), anyInt(), any()); verify(mMockCi1, times(1)).onSlotActiveStatusChange(anyBoolean()); // Verify onPhoneRemoved() gets called on MultiSimSettingController phone verify(mMultiSimSettingController).onPhoneRemoved(); } @Test @SmallTest public void testSwitchMultiSimConfig_multiSimToSingleSim() throws Exception { mPhones = new Phone[]{mPhone, mPhone1}; replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); init(2); public void testNoCallPreferenceIsSetAfterSwitchToDsdsMode() throws Exception { final int startingDefaultSubscriptionId = 2; // arbitrary value (can't be -1 which // represents the "No Call Preference" value) /* TL;DR: the following mockito code block dynamically changes the last call to the getter doAnswer(invocation -> { Integer value = (Integer) invocation.getArguments()[0]; Mockito.when(object.getter()).thenReturn(value); return null; }).when(object).setter(anyInt()); read the code block as, whenever we call the setter, change the Mock call of the getter to whatever argument value we last passed to the setter. ex.) object.set( 2 ) --> next call to object.get() will return 2 */ // setup mocks for VOICE mSubscriptionController. getter/setter doAnswer(invocation -> { Integer value = (Integer) invocation.getArguments()[0]; Mockito.when(mSubscriptionController.getDefaultVoiceSubId()).thenReturn(value); return null; }).when(mSubscriptionController).setDefaultVoiceSubId(anyInt()); // start off the phone stat with 1 active sim. reset values for new test. init(1); mSubscriptionController.setDefaultVoiceSubId(startingDefaultSubscriptionId); // assert the mSubscriptionController registers the change assertEquals(startingDefaultSubscriptionId, mSubscriptionController.getDefaultVoiceSubId()); // Perform the switch to DSDS mode and ensure all existing checks are not altered testSwitchFromSingleToDualSimModeNoReboot(); // VOICE check assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID /* No CALL Preference value */, mSubscriptionController.getDefaultVoiceSubId()); // Now, when the user goes to // place a CALL, they will be prompted on which sim to use. } /** * must call init(1) from the parent test before calling this helper test * @throws Exception */ public void testSwitchFromSingleToDualSimModeNoReboot() throws Exception { verify(mMockCi0, times(1)).registerForAvailable(any(), anyInt(), any()); verify(mMockCi1, times(1)).registerForAvailable(any(), anyInt(), any()); // Register for multi SIM config change. mPcm.registerForMultiSimConfigChange(mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null); verify(mHandler, never()).sendMessageAtTime(any(), anyLong()); // Switch to single sim. // Try switching to dual SIM. Shouldn't work as we haven't indicated DSDS is supported. mPcm.switchMultiSimConfig(2); verify(mMockRadioConfig, never()).setNumOfLiveModems(anyInt(), any()); // Send static capability back to indicate DSDS is supported. clearInvocations(mMockRadioConfig); testGetDsdsCapability(); // testGetDsdsCapability leads to another call to registerForAvailable() verify(mMockCi0, times(2)).registerForAvailable(any(), anyInt(), any()); // Try to switch to DSDS. setRebootRequiredForConfigSwitch(false); mPcm.switchMultiSimConfig(1); mPhones = new Phone[]{mPhone, mPhone1}; replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); mPcm.switchMultiSimConfig(2); ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class); verify(mMockRadioConfig).setNumOfLiveModems(eq(1), captor.capture()); verify(mMockRadioConfig).setNumOfLiveModems(eq(2), captor.capture()); // Send message back to indicate switch success. Message message = captor.getValue(); Loading @@ -231,31 +289,29 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { processAllMessages(); // Verify set system property being called. verify(mMi).setMultiSimProperties(1); verify(mMi).notifyPhoneFactoryOnMultiSimConfigChanged(any(), eq(1)); verify(mMi).setMultiSimProperties(2); verify(mMi).notifyPhoneFactoryOnMultiSimConfigChanged(any(), eq(2)); // Capture and verify registration notification. verify(mHandler).sendMessageAtTime(captor.capture(), anyLong()); message = captor.getValue(); assertEquals(EVENT_MULTI_SIM_CONFIG_CHANGED, message.what); assertEquals(1, ((AsyncResult) message.obj).result); assertEquals(2, ((AsyncResult) message.obj).result); // Capture and verify broadcast. ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext).sendBroadcast(intentCaptor.capture()); Intent intent = intentCaptor.getValue(); assertEquals(ACTION_MULTI_SIM_CONFIG_CHANGED, intent.getAction()); assertEquals(1, intent.getIntExtra( assertEquals(2, intent.getIntExtra( EXTRA_ACTIVE_SIM_SUPPORTED_COUNT, 0)); // Verify clearSubInfoRecord() and onSlotActiveStatusChange() are called for second phone, // and not for the first one verify(mSubscriptionController).clearSubInfoRecord(1); verify(mMockCi1).onSlotActiveStatusChange(anyBoolean()); verify(mSubscriptionController, never()).clearSubInfoRecord(0); // Verify registerForAvailable() and onSlotActiveStatusChange() are called for the second // phone, and not for the first phone (registerForAvailable() was already called twice // earlier so verify that the count is still at 2) verify(mMockCi0, times(2)).registerForAvailable(any(), anyInt(), any()); verify(mMockCi0, never()).onSlotActiveStatusChange(anyBoolean()); // Verify onPhoneRemoved() gets called on MultiSimSettingController phone verify(mMultiSimSettingController).onPhoneRemoved(); verify(mMockCi1, times(1)).registerForAvailable(any(), anyInt(), any()); verify(mMockCi1, times(1)).onSlotActiveStatusChange(anyBoolean()); } }