1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony;
18 
19 import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
20 import static android.telephony.TelephonyManager.EXTRA_ACTIVE_SIM_SUPPORTED_COUNT;
21 
22 import static org.junit.Assert.assertEquals;
23 import static org.mockito.ArgumentMatchers.any;
24 import static org.mockito.ArgumentMatchers.anyBoolean;
25 import static org.mockito.ArgumentMatchers.anyInt;
26 import static org.mockito.ArgumentMatchers.anyLong;
27 import static org.mockito.ArgumentMatchers.eq;
28 import static org.mockito.Mockito.clearInvocations;
29 import static org.mockito.Mockito.doReturn;
30 import static org.mockito.Mockito.never;
31 import static org.mockito.Mockito.times;
32 import static org.mockito.Mockito.verify;
33 
34 import android.content.Intent;
35 import android.os.AsyncResult;
36 import android.os.Handler;
37 import android.os.Message;
38 import android.telephony.PhoneCapability;
39 import android.test.suitebuilder.annotation.SmallTest;
40 import android.testing.AndroidTestingRunner;
41 import android.testing.TestableLooper;
42 
43 import org.junit.After;
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 import org.mockito.ArgumentCaptor;
48 import org.mockito.Mock;
49 
50 @RunWith(AndroidTestingRunner.class)
51 @TestableLooper.RunWithLooper
52 public class PhoneConfigurationManagerTest extends TelephonyTest {
53     @Mock
54     Handler mHandler;
55     @Mock
56     CommandsInterface mMockCi0;
57     @Mock
58     CommandsInterface mMockCi1;
59     @Mock
60     private Phone mPhone1; // mPhone as phone 0 is already defined in TelephonyTest.
61     @Mock
62     PhoneConfigurationManager.MockableInterface mMi;
63 
64     private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 1;
65     PhoneConfigurationManager mPcm;
66 
67     @Before
setUp()68     public void setUp() throws Exception {
69         super.setUp(getClass().getSimpleName());
70         mPhone.mCi = mMockCi0;
71         mCT.mCi = mMockCi0;
72         mPhone1.mCi = mMockCi1;
73     }
74 
75     @After
tearDown()76     public void tearDown() throws Exception {
77         // Restore system properties.
78         super.tearDown();
79     }
80 
setRebootRequiredForConfigSwitch(boolean rebootRequired)81     private void setRebootRequiredForConfigSwitch(boolean rebootRequired) {
82         doReturn(rebootRequired).when(mMi).isRebootRequiredForModemConfigChange();
83     }
84 
init(int numOfSim)85     private void init(int numOfSim) throws Exception {
86         doReturn(numOfSim).when(mTelephonyManager).getActiveModemCount();
87         replaceInstance(PhoneConfigurationManager.class, "sInstance", null, null);
88         mPcm = PhoneConfigurationManager.init(mContext);
89         replaceInstance(PhoneConfigurationManager.class, "mMi", mPcm, mMi);
90         processAllMessages();
91     }
92 
93     /**
94      * Test that a single phone case results in our phone being active and the RIL called
95      */
96     @Test
97     @SmallTest
testGetPhoneCount()98     public void testGetPhoneCount() throws Exception {
99         init(1);
100         doReturn(1).when(mTelephonyManager).getActiveModemCount();
101         assertEquals(1, mPcm.getPhoneCount());
102         doReturn(2).when(mTelephonyManager).getActiveModemCount();
103         assertEquals(2, mPcm.getPhoneCount());
104     }
105 
106     @Test
107     @SmallTest
testEnablePhone()108     public void testEnablePhone() throws Exception {
109         init(1);
110         // Phone is null. No crash.
111         mPcm.enablePhone(null, true, null);
112 
113         Message message = new Message();
114         mPcm.enablePhone(mPhone, false, message);
115         verify(mMockCi0).enableModem(eq(false), eq(message));
116     }
117 
118     @Test
119     @SmallTest
testGetDsdsCapability()120     public void testGetDsdsCapability() throws Exception {
121         init(1);
122         assertEquals(PhoneCapability.DEFAULT_SSSS_CAPABILITY, mPcm.getStaticPhoneCapability());
123 
124         ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
125         verify(mMockRadioConfig).getPhoneCapability(captor.capture());
126         Message msg = captor.getValue();
127         AsyncResult.forMessage(msg, PhoneCapability.DEFAULT_DSDS_CAPABILITY, null);
128         msg.sendToTarget();
129         processAllMessages();
130 
131         // Not static capability should indicate DSDS capable.
132         assertEquals(PhoneCapability.DEFAULT_DSDS_CAPABILITY, mPcm.getStaticPhoneCapability());
133     }
134 
135     @Test
136     @SmallTest
testSwitchMultiSimConfig_notDsdsCapable_shouldFail()137     public void testSwitchMultiSimConfig_notDsdsCapable_shouldFail() throws Exception {
138         init(1);
139         assertEquals(PhoneCapability.DEFAULT_SSSS_CAPABILITY, mPcm.getStaticPhoneCapability());
140 
141         // Try switching to dual SIM. Shouldn't work as we haven't indicated DSDS is supported.
142         mPcm.switchMultiSimConfig(2);
143         verify(mMockRadioConfig, never()).setModemsConfig(anyInt(), any());
144     }
145 
146     @Test
147     @SmallTest
testSwitchMultiSimConfig_dsdsCapable_noRebootRequired()148     public void testSwitchMultiSimConfig_dsdsCapable_noRebootRequired() throws Exception {
149         init(1);
150         verify(mMockCi0, times(1)).registerForAvailable(any(), anyInt(), any());
151 
152         // Register for multi SIM config change.
153         mPcm.registerForMultiSimConfigChange(mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null);
154         verify(mHandler, never()).sendMessageAtTime(any(), anyLong());
155 
156         // Try switching to dual SIM. Shouldn't work as we haven't indicated DSDS is supported.
157         mPcm.switchMultiSimConfig(2);
158         verify(mMockRadioConfig, never()).setModemsConfig(anyInt(), any());
159 
160         // Send static capability back to indicate DSDS is supported.
161         clearInvocations(mMockRadioConfig);
162         testGetDsdsCapability();
163         // testGetDsdsCapability leads to another call to registerForAvailable()
164         verify(mMockCi0, times(2)).registerForAvailable(any(), anyInt(), any());
165 
166         // Try to switch to DSDS.
167         setRebootRequiredForConfigSwitch(false);
168         mPhones = new Phone[]{mPhone, mPhone1};
169         replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
170         mPcm.switchMultiSimConfig(2);
171         ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
172         verify(mMockRadioConfig).setModemsConfig(eq(2), captor.capture());
173 
174         // Send message back to indicate switch success.
175         Message message = captor.getValue();
176         AsyncResult.forMessage(message, null, null);
177         message.sendToTarget();
178         processAllMessages();
179 
180         // Verify set system property being called.
181         verify(mMi).setMultiSimProperties(2);
182         verify(mMi).notifyPhoneFactoryOnMultiSimConfigChanged(any(), eq(2));
183 
184         // Capture and verify registration notification.
185         verify(mHandler).sendMessageAtTime(captor.capture(), anyLong());
186         message = captor.getValue();
187         assertEquals(EVENT_MULTI_SIM_CONFIG_CHANGED, message.what);
188         assertEquals(2, ((AsyncResult) message.obj).result);
189 
190         // Capture and verify broadcast.
191         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
192         verify(mContext).sendBroadcast(intentCaptor.capture());
193         Intent intent = intentCaptor.getValue();
194         assertEquals(ACTION_MULTI_SIM_CONFIG_CHANGED, intent.getAction());
195         assertEquals(2, intent.getIntExtra(
196                 EXTRA_ACTIVE_SIM_SUPPORTED_COUNT, 0));
197 
198         // Verify registerForAvailable() and onSlotActiveStatusChange() are called for the second
199         // phone, and not for the first phone (registerForAvailable() was already called twice
200         // earlier so verify that the count is still at 2)
201         verify(mMockCi0, times(2)).registerForAvailable(any(), anyInt(), any());
202         verify(mMockCi0, never()).onSlotActiveStatusChange(anyBoolean());
203         verify(mMockCi1, times(1)).registerForAvailable(any(), anyInt(), any());
204         verify(mMockCi1, times(1)).onSlotActiveStatusChange(anyBoolean());
205     }
206 
207     @Test
208     @SmallTest
testSwitchMultiSimConfig_multiSimToSingleSim()209     public void testSwitchMultiSimConfig_multiSimToSingleSim() throws Exception {
210         mPhones = new Phone[]{mPhone, mPhone1};
211         replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
212         init(2);
213         verify(mMockCi0, times(1)).registerForAvailable(any(), anyInt(), any());
214         verify(mMockCi1, times(1)).registerForAvailable(any(), anyInt(), any());
215 
216         // Register for multi SIM config change.
217         mPcm.registerForMultiSimConfigChange(mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null);
218         verify(mHandler, never()).sendMessageAtTime(any(), anyLong());
219 
220         // Switch to single sim.
221         setRebootRequiredForConfigSwitch(false);
222         mPcm.switchMultiSimConfig(1);
223         ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
224         verify(mMockRadioConfig).setModemsConfig(eq(1), captor.capture());
225 
226         // Send message back to indicate switch success.
227         Message message = captor.getValue();
228         AsyncResult.forMessage(message, null, null);
229         message.sendToTarget();
230         processAllMessages();
231 
232         // Verify set system property being called.
233         verify(mMi).setMultiSimProperties(1);
234         verify(mMi).notifyPhoneFactoryOnMultiSimConfigChanged(any(), eq(1));
235 
236         // Capture and verify registration notification.
237         verify(mHandler).sendMessageAtTime(captor.capture(), anyLong());
238         message = captor.getValue();
239         assertEquals(EVENT_MULTI_SIM_CONFIG_CHANGED, message.what);
240         assertEquals(1, ((AsyncResult) message.obj).result);
241 
242         // Capture and verify broadcast.
243         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
244         verify(mContext).sendBroadcast(intentCaptor.capture());
245         Intent intent = intentCaptor.getValue();
246         assertEquals(ACTION_MULTI_SIM_CONFIG_CHANGED, intent.getAction());
247         assertEquals(1, intent.getIntExtra(
248                 EXTRA_ACTIVE_SIM_SUPPORTED_COUNT, 0));
249 
250         // Verify clearSubInfoRecord() and onSlotActiveStatusChange() are called for second phone,
251         // and not for the first one
252         verify(mSubscriptionController).clearSubInfoRecord(1);
253         verify(mMockCi1).onSlotActiveStatusChange(anyBoolean());
254         verify(mSubscriptionController, never()).clearSubInfoRecord(0);
255         verify(mMockCi0, never()).onSlotActiveStatusChange(anyBoolean());
256 
257         // Verify onPhoneRemoved() gets called on MultiSimSettingController phone
258         verify(mMultiSimSettingController).onPhoneRemoved();
259     }
260 }
261