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 */ 16 package com.android.internal.telephony; 17 18 import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; 19 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertNotNull; 22 import static org.mockito.Mockito.any; 23 import static org.mockito.Mockito.anyInt; 24 import static org.mockito.Mockito.doReturn; 25 import static org.mockito.Mockito.eq; 26 import static org.mockito.Mockito.isA; 27 import static org.mockito.Mockito.times; 28 import static org.mockito.Mockito.verify; 29 30 import android.os.Handler; 31 import android.os.HandlerThread; 32 import android.os.Message; 33 import android.support.test.filters.FlakyTest; 34 import android.telephony.DisconnectCause; 35 import android.telephony.PhoneNumberUtils; 36 import android.telephony.ServiceState; 37 import android.test.suitebuilder.annotation.MediumTest; 38 import android.test.suitebuilder.annotation.SmallTest; 39 40 import org.junit.After; 41 import org.junit.Assert; 42 import org.junit.Before; 43 import org.junit.Ignore; 44 import org.junit.Test; 45 import org.mockito.ArgumentCaptor; 46 import org.mockito.Mock; 47 48 public 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 GsmCdmaConnection mConnection; 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 connection = mCTUT.mForegroundCall.getConnections().get(0); 170 assertEquals(DisconnectCause.NOT_DISCONNECTED, connection.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, connection.getDisconnectCause()); 184 185 } 186 187 @FlakyTest 188 @Ignore 189 @Test 190 @MediumTest 191 public void testMOCallPendingHangUp() { 192 testMOCallDial(); 193 logd("MO call hangup before established[ getting result from RIL ]"); 194 /* poll call result from RIL, find that there is a pendingMO call, 195 * Didn't do anything for hangup, clear during handle poll result */ 196 try { 197 mCTUT.hangup(mCTUT.mForegroundCall); 198 } catch(Exception ex) { 199 ex.printStackTrace(); 200 Assert.fail("unexpected exception thrown" + ex.getMessage()); 201 } 202 waitForMs(300); 203 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState()); 204 assertEquals(0, mCTUT.mForegroundCall.getConnections().size()); 205 assertEquals(PhoneConstants.State.IDLE, mCTUT.getState()); 206 } 207 208 @Test 209 @MediumTest 210 public void testMOCallSwitch() { 211 testMOCallPickUp(); 212 logd("MO call picked up, initiating a new MO call"); 213 assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState()); 214 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState()); 215 assertEquals(1, mCTUT.mForegroundCall.getConnections().size()); 216 assertEquals(0, mCTUT.mBackgroundCall.getConnections().size()); 217 218 String mDialString = PhoneNumberUtils.stripSeparators("+17005554142"); 219 try { 220 mCTUT.dial(mDialString); 221 } catch(Exception ex) { 222 ex.printStackTrace(); 223 Assert.fail("unexpected exception thrown" + ex.getMessage()); 224 } 225 waitForMs(200); 226 assertEquals(GsmCdmaCall.State.DIALING, mCTUT.mForegroundCall.getState()); 227 assertEquals(GsmCdmaCall.State.HOLDING, mCTUT.mBackgroundCall.getState()); 228 assertEquals(1, mCTUT.mForegroundCall.getConnections().size()); 229 assertEquals(1, mCTUT.mBackgroundCall.getConnections().size()); 230 231 } 232 233 @Test 234 @SmallTest 235 @FlakyTest 236 @Ignore 237 public void testMTCallRinging() { 238 /* Mock there is a MT call mRinging call and try to accept this MT call */ 239 /* if we got a active state followed by another MT call-> move to background call */ 240 assertEquals(PhoneConstants.State.IDLE, mCTUT.getState()); 241 assertEquals(0, mCTUT.mRingingCall.getConnections().size()); 242 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState()); 243 String mDialString = PhoneNumberUtils.stripSeparators("+17005554141"); 244 logd("MT call Ringing"); 245 mSimulatedCommands.triggerRing(mDialString); 246 waitForMs(50); 247 assertEquals(PhoneConstants.State.RINGING, mCTUT.getState()); 248 assertEquals(1, mCTUT.mRingingCall.getConnections().size()); 249 } 250 251 @Test 252 @SmallTest 253 @FlakyTest 254 @Ignore 255 public void testMTCallAccept() { 256 testMTCallRinging(); 257 assertEquals(mCTUT.mForegroundCall.getConnections().size(),0); 258 logd("accept the MT call"); 259 try{ 260 mCTUT.acceptCall(); 261 } catch(Exception ex) { 262 ex.printStackTrace(); 263 Assert.fail("unexpected exception thrown" + ex.getMessage()); 264 } 265 verify(mSimulatedCommandsVerifier).acceptCall(isA(Message.class)); 266 /* send to the RIL */ 267 TelephonyTestUtils.waitForMs(50); 268 assertEquals(PhoneConstants.State.OFFHOOK, mCTUT.getState()); 269 assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState()); 270 assertEquals(1, mCTUT.mForegroundCall.getConnections().size()); 271 assertEquals(0, mCTUT.mRingingCall.getConnections().size()); 272 } 273 274 @Test 275 @SmallTest 276 public void testMTCallReject() { 277 testMTCallRinging(); 278 logd("MT call ringing and rejected "); 279 /* get the reference of the connection before reject */ 280 Connection connection = mCTUT.mRingingCall.getConnections().get(0); 281 assertNotNull(connection); 282 assertEquals(DisconnectCause.NOT_DISCONNECTED, connection.getDisconnectCause()); 283 try { 284 mCTUT.rejectCall(); 285 } catch(Exception ex) { 286 ex.printStackTrace(); 287 Assert.fail("unexpected exception thrown" + ex.getMessage()); 288 } 289 waitForMs(50); 290 assertEquals(PhoneConstants.State.IDLE, mCTUT.getState()); 291 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState()); 292 assertEquals(0, mCTUT.mForegroundCall.getConnections().size()); 293 /* ? why rejectCall didnt -> hang up locally to set the cause to LOCAL? */ 294 assertEquals(DisconnectCause.INCOMING_MISSED, connection.getDisconnectCause()); 295 296 } 297 298 @FlakyTest 299 @Ignore 300 @Test 301 @MediumTest 302 public void testMOCallSwitchHangupForeGround() { 303 testMOCallSwitch(); 304 logd("Hang up the foreground MO call while dialing "); 305 try { 306 mCTUT.hangup(mCTUT.mForegroundCall); 307 } catch(Exception ex) { 308 ex.printStackTrace(); 309 Assert.fail("unexpected exception thrown" + ex.getMessage()); 310 } 311 waitForMs(300); 312 logd(" Foreground Call is IDLE and BackGround Call is still HOLDING "); 313 /* if we want to hang up foreground call which is alerting state, hangup all */ 314 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState()); 315 assertEquals(GsmCdmaCall.State.HOLDING, mCTUT.mBackgroundCall.getState()); 316 } 317 318 @FlakyTest 319 @Ignore 320 @Test 321 @MediumTest 322 public void testMOCallPickUpHangUpResumeBackGround() { 323 testMOCallSwitch(); 324 logd("Pick up the new MO Call"); 325 try{ 326 mSimulatedCommands.progressConnectingToActive(); 327 } catch(Exception ex) { 328 ex.printStackTrace(); 329 Assert.fail("unexpected exception thrown" + ex.getMessage()); 330 } 331 332 waitForMs(200); 333 assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState()); 334 assertEquals(GsmCdmaCall.State.HOLDING, mCTUT.mBackgroundCall.getState()); 335 336 logd("Hang up the new MO Call"); 337 try { 338 mCTUT.hangup(mCTUT.mForegroundCall); 339 } catch(Exception ex) { 340 ex.printStackTrace(); 341 Assert.fail("unexpected exception thrown" + ex.getMessage()); 342 } 343 344 waitForMs(300); 345 logd(" BackGround Call switch to ForeGround Call "); 346 assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState()); 347 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState()); 348 } 349 350 @Test @SmallTest 351 public void testVoiceCallStartListener(){ 352 logd("register for voice call started event"); 353 mCTUT.registerForVoiceCallStarted(mHandler, VOICE_CALL_STARTED_EVENT, null); 354 logd("voice call started"); 355 testMOCallPickUp(); 356 ArgumentCaptor<Message> mCaptorMessage = ArgumentCaptor.forClass(Message.class); 357 ArgumentCaptor<Long> mCaptorLong = ArgumentCaptor.forClass(Long.class); 358 verify(mHandler, times(1)) 359 .sendMessageAtTime(mCaptorMessage.capture(), mCaptorLong.capture()); 360 assertEquals(VOICE_CALL_STARTED_EVENT, mCaptorMessage.getValue().what); 361 362 } 363 364 @FlakyTest 365 @Ignore 366 @Test @SmallTest 367 public void testVoiceCallEndedListener(){ 368 logd("register for voice call ended event"); 369 mCTUT.registerForVoiceCallEnded(mHandler, VOICE_CALL_ENDED_EVENT, null); 370 ArgumentCaptor<Message> mCaptorMessage = ArgumentCaptor.forClass(Message.class); 371 ArgumentCaptor<Long> mCaptorLong = ArgumentCaptor.forClass(Long.class); 372 testMOCallHangup(); 373 verify(mHandler, times(1)) 374 .sendMessageAtTime(mCaptorMessage.capture(), mCaptorLong.capture()); 375 assertEquals(VOICE_CALL_ENDED_EVENT, mCaptorMessage.getValue().what); 376 } 377 378 @Test @SmallTest 379 public void testUpdatePhoneType() { 380 // verify getCurrentCalls is called on init 381 verify(mSimulatedCommandsVerifier).getCurrentCalls(any(Message.class)); 382 383 // update phone type (call the function on same thread as the call tracker) 384 Handler updatePhoneTypeHandler = new Handler(mCTUT.getLooper()) { 385 @Override 386 public void handleMessage(Message msg) { 387 mCTUT.updatePhoneType(); 388 } 389 }; 390 updatePhoneTypeHandler.sendEmptyMessage(0); 391 waitForMs(100); 392 393 // verify getCurrentCalls is called on updating phone type 394 verify(mSimulatedCommandsVerifier, times(2)).getCurrentCalls(any(Message.class)); 395 396 // we'd like to verify that if phone type is updated, calls and callTracker go to idle. 397 // However, as soon as phone type is updated, call tracker queries for calls from RIL and 398 // will go back to OFFHOOK 399 400 // call tracker goes to OFFHOOK 401 testMOCallPickUp(); 402 403 // update phone type - call tracker goes to IDLE and then due to getCurrentCalls(), 404 // goes back to OFFHOOK 405 updatePhoneTypeHandler.sendEmptyMessage(0); 406 waitForMs(100); 407 408 // verify CT and calls go to idle 409 assertEquals(PhoneConstants.State.OFFHOOK, mCTUT.getState()); 410 assertEquals(GsmCdmaCall.State.ACTIVE, mCTUT.mForegroundCall.getState()); 411 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState()); 412 assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mRingingCall.getState()); 413 } 414 415 @Test 416 @SmallTest 417 public void testUpdatePhoneTypeWithActiveCall() { 418 // verify getCurrentCalls is called on init 419 verify(mSimulatedCommandsVerifier).getCurrentCalls(any(Message.class)); 420 421 // fake connection 422 mCTUT.mConnections[0] = mConnection; 423 424 // update phone type (call the function on same thread as the call tracker) 425 Handler updatePhoneTypeHandler = new Handler(mCTUT.getLooper()) { 426 @Override 427 public void handleMessage(Message msg) { 428 mCTUT.updatePhoneType(); 429 } 430 }; 431 updatePhoneTypeHandler.sendEmptyMessage(0); 432 waitForMs(100); 433 434 // verify that the active call is disconnected 435 verify(mConnection).onDisconnect(DisconnectCause.ERROR_UNSPECIFIED); 436 } 437 } 438 439