1/* 2 * Copyright (C) 2016 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 */ 16package com.android.internal.telephony; 17 18import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; 19 20import static org.junit.Assert.assertEquals; 21import static org.junit.Assert.assertNotNull; 22import static org.mockito.Mockito.any; 23import static org.mockito.Mockito.anyInt; 24import static org.mockito.Mockito.doReturn; 25import static org.mockito.Mockito.eq; 26import static org.mockito.Mockito.isA; 27import static org.mockito.Mockito.times; 28import static org.mockito.Mockito.verify; 29 30import android.os.Handler; 31import android.os.HandlerThread; 32import android.os.Message; 33import android.support.test.filters.FlakyTest; 34import android.telephony.DisconnectCause; 35import android.telephony.PhoneNumberUtils; 36import android.telephony.ServiceState; 37import android.test.suitebuilder.annotation.MediumTest; 38import android.test.suitebuilder.annotation.SmallTest; 39 40import org.junit.After; 41import org.junit.Assert; 42import org.junit.Before; 43import org.junit.Ignore; 44import org.junit.Test; 45import org.mockito.ArgumentCaptor; 46import org.mockito.Mock; 47 48public class GsmCdmaCallTrackerTest extends TelephonyTest { 49 private static final int VOICE_CALL_STARTED_EVENT = 0; 50 private static final int VOICE_CALL_ENDED_EVENT = 1; 51 private String mDialString = PhoneNumberUtils.stripSeparators("+17005554141"); 52 /* Handler class initiated at the HandlerThread */ 53 private GsmCdmaCallTracker mCTUT; 54 private GsmCdmaCTHandlerThread mGsmCdmaCTHandlerThread; 55 @Mock 56 GsmCdmaCall mCall; 57 @Mock 58 private Handler mHandler; 59 60 private class GsmCdmaCTHandlerThread extends HandlerThread { 61 62 private GsmCdmaCTHandlerThread(String name) { 63 super(name); 64 } 65 @Override 66 public void onLooperPrepared() { 67 mCTUT = new GsmCdmaCallTracker(mPhone); 68 setReady(true); 69 } 70 } 71 72 @Before 73 public void setUp() throws Exception { 74 super.setUp(this.getClass().getSimpleName()); 75 mSimulatedCommands.setRadioPower(true, null); 76 mPhone.mCi = this.mSimulatedCommands; 77 78 mGsmCdmaCTHandlerThread = new GsmCdmaCTHandlerThread(TAG); 79 mGsmCdmaCTHandlerThread.start(); 80 81 waitUntilReady(); 82 logd("GsmCdmaCallTracker initiated, waiting for Power on"); 83 /* Make sure radio state is power on before dial. 84 * When radio state changed from off to on, CallTracker 85 * will poll result from RIL. Avoid dialing triggered at the same*/ 86 waitForMs(100); 87 } 88 89 @After 90 public void tearDown() throws Exception { 91 mCTUT = null; 92 mGsmCdmaCTHandlerThread.quit(); 93 super.tearDown(); 94 } 95 96 @Test 97 @SmallTest 98 public void testMOCallDial() { 99 doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState(); 100 assertEquals(PhoneConstants.State.IDLE, mCTUT.getState()); 101 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState()); 102 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState()); 103 assertEquals(0, mCTUT.mForegroundCall.getConnections().size()); 104 try { 105 mCTUT.dial(mDialString); 106 waitForMs(100); 107 } catch(Exception ex) { 108 ex.printStackTrace(); 109 Assert.fail("unexpected exception thrown"+ex.getMessage()+ex.getStackTrace()); 110 } 111 112 assertEquals(PhoneConstants.State.OFFHOOK, mCTUT.getState()); 113 assertEquals(GsmCdmaCall.State.DIALING, mCTUT.mForegroundCall.getState()); 114 assertEquals(1, mCTUT.mForegroundCall.getConnections().size()); 115 /* verify the command is sent out to RIL */ 116 verify(mSimulatedCommandsVerifier).dial(eq(PhoneNumberUtils. 117 extractNetworkPortionAlt(mDialString)), anyInt(), 118 eq((UUSInfo) null), 119 isA(Message.class)); 120 } 121 122 @Test 123 @SmallTest 124 public void testMOCallPickUp() { 125 testMOCallDial(); 126 logd("Waiting for POLL CALL response from RIL"); 127 TelephonyTestUtils.waitForMs(50); 128 logd("Pick Up MO call, expecting call state change event "); 129 mSimulatedCommands.progressConnectingToActive(); 130 waitForMs(100); 131 assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState()); 132 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState()); 133 } 134 135 @FlakyTest 136 @Ignore 137 @Test 138 @MediumTest 139 public void testMOCallHangup() { 140 testMOCallDial(); 141 logd("Waiting for POLL CALL response from RIL "); 142 TelephonyTestUtils.waitForMs(50); 143 assertEquals(GsmCdmaCall.State.DIALING, mCTUT.mForegroundCall.getState()); 144 assertEquals(PhoneConstants.State.OFFHOOK, mCTUT.getState()); 145 assertEquals(1, mCTUT.mForegroundCall.getConnections().size()); 146 logd("Hang up MO call after MO call established "); 147 try { 148 mCTUT.hangup(mCTUT.mForegroundCall); 149 } catch(Exception ex) { 150 ex.printStackTrace(); 151 Assert.fail("unexpected exception thrown" + ex.getMessage()); 152 } 153 waitForMs(300); 154 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState()); 155 assertEquals(0, mCTUT.mForegroundCall.getConnections().size()); 156 assertEquals(PhoneConstants.State.IDLE, mCTUT.getState()); 157 } 158 159 @FlakyTest 160 @Ignore 161 @Test 162 @MediumTest 163 public void testMOCallDialPickUpHangup() { 164 testMOCallPickUp(); 165 assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState()); 166 assertEquals(PhoneConstants.State.OFFHOOK, mCTUT.getState()); 167 assertEquals(1, mCTUT.mForegroundCall.getConnections().size()); 168 /* get the reference of the connection before reject */ 169 Connection mConnection = mCTUT.mForegroundCall.getConnections().get(0); 170 assertEquals(DisconnectCause.NOT_DISCONNECTED, mConnection.getDisconnectCause()); 171 logd("hang up MO call after pickup"); 172 try { 173 mCTUT.hangup(mCTUT.mForegroundCall); 174 } catch(Exception ex) { 175 ex.printStackTrace(); 176 Assert.fail("unexpected exception thrown" + ex.getMessage()); 177 } 178 /* request send to RIL still in disconnecting state */ 179 waitForMs(300); 180 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState()); 181 assertEquals(0, mCTUT.mForegroundCall.getConnections().size()); 182 assertEquals(PhoneConstants.State.IDLE, mCTUT.getState()); 183 assertEquals(DisconnectCause.LOCAL, mConnection.getDisconnectCause()); 184 185 } 186 187 @FlakyTest 188 @Test 189 @MediumTest 190 public void testMOCallPendingHangUp() { 191 testMOCallDial(); 192 logd("MO call hangup before established[ getting result from RIL ]"); 193 /* poll call result from RIL, find that there is a pendingMO call, 194 * Didn't do anything for hangup, clear during handle poll result */ 195 try { 196 mCTUT.hangup(mCTUT.mForegroundCall); 197 } catch(Exception ex) { 198 ex.printStackTrace(); 199 Assert.fail("unexpected exception thrown" + ex.getMessage()); 200 } 201 waitForMs(300); 202 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState()); 203 assertEquals(0, mCTUT.mForegroundCall.getConnections().size()); 204 assertEquals(PhoneConstants.State.IDLE, mCTUT.getState()); 205 } 206 207 @Test 208 @MediumTest 209 public void testMOCallSwitch() { 210 testMOCallPickUp(); 211 logd("MO call picked up, initiating a new MO call"); 212 assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState()); 213 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState()); 214 assertEquals(1, mCTUT.mForegroundCall.getConnections().size()); 215 assertEquals(0, mCTUT.mBackgroundCall.getConnections().size()); 216 217 String mDialString = PhoneNumberUtils.stripSeparators("+17005554142"); 218 try { 219 mCTUT.dial(mDialString); 220 } catch(Exception ex) { 221 ex.printStackTrace(); 222 Assert.fail("unexpected exception thrown" + ex.getMessage()); 223 } 224 waitForMs(200); 225 assertEquals(GsmCdmaCall.State.DIALING, mCTUT.mForegroundCall.getState()); 226 assertEquals(GsmCdmaCall.State.HOLDING, mCTUT.mBackgroundCall.getState()); 227 assertEquals(1, mCTUT.mForegroundCall.getConnections().size()); 228 assertEquals(1, mCTUT.mBackgroundCall.getConnections().size()); 229 230 } 231 232 @Test 233 @SmallTest 234 @FlakyTest 235 @Ignore 236 public void testMTCallRinging() { 237 /* Mock there is a MT call mRinging call and try to accept this MT call */ 238 /* if we got a active state followed by another MT call-> move to background call */ 239 assertEquals(PhoneConstants.State.IDLE, mCTUT.getState()); 240 assertEquals(0, mCTUT.mRingingCall.getConnections().size()); 241 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState()); 242 String mDialString = PhoneNumberUtils.stripSeparators("+17005554141"); 243 logd("MT call Ringing"); 244 mSimulatedCommands.triggerRing(mDialString); 245 waitForMs(50); 246 assertEquals(PhoneConstants.State.RINGING, mCTUT.getState()); 247 assertEquals(1, mCTUT.mRingingCall.getConnections().size()); 248 } 249 250 @Test 251 @SmallTest 252 @FlakyTest 253 @Ignore 254 public void testMTCallAccept() { 255 testMTCallRinging(); 256 assertEquals(mCTUT.mForegroundCall.getConnections().size(),0); 257 logd("accept the MT call"); 258 try{ 259 mCTUT.acceptCall(); 260 } catch(Exception ex) { 261 ex.printStackTrace(); 262 Assert.fail("unexpected exception thrown" + ex.getMessage()); 263 } 264 verify(mSimulatedCommandsVerifier).acceptCall(isA(Message.class)); 265 /* send to the RIL */ 266 TelephonyTestUtils.waitForMs(50); 267 assertEquals(PhoneConstants.State.OFFHOOK, mCTUT.getState()); 268 assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState()); 269 assertEquals(1, mCTUT.mForegroundCall.getConnections().size()); 270 assertEquals(0, mCTUT.mRingingCall.getConnections().size()); 271 } 272 273 @Test 274 @SmallTest 275 public void testMTCallReject() { 276 testMTCallRinging(); 277 logd("MT call ringing and rejected "); 278 /* get the reference of the connection before reject */ 279 Connection mConnection = mCTUT.mRingingCall.getConnections().get(0); 280 assertNotNull(mConnection); 281 assertEquals(DisconnectCause.NOT_DISCONNECTED, mConnection.getDisconnectCause()); 282 try { 283 mCTUT.rejectCall(); 284 } catch(Exception ex) { 285 ex.printStackTrace(); 286 Assert.fail("unexpected exception thrown" + ex.getMessage()); 287 } 288 waitForMs(50); 289 assertEquals(PhoneConstants.State.IDLE, mCTUT.getState()); 290 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState()); 291 assertEquals(0, mCTUT.mForegroundCall.getConnections().size()); 292 /* ? why rejectCall didnt -> hang up locally to set the cause to LOCAL? */ 293 assertEquals(DisconnectCause.INCOMING_MISSED, mConnection.getDisconnectCause()); 294 295 } 296 297 @Test 298 @MediumTest 299 public void testMOCallSwitchHangupForeGround() { 300 testMOCallSwitch(); 301 logd("Hang up the foreground MO call while dialing "); 302 try { 303 mCTUT.hangup(mCTUT.mForegroundCall); 304 } catch(Exception ex) { 305 ex.printStackTrace(); 306 Assert.fail("unexpected exception thrown" + ex.getMessage()); 307 } 308 waitForMs(300); 309 logd(" Foreground Call is IDLE and BackGround Call is still HOLDING "); 310 /* if we want to hang up foreground call which is alerting state, hangup all */ 311 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState()); 312 assertEquals(GsmCdmaCall.State.HOLDING, mCTUT.mBackgroundCall.getState()); 313 } 314 315 @FlakyTest 316 @Ignore 317 @Test 318 @MediumTest 319 public void testMOCallPickUpHangUpResumeBackGround() { 320 testMOCallSwitch(); 321 logd("Pick up the new MO Call"); 322 try{ 323 mSimulatedCommands.progressConnectingToActive(); 324 } catch(Exception ex) { 325 ex.printStackTrace(); 326 Assert.fail("unexpected exception thrown" + ex.getMessage()); 327 } 328 329 waitForMs(200); 330 assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState()); 331 assertEquals(GsmCdmaCall.State.HOLDING, mCTUT.mBackgroundCall.getState()); 332 333 logd("Hang up the new MO Call"); 334 try { 335 mCTUT.hangup(mCTUT.mForegroundCall); 336 } catch(Exception ex) { 337 ex.printStackTrace(); 338 Assert.fail("unexpected exception thrown" + ex.getMessage()); 339 } 340 341 waitForMs(300); 342 logd(" BackGround Call switch to ForeGround Call "); 343 assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState()); 344 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState()); 345 } 346 347 @Test @SmallTest 348 public void testVoiceCallStartListener(){ 349 logd("register for voice call started event"); 350 mCTUT.registerForVoiceCallStarted(mHandler, VOICE_CALL_STARTED_EVENT, null); 351 logd("voice call started"); 352 testMOCallPickUp(); 353 ArgumentCaptor<Message> mCaptorMessage = ArgumentCaptor.forClass(Message.class); 354 ArgumentCaptor<Long> mCaptorLong = ArgumentCaptor.forClass(Long.class); 355 verify(mHandler,times(1)).sendMessageAtTime(mCaptorMessage.capture(), mCaptorLong.capture()); 356 assertEquals(VOICE_CALL_STARTED_EVENT, mCaptorMessage.getValue().what); 357 358 } 359 360 @FlakyTest 361 @Ignore 362 @Test @SmallTest 363 public void testVoiceCallEndedListener(){ 364 logd("register for voice call ended event"); 365 mCTUT.registerForVoiceCallEnded(mHandler, VOICE_CALL_ENDED_EVENT, null); 366 ArgumentCaptor<Message> mCaptorMessage = ArgumentCaptor.forClass(Message.class); 367 ArgumentCaptor<Long> mCaptorLong = ArgumentCaptor.forClass(Long.class); 368 testMOCallHangup(); 369 verify(mHandler,times(1)).sendMessageAtTime(mCaptorMessage.capture(), mCaptorLong.capture()); 370 assertEquals(VOICE_CALL_ENDED_EVENT, mCaptorMessage.getValue().what); 371 } 372 373 @Test @SmallTest 374 public void testUpdatePhoneType() { 375 // verify getCurrentCalls is called on init 376 verify(mSimulatedCommandsVerifier).getCurrentCalls(any(Message.class)); 377 378 // update phone type (call the function on same thread as the call tracker) 379 Handler updatePhoneTypeHandler = new Handler(mCTUT.getLooper()) { 380 @Override 381 public void handleMessage(Message msg) { 382 mCTUT.updatePhoneType(); 383 } 384 }; 385 updatePhoneTypeHandler.sendEmptyMessage(0); 386 waitForMs(100); 387 388 // verify getCurrentCalls is called on updating phone type 389 verify(mSimulatedCommandsVerifier, times(2)).getCurrentCalls(any(Message.class)); 390 391 // we'd like to verify that if phone type is updated, calls and callTracker go to idle. 392 // However, as soon as phone type is updated, call tracker queries for calls from RIL and 393 // will go back to OFFHOOK 394 395 // call tracker goes to OFFHOOK 396 testMOCallPickUp(); 397 398 // update phone type - call tracker goes to IDLE and then due to getCurrentCalls(), 399 // goes back to OFFHOOK 400 updatePhoneTypeHandler.sendEmptyMessage(0); 401 waitForMs(100); 402 403 // verify CT and calls go to idle 404 assertEquals(PhoneConstants.State.OFFHOOK, mCTUT.getState()); 405 assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState()); 406 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState()); 407 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mRingingCall.getState()); 408 } 409} 410 411