1 /* 2 * Copyright (C) 2015 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 android.telecom.cts; 18 19 import static android.telecom.cts.TestUtils.PACKAGE; 20 import static android.telecom.cts.TestUtils.TAG; 21 import static android.telecom.cts.TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS; 22 23 import static org.hamcrest.CoreMatchers.equalTo; 24 import static org.hamcrest.CoreMatchers.not; 25 import static org.junit.Assert.assertNotEquals; 26 import static org.junit.Assert.assertThat; 27 28 import android.app.AppOpsManager; 29 import android.app.UiAutomation; 30 import android.app.UiModeManager; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.res.Configuration; 34 import android.content.pm.PackageManager; 35 import android.database.ContentObserver; 36 import android.database.Cursor; 37 import android.media.AudioManager; 38 import android.net.Uri; 39 import android.os.Bundle; 40 import android.os.Handler; 41 import android.os.HandlerThread; 42 import android.os.Looper; 43 import android.os.RemoteException; 44 import android.os.Process; 45 import android.os.UserHandle; 46 import android.provider.CallLog; 47 import android.telecom.Call; 48 import android.telecom.CallAudioState; 49 import android.telecom.Conference; 50 import android.telecom.Connection; 51 import android.telecom.ConnectionRequest; 52 import android.telecom.InCallService; 53 import android.telecom.PhoneAccount; 54 import android.telecom.PhoneAccountHandle; 55 import android.telecom.TelecomManager; 56 import android.telecom.VideoProfile; 57 import android.telecom.cts.MockInCallService.InCallServiceCallbacks; 58 import android.telecom.cts.carmodetestapp.ICtsCarModeInCallServiceControl; 59 import android.telephony.PhoneStateListener; 60 import android.telephony.TelephonyCallback; 61 import android.telephony.TelephonyManager; 62 import android.telephony.emergency.EmergencyNumber; 63 import android.test.InstrumentationTestCase; 64 import android.text.TextUtils; 65 import android.util.Log; 66 import android.util.Pair; 67 68 import androidx.test.InstrumentationRegistry; 69 70 import com.android.compatibility.common.util.ShellIdentityUtils; 71 72 import java.util.ArrayList; 73 import java.util.List; 74 import java.util.Map; 75 import java.util.Objects; 76 import java.util.Random; 77 import java.util.concurrent.CountDownLatch; 78 import java.util.concurrent.LinkedBlockingQueue; 79 import java.util.concurrent.Semaphore; 80 import java.util.concurrent.TimeUnit; 81 import java.util.stream.Collectors; 82 83 /** 84 * Base class for Telecom CTS tests that require a {@link CtsConnectionService} and 85 * {@link MockInCallService} to verify Telecom functionality. 86 */ 87 public class BaseTelecomTestWithMockServices extends InstrumentationTestCase { 88 89 public static final int FLAG_REGISTER = 0x1; 90 public static final int FLAG_ENABLE = 0x2; 91 public static final int FLAG_SET_DEFAULT = 0x4; 92 93 // Don't accidently use emergency number. 94 private static int sCounter = 5553638; 95 96 public static final String TEST_EMERGENCY_NUMBER = "5553637"; 97 public static final Uri TEST_EMERGENCY_URI = Uri.fromParts("tel", TEST_EMERGENCY_NUMBER, null); 98 public static final String PKG_NAME = "android.telecom.cts"; 99 public static final String PERMISSION_PROCESS_OUTGOING_CALLS = 100 "android.permission.PROCESS_OUTGOING_CALLS"; 101 102 Context mContext; 103 TelecomManager mTelecomManager; 104 TelephonyManager mTelephonyManager; 105 UiModeManager mUiModeManager; 106 107 TestUtils.InvokeCounter mOnBringToForegroundCounter; 108 TestUtils.InvokeCounter mOnCallAudioStateChangedCounter; 109 TestUtils.InvokeCounter mOnPostDialWaitCounter; 110 TestUtils.InvokeCounter mOnCannedTextResponsesLoadedCounter; 111 TestUtils.InvokeCounter mOnSilenceRingerCounter; 112 TestUtils.InvokeCounter mOnConnectionEventCounter; 113 TestUtils.InvokeCounter mOnExtrasChangedCounter; 114 TestUtils.InvokeCounter mOnPropertiesChangedCounter; 115 TestUtils.InvokeCounter mOnRttModeChangedCounter; 116 TestUtils.InvokeCounter mOnRttStatusChangedCounter; 117 TestUtils.InvokeCounter mOnRttInitiationFailedCounter; 118 TestUtils.InvokeCounter mOnRttRequestCounter; 119 TestUtils.InvokeCounter mOnHandoverCompleteCounter; 120 TestUtils.InvokeCounter mOnHandoverFailedCounter; 121 TestUtils.InvokeCounter mOnPhoneAccountChangedCounter; 122 Bundle mPreviousExtras; 123 int mPreviousProperties = -1; 124 PhoneAccountHandle mPreviousPhoneAccountHandle = null; 125 126 InCallServiceCallbacks mInCallCallbacks; 127 String mPreviousDefaultDialer = null; 128 PhoneAccountHandle mPreviousDefaultOutgoingAccount = null; 129 boolean mShouldRestoreDefaultOutgoingAccount = false; 130 MockConnectionService connectionService = null; 131 boolean mIsEmergencyCallingSetup = false; 132 133 HandlerThread mTelephonyCallbackThread; 134 Handler mTelephonyCallbackHandler; 135 TestTelephonyCallback mTelephonyCallback; 136 TestCallStateListener mTestCallStateListener; 137 Handler mHandler; 138 139 /** 140 * Uses the control interface to disable car mode. 141 * @param expectedUiMode 142 */ disableAndVerifyCarMode(ICtsCarModeInCallServiceControl control, int expectedUiMode)143 protected void disableAndVerifyCarMode(ICtsCarModeInCallServiceControl control, 144 int expectedUiMode) { 145 if (control == null) { 146 return; 147 } 148 try { 149 control.disableCarMode(); 150 } catch (RemoteException re) { 151 fail("Bee-boop; can't control the incall service"); 152 } 153 assertUiMode(expectedUiMode); 154 } 155 disconnectAllCallsAndVerify(ICtsCarModeInCallServiceControl controlBinder)156 protected void disconnectAllCallsAndVerify(ICtsCarModeInCallServiceControl controlBinder) { 157 if (controlBinder == null) { 158 return; 159 } 160 try { 161 controlBinder.disconnectCalls(); 162 } catch (RemoteException re) { 163 fail("Bee-boop; can't control the incall service"); 164 } 165 assertCarModeCallCount(controlBinder, 0); 166 } 167 168 /** 169 * Verify the car mode ICS has an expected call count. 170 * @param expected 171 */ assertCarModeCallCount(ICtsCarModeInCallServiceControl control, int expected)172 protected void assertCarModeCallCount(ICtsCarModeInCallServiceControl control, int expected) { 173 waitUntilConditionIsTrueOrTimeout( 174 new Condition() { 175 @Override 176 public Object expected() { 177 return expected; 178 } 179 180 @Override 181 public Object actual() { 182 int callCount = 0; 183 try { 184 callCount = control.getCallCount(); 185 } catch (RemoteException re) { 186 fail("Bee-boop; can't control the incall service"); 187 } 188 return callCount; 189 } 190 }, 191 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 192 "Expected " + expected + " calls." 193 ); 194 } 195 196 static class TestCallStateListener extends TelephonyCallback 197 implements TelephonyCallback.CallStateListener { 198 199 private CountDownLatch mCountDownLatch = new CountDownLatch(1); 200 private int mLastState = -1; 201 202 @Override onCallStateChanged(int state)203 public void onCallStateChanged(int state) { 204 Log.i(TAG, "onCallStateChanged: state=" + state); 205 mLastState = state; 206 mCountDownLatch.countDown(); 207 mCountDownLatch = new CountDownLatch(1); 208 } 209 getCountDownLatch()210 public CountDownLatch getCountDownLatch() { 211 return mCountDownLatch; 212 } 213 getLastState()214 public int getLastState() { 215 return mLastState; 216 } 217 } 218 219 static class TestTelephonyCallback extends TelephonyCallback implements 220 TelephonyCallback.CallStateListener, 221 TelephonyCallback.OutgoingEmergencyCallListener, 222 TelephonyCallback.EmergencyNumberListListener { 223 /** Semaphore released for every callback invocation. */ 224 public Semaphore mCallbackSemaphore = new Semaphore(0); 225 226 List<Integer> mCallStates = new ArrayList<>(); 227 EmergencyNumber mLastOutgoingEmergencyNumber; 228 229 LinkedBlockingQueue<Map<Integer, List<EmergencyNumber>>> mEmergencyNumberListQueue = 230 new LinkedBlockingQueue<>(2); 231 232 @Override onCallStateChanged(int state)233 public void onCallStateChanged(int state) { 234 Log.i(TAG, "onCallStateChanged: state=" + state); 235 mCallStates.add(state); 236 mCallbackSemaphore.release(); 237 } 238 239 @Override onOutgoingEmergencyCall(EmergencyNumber emergencyNumber, int subscriptionId)240 public void onOutgoingEmergencyCall(EmergencyNumber emergencyNumber, int subscriptionId) { 241 Log.i(TAG, "onOutgoingEmergencyCall: emergencyNumber=" + emergencyNumber); 242 mLastOutgoingEmergencyNumber = emergencyNumber; 243 mCallbackSemaphore.release(); 244 } 245 246 @Override onEmergencyNumberListChanged( Map<Integer, List<EmergencyNumber>> emergencyNumberList)247 public void onEmergencyNumberListChanged( 248 Map<Integer, List<EmergencyNumber>> emergencyNumberList) { 249 Log.i(TAG, "onEmergencyNumberChanged, total size=" + emergencyNumberList.values() 250 .stream().mapToInt(List::size).sum()); 251 mEmergencyNumberListQueue.offer(emergencyNumberList); 252 } 253 waitForEmergencyNumberListUpdate( long timeoutMillis)254 public Map<Integer, List<EmergencyNumber>> waitForEmergencyNumberListUpdate( 255 long timeoutMillis) throws Throwable { 256 return mEmergencyNumberListQueue.poll(timeoutMillis, TimeUnit.MILLISECONDS); 257 } 258 } 259 260 boolean mShouldTestTelecom = true; 261 262 @Override setUp()263 protected void setUp() throws Exception { 264 super.setUp(); 265 mContext = getInstrumentation().getContext(); 266 mHandler = new Handler(Looper.getMainLooper()); 267 mShouldTestTelecom = TestUtils.shouldTestTelecom(mContext); 268 if (!mShouldTestTelecom) { 269 return; 270 } 271 272 // Assume we start in normal mode at the start of all Telecom tests; a failure to leave car 273 // mode in any of the tests would cause subsequent test failures. 274 // For Watch, UI_MODE shouldn't be normal mode. 275 mUiModeManager = mContext.getSystemService(UiModeManager.class); 276 TestUtils.executeShellCommand(getInstrumentation(), "telecom reset-car-mode"); 277 278 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) { 279 assertUiMode(Configuration.UI_MODE_TYPE_WATCH); 280 } else { 281 assertUiMode(Configuration.UI_MODE_TYPE_NORMAL); 282 } 283 284 AppOpsManager aom = mContext.getSystemService(AppOpsManager.class); 285 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(aom, 286 (appOpsMan) -> appOpsMan.setUidMode(AppOpsManager.OPSTR_PROCESS_OUTGOING_CALLS, 287 Process.myUid(), AppOpsManager.MODE_ALLOWED)); 288 289 mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); 290 mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); 291 292 mPreviousDefaultDialer = TestUtils.getDefaultDialer(getInstrumentation()); 293 TestUtils.setDefaultDialer(getInstrumentation(), PACKAGE); 294 setupCallbacks(); 295 296 // Register a call state listener. 297 mTestCallStateListener = new TestCallStateListener(); 298 CountDownLatch latch = mTestCallStateListener.getCountDownLatch(); 299 mTelephonyManager.registerTelephonyCallback(r -> r.run(), mTestCallStateListener); 300 latch.await( 301 TestUtils.WAIT_FOR_PHONE_STATE_LISTENER_REGISTERED_TIMEOUT_S, TimeUnit.SECONDS); 302 // Create a new thread for the telephony callback. 303 mTelephonyCallbackThread = new HandlerThread("PhoneStateListenerThread"); 304 mTelephonyCallbackThread.start(); 305 mTelephonyCallbackHandler = new Handler(mTelephonyCallbackThread.getLooper()); 306 307 mTelephonyCallback = new TestTelephonyCallback(); 308 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager, 309 (tm) -> tm.registerTelephonyCallback( 310 mTelephonyCallbackHandler::post, 311 mTelephonyCallback)); 312 UiAutomation uiAutomation = 313 InstrumentationRegistry.getInstrumentation().getUiAutomation(); 314 uiAutomation.grantRuntimePermissionAsUser(PKG_NAME, PERMISSION_PROCESS_OUTGOING_CALLS, 315 UserHandle.CURRENT); 316 } 317 318 @Override tearDown()319 protected void tearDown() throws Exception { 320 super.tearDown(); 321 if (!mShouldTestTelecom) { 322 return; 323 } 324 325 mTelephonyManager.unregisterTelephonyCallback(mTestCallStateListener); 326 327 mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback); 328 mTelephonyCallbackThread.quit(); 329 330 cleanupCalls(); 331 if (!TextUtils.isEmpty(mPreviousDefaultDialer)) { 332 TestUtils.setDefaultDialer(getInstrumentation(), mPreviousDefaultDialer); 333 } 334 tearDownConnectionService(TestUtils.TEST_PHONE_ACCOUNT_HANDLE); 335 tearDownEmergencyCalling(); 336 try { 337 assertMockInCallServiceUnbound(); 338 } catch (Throwable t) { 339 // If we haven't unbound, that means there's some dirty state in Telecom that needs 340 // cleaning up. Forcibly unbind and clean up Telecom state so that we don't have a 341 // cascading failure of tests. 342 TestUtils.executeShellCommand(getInstrumentation(), "telecom cleanup-stuck-calls"); 343 throw t; 344 } 345 UiAutomation uiAutomation = 346 InstrumentationRegistry.getInstrumentation().getUiAutomation(); 347 uiAutomation.revokeRuntimePermissionAsUser(PKG_NAME, PERMISSION_PROCESS_OUTGOING_CALLS, 348 UserHandle.CURRENT); 349 } 350 setupConnectionService(MockConnectionService connectionService, int flags)351 protected PhoneAccount setupConnectionService(MockConnectionService connectionService, 352 int flags) throws Exception { 353 Log.i(TAG, "Setting up mock connection service"); 354 if (connectionService != null) { 355 this.connectionService = connectionService; 356 } else { 357 // Generate a vanilla mock connection service, if not provided. 358 this.connectionService = new MockConnectionService(); 359 } 360 CtsConnectionService.setUp(this.connectionService); 361 362 if ((flags & FLAG_REGISTER) != 0) { 363 mTelecomManager.registerPhoneAccount(TestUtils.TEST_PHONE_ACCOUNT); 364 } 365 if ((flags & FLAG_ENABLE) != 0) { 366 TestUtils.enablePhoneAccount(getInstrumentation(), TestUtils.TEST_PHONE_ACCOUNT_HANDLE); 367 // Wait till the adb commands have executed and account is enabled in Telecom database. 368 assertPhoneAccountEnabled(TestUtils.TEST_PHONE_ACCOUNT_HANDLE); 369 } 370 371 if ((flags & FLAG_SET_DEFAULT) != 0) { 372 mPreviousDefaultOutgoingAccount = mTelecomManager.getUserSelectedOutgoingPhoneAccount(); 373 mShouldRestoreDefaultOutgoingAccount = true; 374 TestUtils.setDefaultOutgoingPhoneAccount(getInstrumentation(), 375 TestUtils.TEST_PHONE_ACCOUNT_HANDLE); 376 // Wait till the adb commands have executed and the default has changed. 377 assertPhoneAccountIsDefault(TestUtils.TEST_PHONE_ACCOUNT_HANDLE); 378 } 379 380 return TestUtils.TEST_PHONE_ACCOUNT; 381 } 382 tearDownConnectionService(PhoneAccountHandle accountHandle)383 protected void tearDownConnectionService(PhoneAccountHandle accountHandle) throws Exception { 384 Log.i(TAG, "Tearing down mock connection service"); 385 if (this.connectionService != null) { 386 assertNumConnections(this.connectionService, 0); 387 } 388 mTelecomManager.unregisterPhoneAccount(accountHandle); 389 CtsConnectionService.tearDown(); 390 assertCtsConnectionServiceUnbound(); 391 if (mShouldRestoreDefaultOutgoingAccount) { 392 TestUtils.setDefaultOutgoingPhoneAccount(getInstrumentation(), 393 mPreviousDefaultOutgoingAccount); 394 } 395 this.connectionService = null; 396 mPreviousDefaultOutgoingAccount = null; 397 mShouldRestoreDefaultOutgoingAccount = false; 398 } 399 setupForEmergencyCalling(String testNumber)400 protected void setupForEmergencyCalling(String testNumber) throws Exception { 401 TestUtils.setSystemDialerOverride(getInstrumentation()); 402 TestUtils.addTestEmergencyNumber(getInstrumentation(), testNumber); 403 TestUtils.setTestEmergencyPhoneAccountPackageFilter(getInstrumentation(), mContext); 404 // Emergency calls require special capabilities. 405 TestUtils.registerEmergencyPhoneAccount(getInstrumentation(), 406 TestUtils.TEST_EMERGENCY_PHONE_ACCOUNT_HANDLE, 407 TestUtils.ACCOUNT_LABEL + "E", "tel:555-EMER"); 408 mIsEmergencyCallingSetup = true; 409 } 410 tearDownEmergencyCalling()411 protected void tearDownEmergencyCalling() throws Exception { 412 if (!mIsEmergencyCallingSetup) return; 413 414 TestUtils.clearSystemDialerOverride(getInstrumentation()); 415 TestUtils.clearTestEmergencyNumbers(getInstrumentation()); 416 TestUtils.clearTestEmergencyPhoneAccountPackageFilter(getInstrumentation()); 417 mTelecomManager.unregisterPhoneAccount(TestUtils.TEST_EMERGENCY_PHONE_ACCOUNT_HANDLE); 418 } 419 startCallTo(Uri address, PhoneAccountHandle accountHandle)420 protected void startCallTo(Uri address, PhoneAccountHandle accountHandle) { 421 final Intent intent = new Intent(Intent.ACTION_CALL, address); 422 if (accountHandle != null) { 423 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 424 } 425 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 426 mContext.startActivity(intent); 427 } 428 sleep(long ms)429 void sleep(long ms) { 430 try { 431 Thread.sleep(ms); 432 } catch (InterruptedException e) { 433 } 434 } 435 setupCallbacks()436 private void setupCallbacks() { 437 mInCallCallbacks = new InCallServiceCallbacks() { 438 @Override 439 public void onCallAdded(Call call, int numCalls) { 440 Log.i(TAG, "onCallAdded, Call: " + call + ", Num Calls: " + numCalls); 441 this.lock.release(); 442 mPreviousPhoneAccountHandle = call.getDetails().getAccountHandle(); 443 } 444 @Override 445 public void onCallRemoved(Call call, int numCalls) { 446 Log.i(TAG, "onCallRemoved, Call: " + call + ", Num Calls: " + numCalls); 447 } 448 @Override 449 public void onParentChanged(Call call, Call parent) { 450 Log.i(TAG, "onParentChanged, Call: " + call + ", Parent: " + parent); 451 this.lock.release(); 452 } 453 @Override 454 public void onChildrenChanged(Call call, List<Call> children) { 455 Log.i(TAG, "onChildrenChanged, Call: " + call + "Children: " + children); 456 this.lock.release(); 457 } 458 @Override 459 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) { 460 Log.i(TAG, "onConferenceableCallsChanged, Call: " + call + ", Conferenceables: " + 461 conferenceableCalls); 462 } 463 @Override 464 public void onDetailsChanged(Call call, Call.Details details) { 465 Log.i(TAG, "onDetailsChanged, Call: " + call + ", Details: " + details); 466 if (!areBundlesEqual(mPreviousExtras, details.getExtras())) { 467 mOnExtrasChangedCounter.invoke(call, details); 468 } 469 mPreviousExtras = details.getExtras(); 470 471 if (mPreviousProperties != details.getCallProperties()) { 472 mOnPropertiesChangedCounter.invoke(call, details); 473 Log.i(TAG, "onDetailsChanged; properties changed from " + Call.Details.propertiesToString(mPreviousProperties) + 474 " to " + Call.Details.propertiesToString(details.getCallProperties())); 475 } 476 mPreviousProperties = details.getCallProperties(); 477 478 if (details.getAccountHandle() != null && 479 !details.getAccountHandle().equals(mPreviousPhoneAccountHandle)) { 480 mOnPhoneAccountChangedCounter.invoke(call, details.getAccountHandle()); 481 } 482 mPreviousPhoneAccountHandle = details.getAccountHandle(); 483 } 484 @Override 485 public void onCallDestroyed(Call call) { 486 Log.i(TAG, "onCallDestroyed, Call: " + call); 487 } 488 @Override 489 public void onCallStateChanged(Call call, int newState) { 490 Log.i(TAG, "onCallStateChanged, Call: " + call + ", New State: " + newState); 491 } 492 @Override 493 public void onBringToForeground(boolean showDialpad) { 494 mOnBringToForegroundCounter.invoke(showDialpad); 495 } 496 @Override 497 public void onCallAudioStateChanged(CallAudioState audioState) { 498 Log.i(TAG, "onCallAudioStateChanged, audioState: " + audioState); 499 mOnCallAudioStateChangedCounter.invoke(audioState); 500 } 501 @Override 502 public void onPostDialWait(Call call, String remainingPostDialSequence) { 503 mOnPostDialWaitCounter.invoke(call, remainingPostDialSequence); 504 } 505 @Override 506 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) { 507 mOnCannedTextResponsesLoadedCounter.invoke(call, cannedTextResponses); 508 } 509 @Override 510 public void onConnectionEvent(Call call, String event, Bundle extras) { 511 mOnConnectionEventCounter.invoke(call, event, extras); 512 } 513 514 @Override 515 public void onSilenceRinger() { 516 Log.i(TAG, "onSilenceRinger"); 517 mOnSilenceRingerCounter.invoke(); 518 } 519 520 @Override 521 public void onRttModeChanged(Call call, int mode) { 522 mOnRttModeChangedCounter.invoke(call, mode); 523 } 524 525 @Override 526 public void onRttStatusChanged(Call call, boolean enabled, Call.RttCall rttCall) { 527 mOnRttStatusChangedCounter.invoke(call, enabled, rttCall); 528 } 529 530 @Override 531 public void onRttRequest(Call call, int id) { 532 mOnRttRequestCounter.invoke(call, id); 533 } 534 535 @Override 536 public void onRttInitiationFailure(Call call, int reason) { 537 mOnRttInitiationFailedCounter.invoke(call, reason); 538 } 539 540 @Override 541 public void onHandoverComplete(Call call) { 542 mOnHandoverCompleteCounter.invoke(call); 543 } 544 545 @Override 546 public void onHandoverFailed(Call call, int reason) { 547 mOnHandoverFailedCounter.invoke(call, reason); 548 } 549 }; 550 551 MockInCallService.setCallbacks(mInCallCallbacks); 552 553 // TODO: If more InvokeCounters are added in the future, consider consolidating them into a 554 // single Collection. 555 mOnBringToForegroundCounter = new TestUtils.InvokeCounter("OnBringToForeground"); 556 mOnCallAudioStateChangedCounter = new TestUtils.InvokeCounter("OnCallAudioStateChanged"); 557 mOnPostDialWaitCounter = new TestUtils.InvokeCounter("OnPostDialWait"); 558 mOnCannedTextResponsesLoadedCounter = new TestUtils.InvokeCounter("OnCannedTextResponsesLoaded"); 559 mOnSilenceRingerCounter = new TestUtils.InvokeCounter("OnSilenceRinger"); 560 mOnConnectionEventCounter = new TestUtils.InvokeCounter("OnConnectionEvent"); 561 mOnExtrasChangedCounter = new TestUtils.InvokeCounter("OnDetailsChangedCounter"); 562 mOnPropertiesChangedCounter = new TestUtils.InvokeCounter("OnPropertiesChangedCounter"); 563 mOnRttModeChangedCounter = new TestUtils.InvokeCounter("mOnRttModeChangedCounter"); 564 mOnRttStatusChangedCounter = new TestUtils.InvokeCounter("mOnRttStatusChangedCounter"); 565 mOnRttInitiationFailedCounter = 566 new TestUtils.InvokeCounter("mOnRttInitiationFailedCounter"); 567 mOnRttRequestCounter = new TestUtils.InvokeCounter("mOnRttRequestCounter"); 568 mOnHandoverCompleteCounter = new TestUtils.InvokeCounter("mOnHandoverCompleteCounter"); 569 mOnHandoverFailedCounter = new TestUtils.InvokeCounter("mOnHandoverFailedCounter"); 570 mOnPhoneAccountChangedCounter = new TestUtils.InvokeCounter( 571 "mOnPhoneAccountChangedCounter"); 572 } 573 addAndVerifyNewFailedIncomingCall(Uri incomingHandle, Bundle extras)574 void addAndVerifyNewFailedIncomingCall(Uri incomingHandle, Bundle extras) { 575 assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); 576 int currentCallCount = 0; 577 if (mInCallCallbacks.getService() != null) { 578 currentCallCount = mInCallCallbacks.getService().getCallCount(); 579 } 580 581 if (extras == null) { 582 extras = new Bundle(); 583 } 584 extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, incomingHandle); 585 mTelecomManager.addNewIncomingCall(TestUtils.TEST_PHONE_ACCOUNT_HANDLE, extras); 586 587 if (!connectionService.waitForEvent( 588 MockConnectionService.EVENT_CONNECTION_SERVICE_CREATE_CONNECTION_FAILED)) { 589 fail("Incoming Connection failure indication did not get called."); 590 } 591 592 assertEquals("ConnectionService did not receive failed connection", 593 1, connectionService.failedConnections.size()); 594 595 assertEquals("Address is not correct for failed connection", 596 connectionService.failedConnections.get(0).getAddress(), incomingHandle); 597 598 assertEquals("InCallService should contain the same number of calls.", 599 currentCallCount, 600 mInCallCallbacks.getService().getCallCount()); 601 } 602 603 /** 604 * Puts Telecom in a state where there is an incoming call provided by the 605 * {@link CtsConnectionService} which can be tested. 606 */ addAndVerifyNewIncomingCall(Uri incomingHandle, Bundle extras)607 void addAndVerifyNewIncomingCall(Uri incomingHandle, Bundle extras) { 608 int currentCallCount = addNewIncomingCall(incomingHandle, extras); 609 verifyNewIncomingCall(currentCallCount); 610 } 611 addNewIncomingCall(Uri incomingHandle, Bundle extras)612 int addNewIncomingCall(Uri incomingHandle, Bundle extras) { 613 assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); 614 int currentCallCount = 0; 615 if (mInCallCallbacks.getService() != null) { 616 currentCallCount = mInCallCallbacks.getService().getCallCount(); 617 } 618 619 if (extras == null) { 620 extras = new Bundle(); 621 } 622 extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, incomingHandle); 623 mTelecomManager.addNewIncomingCall(TestUtils.TEST_PHONE_ACCOUNT_HANDLE, extras); 624 625 return currentCallCount; 626 } 627 verifyNewIncomingCall(int currentCallCount)628 void verifyNewIncomingCall(int currentCallCount) { 629 try { 630 if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S, 631 TimeUnit.SECONDS)) { 632 fail("No call added to InCallService."); 633 } 634 } catch (InterruptedException e) { 635 Log.i(TAG, "Test interrupted!"); 636 } 637 638 assertEquals("InCallService should contain 1 more call after adding a call.", 639 currentCallCount + 1, 640 mInCallCallbacks.getService().getCallCount()); 641 } 642 643 /** 644 * Puts Telecom in a state where there is an active call provided by the 645 * {@link CtsConnectionService} which can be tested. 646 */ placeAndVerifyCall()647 void placeAndVerifyCall() { 648 placeAndVerifyCall(null); 649 } 650 placeAndVerifyCallByRedirection(boolean wasCancelled)651 void placeAndVerifyCallByRedirection(boolean wasCancelled) { 652 placeAndVerifyCallByRedirection(null, wasCancelled); 653 } 654 655 /** 656 * Puts Telecom in a state where there is an active call provided by the 657 * {@link CtsConnectionService} which can be tested. 658 */ placeAndVerifyCallByRedirection(Bundle extras, boolean wasCancelled)659 void placeAndVerifyCallByRedirection(Bundle extras, boolean wasCancelled) { 660 int currentCallCount = (getInCallService() == null) ? 0 : getInCallService().getCallCount(); 661 int currentConnections = getNumberOfConnections(); 662 // We expect a new connection if it wasn't cancelled. 663 if (!wasCancelled) { 664 currentConnections++; 665 currentCallCount++; 666 } 667 placeAndVerifyCall(extras, VideoProfile.STATE_AUDIO_ONLY, currentCallCount); 668 // The connectionService.lock is released in 669 // MockConnectionService#onCreateOutgoingConnection, however the connection will not 670 // actually be added to the list of connections in the ConnectionService until shortly 671 // afterwards. So there is still a potential for the lock to be released before it would 672 // be seen by calls to ConnectionService#getAllConnections(). 673 // We will wait here until the list of connections includes one more connection to ensure 674 // that placing the call has fully completed. 675 assertCSConnections(currentConnections); 676 677 // Ensure the new outgoing call broadcast fired for the outgoing call. 678 assertOutgoingCallBroadcastReceived(true); 679 680 // CTS test does not have read call log permission so should not get the phone number. 681 assertNull(NewOutgoingCallBroadcastReceiver.getReceivedNumber()); 682 } 683 684 /** 685 * Puts Telecom in a state where there is an active call provided by the 686 * {@link CtsConnectionService} which can be tested. 687 * 688 * @param videoState the video state of the call. 689 */ placeAndVerifyCall(int videoState)690 void placeAndVerifyCall(int videoState) { 691 placeAndVerifyCall(null, videoState); 692 } 693 694 /** 695 * Puts Telecom in a state where there is an active call provided by the 696 * {@link CtsConnectionService} which can be tested. 697 */ placeAndVerifyCall(Bundle extras)698 void placeAndVerifyCall(Bundle extras) { 699 placeAndVerifyCall(extras, VideoProfile.STATE_AUDIO_ONLY); 700 } 701 702 /** 703 * Puts Telecom in a state where there is an active call provided by the 704 * {@link CtsConnectionService} which can be tested. 705 */ placeAndVerifyCall(Bundle extras, int videoState)706 void placeAndVerifyCall(Bundle extras, int videoState) { 707 int currentCallCount = (getInCallService() == null) ? 0 : getInCallService().getCallCount(); 708 // We expect placing the call adds a new call/connection. 709 int expectedConnections = getNumberOfConnections() + 1; 710 placeAndVerifyCall(extras, videoState, currentCallCount + 1); 711 // The connectionService.lock is released in 712 // MockConnectionService#onCreateOutgoingConnection, however the connection will not 713 // actually be added to the list of connections in the ConnectionService until shortly 714 // afterwards. So there is still a potential for the lock to be released before it would 715 // be seen by calls to ConnectionService#getAllConnections(). 716 // We will wait here until the list of connections includes one more connection to ensure 717 // that placing the call has fully completed. 718 assertCSConnections(expectedConnections); 719 assertOutgoingCallBroadcastReceived(true); 720 721 // CTS test does not have read call log permission so should not get the phone number. 722 assertNull(NewOutgoingCallBroadcastReceiver.getReceivedNumber()); 723 } 724 725 /** 726 * Puts Telecom in a state where there is an active call provided by the 727 * {@link CtsConnectionService} which can be tested. 728 */ placeAndVerifyCall(Bundle extras, int videoState, int expectedCallCount)729 void placeAndVerifyCall(Bundle extras, int videoState, int expectedCallCount) { 730 assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); 731 placeNewCallWithPhoneAccount(extras, videoState); 732 733 try { 734 if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S, 735 TimeUnit.SECONDS)) { 736 fail("No call added to InCallService."); 737 } 738 } catch (InterruptedException e) { 739 Log.i(TAG, "Test interrupted!"); 740 } 741 742 // Make sure any procedures to disconnect existing calls (makeRoomForOutgoingCall) 743 // complete successfully 744 TestUtils.waitOnLocalMainLooper(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 745 TestUtils.waitOnAllHandlers(getInstrumentation()); 746 747 assertEquals("InCallService should match the expected count.", expectedCallCount, 748 mInCallCallbacks.getService().getCallCount()); 749 } 750 751 /** 752 * Place an emergency call and verify that it has been setup properly. 753 * 754 * @param supportsHold If telecom supports holding emergency calls, this will expect two 755 * calls. If telecom does not support holding emergency calls, this will expect only the 756 * emergency call to be active. 757 * @return The emergency connection 758 */ placeAndVerifyEmergencyCall(boolean supportsHold)759 public Connection placeAndVerifyEmergencyCall(boolean supportsHold) { 760 Bundle extras = new Bundle(); 761 extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, TEST_EMERGENCY_URI); 762 // We want to request the active connections vs number of connections because in some cases, 763 // we wait to destroy the underlying connection to prevent race conditions. This will result 764 // in Connections in the DISCONNECTED state. 765 int currentConnectionCount = supportsHold ? 766 getNumberOfActiveConnections() + 1 : getNumberOfActiveConnections(); 767 int currentCallCount = (getInCallService() == null) ? 0 : getInCallService().getCallCount(); 768 currentCallCount = supportsHold ? currentCallCount + 1 : currentCallCount; 769 // The device only supports a max of two calls active at any one time 770 currentCallCount = Math.min(currentCallCount, 2); 771 772 placeAndVerifyCall(extras, VideoProfile.STATE_AUDIO_ONLY, currentCallCount); 773 // The connectionService.lock is released in 774 // MockConnectionService#onCreateOutgoingConnection, however the connection will not 775 // actually be added to the list of connections in the ConnectionService until shortly 776 // afterwards. So there is still a potential for the lock to be released before it would 777 // be seen by calls to ConnectionService#getAllConnections(). 778 // We will wait here until the list of connections includes one more connection to ensure 779 // that placing the call has fully completed. 780 assertActiveCSConnections(currentConnectionCount); 781 782 assertOutgoingCallBroadcastReceived(true); 783 Connection connection = verifyConnectionForOutgoingCall(TEST_EMERGENCY_URI); 784 TestUtils.waitOnAllHandlers(getInstrumentation()); 785 return connection; 786 } 787 getNumberOfConnections()788 int getNumberOfConnections() { 789 return CtsConnectionService.getAllConnectionsFromTelecom().size(); 790 } 791 getNumberOfActiveConnections()792 int getNumberOfActiveConnections() { 793 return CtsConnectionService.getAllConnectionsFromTelecom().stream() 794 .filter(c -> c.getState() != Connection.STATE_DISCONNECTED).collect( 795 Collectors.toSet()).size(); 796 } 797 getConnection(Uri address)798 Connection getConnection(Uri address) { 799 return CtsConnectionService.getAllConnectionsFromTelecom().stream() 800 .filter(c -> c.getAddress().equals(address)).findFirst().orElse(null); 801 } 802 verifyConnectionForOutgoingCall()803 MockConnection verifyConnectionForOutgoingCall() { 804 // Assuming only 1 connection present 805 return verifyConnectionForOutgoingCall(0); 806 } 807 verifyConnectionForOutgoingCall(int connectionIndex)808 MockConnection verifyConnectionForOutgoingCall(int connectionIndex) { 809 try { 810 if (!connectionService.lock.tryAcquire(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 811 TimeUnit.MILLISECONDS)) { 812 fail("No outgoing call connection requested by Telecom"); 813 } 814 } catch (InterruptedException e) { 815 Log.i(TAG, "Test interrupted!"); 816 } 817 818 assertThat("Telecom should create outgoing connection for outgoing call", 819 connectionService.outgoingConnections.size(), not(equalTo(0))); 820 MockConnection connection = connectionService.outgoingConnections.get(connectionIndex); 821 return connection; 822 } 823 verifyConnectionForOutgoingCall(Uri address)824 MockConnection verifyConnectionForOutgoingCall(Uri address) { 825 if (!connectionService.waitForEvent( 826 MockConnectionService.EVENT_CONNECTION_SERVICE_CREATE_CONNECTION)) { 827 fail("No outgoing call connection requested by Telecom"); 828 } 829 assertThat("Telecom should create outgoing connection for outgoing call", 830 connectionService.outgoingConnections.size(), not(equalTo(0))); 831 832 // There is a subtle race condition in ConnectionService. When onCreateIncomingConnection 833 // or onCreateOutgoingConnection completes, ConnectionService then adds the connection to 834 // the list of tracked connections. It's very possible for the lock to be released and 835 // the connection to have not yet been added to the connection list yet. 836 waitUntilConditionIsTrueOrTimeout(new Condition() { 837 @Override 838 public Object expected() { 839 return true; 840 } 841 842 @Override 843 public Object actual() { 844 return getConnection(address) != null; 845 } 846 }, 847 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 848 "Expected call from number " + address); 849 Connection connection = getConnection(address); 850 851 if (connection instanceof MockConnection) { 852 if (connectionService.outgoingConnections.contains(connection)) { 853 return (MockConnection) connection; 854 } 855 } 856 return null; 857 } 858 verifyConnectionForIncomingCall()859 MockConnection verifyConnectionForIncomingCall() { 860 // Assuming only 1 connection present 861 return verifyConnectionForIncomingCall(0); 862 } 863 verifyConnectionForIncomingCall(int connectionIndex)864 MockConnection verifyConnectionForIncomingCall(int connectionIndex) { 865 try { 866 if (!connectionService.lock.tryAcquire(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 867 TimeUnit.MILLISECONDS)) { 868 fail("No outgoing call connection requested by Telecom"); 869 } 870 } catch (InterruptedException e) { 871 Log.i(TAG, "Test interrupted!"); 872 } 873 874 assertThat("Telecom should create incoming connections for incoming calls", 875 connectionService.incomingConnections.size(), not(equalTo(0))); 876 MockConnection connection = connectionService.incomingConnections.get(connectionIndex); 877 setAndVerifyConnectionForIncomingCall(connection); 878 return connection; 879 } 880 verifyConference(int permit)881 MockConference verifyConference(int permit) { 882 try { 883 if (!connectionService.lock.tryAcquire(permit, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 884 TimeUnit.MILLISECONDS)) { 885 fail("No conference requested by Telecom"); 886 } 887 } catch (InterruptedException e) { 888 Log.i(TAG, "Test interrupted!"); 889 } 890 return connectionService.conferences.get(0); 891 } 892 setAndVerifyConnectionForIncomingCall(MockConnection connection)893 void setAndVerifyConnectionForIncomingCall(MockConnection connection) { 894 if (connection.getState() == Connection.STATE_ACTIVE) { 895 // If the connection is already active (like if it got picked up immediately), don't 896 // bother with setting it back to ringing. 897 return; 898 } 899 connection.setRinging(); 900 assertConnectionState(connection, Connection.STATE_RINGING); 901 } 902 setAndVerifyConferenceablesForOutgoingConnection(int connectionIndex)903 void setAndVerifyConferenceablesForOutgoingConnection(int connectionIndex) { 904 assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); 905 // Make all other outgoing connections as conferenceable with this connection. 906 MockConnection connection = connectionService.outgoingConnections.get(connectionIndex); 907 List<Connection> confConnections = 908 new ArrayList<>(connectionService.outgoingConnections.size()); 909 for (Connection c : connectionService.outgoingConnections) { 910 if (c != connection) { 911 confConnections.add(c); 912 } 913 } 914 connection.setConferenceableConnections(confConnections); 915 assertEquals(connection.getConferenceables(), confConnections); 916 } 917 addConferenceCall(Call call1, Call call2)918 void addConferenceCall(Call call1, Call call2) { 919 assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); 920 int currentConfCallCount = 0; 921 if (mInCallCallbacks.getService() != null) { 922 currentConfCallCount = mInCallCallbacks.getService().getConferenceCallCount(); 923 } 924 // Verify that the calls have each other on their conferenceable list before proceeding 925 List<Call> callConfList = new ArrayList<>(); 926 callConfList.add(call2); 927 assertCallConferenceableList(call1, callConfList); 928 929 callConfList.clear(); 930 callConfList.add(call1); 931 assertCallConferenceableList(call2, callConfList); 932 933 call1.conference(call2); 934 935 /** 936 * We should have 1 onCallAdded, 2 onChildrenChanged and 2 onParentChanged invoked, so 937 * we should have 5 available permits on the incallService lock. 938 */ 939 try { 940 if (!mInCallCallbacks.lock.tryAcquire(5, 3, TimeUnit.SECONDS)) { 941 fail("Conference addition failed."); 942 } 943 } catch (InterruptedException e) { 944 Log.i(TAG, "Test interrupted!"); 945 } 946 947 assertEquals("InCallService should contain 1 more call after adding a conf call.", 948 currentConfCallCount + 1, 949 mInCallCallbacks.getService().getConferenceCallCount()); 950 } 951 splitFromConferenceCall(Call call1)952 void splitFromConferenceCall(Call call1) { 953 assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); 954 955 call1.splitFromConference(); 956 /** 957 * We should have 1 onChildrenChanged and 1 onParentChanged invoked, so 958 * we should have 2 available permits on the incallService lock. 959 */ 960 try { 961 if (!mInCallCallbacks.lock.tryAcquire(2, 3, TimeUnit.SECONDS)) { 962 fail("Conference split failed"); 963 } 964 } catch (InterruptedException e) { 965 Log.i(TAG, "Test interrupted!"); 966 } 967 } 968 verifyConferenceForOutgoingCall()969 MockConference verifyConferenceForOutgoingCall() { 970 try { 971 if (!connectionService.lock.tryAcquire(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 972 TimeUnit.MILLISECONDS)) { 973 fail("No outgoing conference requested by Telecom"); 974 } 975 } catch (InterruptedException e) { 976 Log.i(TAG, "Test interrupted!"); 977 } 978 // Return the newly created conference object to the caller 979 MockConference conference = connectionService.conferences.get(0); 980 setAndVerifyConferenceForOutgoingCall(conference); 981 return conference; 982 } 983 verifyAdhocConferenceCall()984 Pair<Conference, ConnectionRequest> verifyAdhocConferenceCall() { 985 try { 986 if (!connectionService.lock.tryAcquire(2, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 987 TimeUnit.MILLISECONDS)) { 988 fail("No conference requested by Telecom"); 989 } 990 } catch (InterruptedException e) { 991 Log.i(TAG, "Test interrupted!"); 992 } 993 return new Pair<>(connectionService.conferences.get(0), 994 connectionService.connectionRequest); 995 } 996 setAndVerifyConferenceForOutgoingCall(MockConference conference)997 void setAndVerifyConferenceForOutgoingCall(MockConference conference) { 998 conference.setActive(); 999 assertConferenceState(conference, Connection.STATE_ACTIVE); 1000 } 1001 verifyCallStateListener(int expectedCallState)1002 void verifyCallStateListener(int expectedCallState) throws InterruptedException { 1003 mTestCallStateListener.getCountDownLatch().await( 1004 TestUtils.WAIT_FOR_PHONE_STATE_LISTENER_CALLBACK_TIMEOUT_S, TimeUnit.SECONDS); 1005 assertEquals(expectedCallState, mTestCallStateListener.getLastState()); 1006 } 1007 verifyPhoneStateListenerCallbacksForCall(int expectedCallState, String expectedNumber)1008 void verifyPhoneStateListenerCallbacksForCall(int expectedCallState, String expectedNumber) 1009 throws Exception { 1010 assertTrue(mTelephonyCallback.mCallbackSemaphore.tryAcquire( 1011 TestUtils.WAIT_FOR_PHONE_STATE_LISTENER_CALLBACK_TIMEOUT_S, TimeUnit.SECONDS)); 1012 // At this point we can only be sure that we got AN update, but not necessarily the one we 1013 // are looking for; wait until we see the state we want before verifying further. 1014 waitUntilConditionIsTrueOrTimeout(new Condition() { 1015 @Override 1016 public Object expected() { 1017 return true; 1018 } 1019 1020 @Override 1021 public Object actual() { 1022 return mTelephonyCallback.mCallStates 1023 .stream() 1024 .filter(p -> p == expectedCallState) 1025 .count() > 0; 1026 } 1027 }, 1028 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1029 "Expected call state " + expectedCallState + " and number " 1030 + expectedNumber); 1031 1032 1033 // Get the most recent callback; it is possible that there was an initial state reported due 1034 // to the fact that TelephonyManager will sometimes give an initial state back to the caller 1035 // when the listener is registered. 1036 int callState = mTelephonyCallback.mCallStates.get( 1037 mTelephonyCallback.mCallStates.size() - 1); 1038 assertEquals(expectedCallState, callState); 1039 // Note: We do NOT check the phone number here. Due to changes in how the phone state 1040 // broadcast is sent, the caller may receive multiple broadcasts, and the number will be 1041 // present in one or the other. We waited for a full matching broadcast above so we can 1042 // be sure the number was reported as expected. 1043 } 1044 verifyPhoneStateListenerCallbacksForEmergencyCall(String expectedNumber)1045 void verifyPhoneStateListenerCallbacksForEmergencyCall(String expectedNumber) 1046 throws Exception { 1047 assertTrue(mTelephonyCallback.mCallbackSemaphore.tryAcquire( 1048 TestUtils.WAIT_FOR_PHONE_STATE_LISTENER_CALLBACK_TIMEOUT_S, TimeUnit.SECONDS)); 1049 // At this point we can only be sure that we got AN update, but not necessarily the one we 1050 // are looking for; wait until we see the state we want before verifying further. 1051 waitUntilConditionIsTrueOrTimeout(new Condition() { 1052 @Override 1053 public Object expected() { 1054 return true; 1055 } 1056 1057 @Override 1058 public Object actual() { 1059 return mTelephonyCallback 1060 .mLastOutgoingEmergencyNumber != null 1061 && mTelephonyCallback 1062 .mLastOutgoingEmergencyNumber.getNumber() 1063 .equals(expectedNumber); 1064 } 1065 }, 1066 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1067 "Expected emergency number: " + expectedNumber); 1068 1069 assertEquals(mTelephonyCallback.mLastOutgoingEmergencyNumber.getNumber(), 1070 expectedNumber); 1071 } 1072 1073 /** 1074 * Disconnect the created test call and verify that Telecom has cleared all calls. 1075 */ cleanupCalls()1076 void cleanupCalls() { 1077 if (mInCallCallbacks != null && mInCallCallbacks.getService() != null) { 1078 mInCallCallbacks.getService().disconnectAllConferenceCalls(); 1079 mInCallCallbacks.getService().disconnectAllCalls(); 1080 assertNumConferenceCalls(mInCallCallbacks.getService(), 0); 1081 assertNumCalls(mInCallCallbacks.getService(), 0); 1082 } 1083 } 1084 1085 /** 1086 * Place a new outgoing call via the {@link CtsConnectionService} 1087 */ placeNewCallWithPhoneAccount(Bundle extras, int videoState)1088 private void placeNewCallWithPhoneAccount(Bundle extras, int videoState) { 1089 if (extras == null) { 1090 extras = new Bundle(); 1091 } 1092 if (!extras.containsKey(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE)) { 1093 extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, 1094 TestUtils.TEST_PHONE_ACCOUNT_HANDLE); 1095 } 1096 1097 if (!VideoProfile.isAudioOnly(videoState)) { 1098 extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState); 1099 } 1100 Uri number; 1101 if (extras.containsKey(TestUtils.EXTRA_PHONE_NUMBER)) { 1102 number = extras.getParcelable(TestUtils.EXTRA_PHONE_NUMBER); 1103 } else { 1104 number = createTestNumber(); 1105 } 1106 mTelecomManager.placeCall(number, extras); 1107 } 1108 1109 /** 1110 * Create a new number each time for a new test. Telecom has special logic to reuse certain 1111 * calls if multiple calls to the same number are placed within a short period of time which 1112 * can cause certain tests to fail. 1113 */ createTestNumber()1114 Uri createTestNumber() { 1115 return Uri.fromParts("tel", String.valueOf(++sCounter), null); 1116 } 1117 1118 /** 1119 * Creates a new random phone number in the range: 1120 * 000-000-0000 1121 * to 1122 * 999-999-9999 1123 * @return Randomized phone number. 1124 */ createRandomTestNumber()1125 Uri createRandomTestNumber() { 1126 return Uri.fromParts("tel", String.format("16%05d", new Random().nextInt(99999)) 1127 + String.format("%04d", new Random().nextInt(9999)), null); 1128 } 1129 getTestNumber()1130 public static Uri getTestNumber() { 1131 return Uri.fromParts("tel", String.valueOf(sCounter), null); 1132 } 1133 isLoggedCall(PhoneAccountHandle handle)1134 public boolean isLoggedCall(PhoneAccountHandle handle) { 1135 PhoneAccount phoneAccount = mTelecomManager.getPhoneAccount(handle); 1136 Bundle extras = phoneAccount.getExtras(); 1137 if (extras == null) { 1138 extras = new Bundle(); 1139 } 1140 boolean isSelfManaged = (phoneAccount.getCapabilities() 1141 & PhoneAccount.CAPABILITY_SELF_MANAGED) == PhoneAccount.CAPABILITY_SELF_MANAGED; 1142 // Calls are logged if: 1143 // 1. They're not self-managed 1144 // 2. They're self-managed and are configured to request logging. 1145 return (!isSelfManaged 1146 || (isSelfManaged 1147 && extras.getBoolean(PhoneAccount.EXTRA_LOG_SELF_MANAGED_CALLS) 1148 && (phoneAccount.getSupportedUriSchemes().contains(PhoneAccount.SCHEME_TEL) 1149 || phoneAccount.getSupportedUriSchemes().contains(PhoneAccount.SCHEME_SIP)))); 1150 } 1151 getCallLogEntryLatch()1152 public CountDownLatch getCallLogEntryLatch() { 1153 CountDownLatch changeLatch = new CountDownLatch(1); 1154 mContext.getContentResolver().registerContentObserver( 1155 CallLog.Calls.CONTENT_URI, true, 1156 new ContentObserver(mHandler) { 1157 @Override 1158 public void onChange(boolean selfChange, Uri uri) { 1159 mContext.getContentResolver().unregisterContentObserver(this); 1160 changeLatch.countDown(); 1161 super.onChange(selfChange); 1162 } 1163 }); 1164 return changeLatch; 1165 } 1166 1167 verifyCallLogging(CountDownLatch logLatch, boolean isCallLogged, Uri testNumber)1168 public void verifyCallLogging(CountDownLatch logLatch, boolean isCallLogged, Uri testNumber) { 1169 Cursor logCursor = getLatestCallLogCursorIfMatchesUri(logLatch, isCallLogged, testNumber); 1170 if (isCallLogged) { 1171 assertNotNull("Call log entry not found for test number", logCursor); 1172 } 1173 } 1174 verifyCallLogging(Uri testNumber, int expectedLogType)1175 public void verifyCallLogging(Uri testNumber, int expectedLogType) { 1176 CountDownLatch logLatch = getCallLogEntryLatch(); 1177 Cursor logCursor = getLatestCallLogCursorIfMatchesUri(logLatch, true /*isCallLogged*/, 1178 testNumber); 1179 assertNotNull("Call log entry not found for test number", logCursor); 1180 int typeIndex = logCursor.getColumnIndex(CallLog.Calls.TYPE); 1181 int type = logCursor.getInt(typeIndex); 1182 assertEquals("recorded type does not match expected", expectedLogType, type); 1183 } 1184 getLatestCallLogCursorIfMatchesUri(CountDownLatch latch, boolean newLogExpected, Uri testNumber)1185 public Cursor getLatestCallLogCursorIfMatchesUri(CountDownLatch latch, boolean newLogExpected, 1186 Uri testNumber) { 1187 if (newLogExpected) { 1188 // Wait for the content observer to report that we have gotten a new call log entry. 1189 try { 1190 latch.await(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, TimeUnit.MILLISECONDS); 1191 } catch (InterruptedException ie) { 1192 fail("Expected log latch"); 1193 } 1194 } 1195 1196 // Query the latest entry into the call log. 1197 Cursor callsCursor = mContext.getContentResolver().query(CallLog.Calls.CONTENT_URI, null, 1198 null, null, CallLog.Calls._ID + " DESC limit 1;"); 1199 int numberIndex = callsCursor.getColumnIndex(CallLog.Calls.NUMBER); 1200 if (callsCursor.moveToNext()) { 1201 String number = callsCursor.getString(numberIndex); 1202 if (testNumber.getSchemeSpecificPart().equals(number)) { 1203 return callsCursor; 1204 } else { 1205 // Last call log entry doesnt match expected number. 1206 return null; 1207 } 1208 } 1209 // No Calls 1210 return null; 1211 } 1212 assertNumCalls(final MockInCallService inCallService, final int numCalls)1213 void assertNumCalls(final MockInCallService inCallService, final int numCalls) { 1214 waitUntilConditionIsTrueOrTimeout(new Condition() { 1215 @Override 1216 public Object expected() { 1217 return numCalls; 1218 } 1219 @Override 1220 public Object actual() { 1221 return inCallService.getCallCount(); 1222 } 1223 }, 1224 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1225 "InCallService should contain " + numCalls + " calls." 1226 ); 1227 } 1228 assertNumConferenceCalls(final MockInCallService inCallService, final int numCalls)1229 void assertNumConferenceCalls(final MockInCallService inCallService, final int numCalls) { 1230 waitUntilConditionIsTrueOrTimeout(new Condition() { 1231 @Override 1232 public Object expected() { 1233 return numCalls; 1234 } 1235 @Override 1236 public Object actual() { 1237 return inCallService.getConferenceCallCount(); 1238 } 1239 }, 1240 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1241 "InCallService should contain " + numCalls + " conference calls." 1242 ); 1243 } 1244 assertActiveCSConnections(final int numConnections)1245 void assertActiveCSConnections(final int numConnections) { 1246 waitUntilConditionIsTrueOrTimeout(new Condition() { 1247 @Override 1248 public Object expected() { 1249 return numConnections; 1250 } 1251 1252 @Override 1253 public Object actual() { 1254 return getNumberOfActiveConnections(); 1255 } 1256 }, 1257 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1258 "ConnectionService should contain " + numConnections + " connections." 1259 ); 1260 } 1261 assertCSConnections(final int numConnections)1262 void assertCSConnections(final int numConnections) { 1263 waitUntilConditionIsTrueOrTimeout(new Condition() { 1264 @Override 1265 public Object expected() { 1266 return numConnections; 1267 } 1268 1269 @Override 1270 public Object actual() { 1271 return CtsConnectionService 1272 .getAllConnectionsFromTelecom() 1273 .size(); 1274 } 1275 }, 1276 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1277 "ConnectionService should contain " + numConnections + " connections." 1278 ); 1279 } 1280 assertNumConnections(final MockConnectionService connService, final int numConnections)1281 void assertNumConnections(final MockConnectionService connService, final int numConnections) { 1282 waitUntilConditionIsTrueOrTimeout(new Condition() { 1283 @Override 1284 public Object expected() { 1285 return numConnections; 1286 } 1287 @Override 1288 public Object actual() { 1289 return connService.getAllConnections().size(); 1290 } 1291 }, 1292 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1293 "ConnectionService should contain " + numConnections + " connections." 1294 ); 1295 } 1296 assertMuteState(final InCallService incallService, final boolean isMuted)1297 void assertMuteState(final InCallService incallService, final boolean isMuted) { 1298 waitUntilConditionIsTrueOrTimeout( 1299 new Condition() { 1300 @Override 1301 public Object expected() { 1302 return isMuted; 1303 } 1304 1305 @Override 1306 public Object actual() { 1307 final CallAudioState state = incallService.getCallAudioState(); 1308 return state == null ? null : state.isMuted(); 1309 } 1310 }, 1311 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1312 "Phone's mute state should be: " + isMuted 1313 ); 1314 } 1315 assertMuteState(final MockConnection connection, final boolean isMuted)1316 void assertMuteState(final MockConnection connection, final boolean isMuted) { 1317 waitUntilConditionIsTrueOrTimeout( 1318 new Condition() { 1319 @Override 1320 public Object expected() { 1321 return isMuted; 1322 } 1323 1324 @Override 1325 public Object actual() { 1326 final CallAudioState state = connection.getCallAudioState(); 1327 return state == null ? null : state.isMuted(); 1328 } 1329 }, 1330 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1331 "Connection's mute state should be: " + isMuted 1332 ); 1333 } 1334 assertAudioRoute(final InCallService incallService, final int route)1335 void assertAudioRoute(final InCallService incallService, final int route) { 1336 waitUntilConditionIsTrueOrTimeout( 1337 new Condition() { 1338 @Override 1339 public Object expected() { 1340 return route; 1341 } 1342 1343 @Override 1344 public Object actual() { 1345 final CallAudioState state = incallService.getCallAudioState(); 1346 return state == null ? null : state.getRoute(); 1347 } 1348 }, 1349 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1350 "Phone's audio route should be: " + route 1351 ); 1352 } 1353 assertNotAudioRoute(final InCallService incallService, final int route)1354 void assertNotAudioRoute(final InCallService incallService, final int route) { 1355 waitUntilConditionIsTrueOrTimeout( 1356 new Condition() { 1357 @Override 1358 public Object expected() { 1359 return new Boolean(true); 1360 } 1361 1362 @Override 1363 public Object actual() { 1364 final CallAudioState state = incallService.getCallAudioState(); 1365 return route != state.getRoute(); 1366 } 1367 }, 1368 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1369 "Phone's audio route should not be: " + route 1370 ); 1371 } 1372 assertAudioRoute(final MockConnection connection, final int route)1373 void assertAudioRoute(final MockConnection connection, final int route) { 1374 waitUntilConditionIsTrueOrTimeout( 1375 new Condition() { 1376 @Override 1377 public Object expected() { 1378 return route; 1379 } 1380 1381 @Override 1382 public Object actual() { 1383 final CallAudioState state = ((Connection) connection).getCallAudioState(); 1384 return state == null ? null : state.getRoute(); 1385 } 1386 }, 1387 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1388 "Connection's audio route should be: " + route 1389 ); 1390 } 1391 assertConnectionState(final Connection connection, final int state)1392 void assertConnectionState(final Connection connection, final int state) { 1393 waitUntilConditionIsTrueOrTimeout( 1394 new Condition() { 1395 @Override 1396 public Object expected() { 1397 return state; 1398 } 1399 1400 @Override 1401 public Object actual() { 1402 return connection.getState(); 1403 } 1404 }, 1405 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1406 "Connection should be in state " + state 1407 ); 1408 } 1409 assertCallState(final Call call, final int state)1410 void assertCallState(final Call call, final int state) { 1411 waitUntilConditionIsTrueOrTimeout( 1412 new Condition() { 1413 @Override 1414 public Object expected() { 1415 return true; 1416 } 1417 1418 @Override 1419 public Object actual() { 1420 return call.getState() == state && call.getDetails().getState() == state; 1421 } 1422 }, 1423 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1424 "Expected state: " + state + ", callState=" + call.getState() + ", detailState=" 1425 + call.getDetails().getState() 1426 ); 1427 } 1428 assertCallConferenceableList(final Call call, final List<Call> conferenceableList)1429 void assertCallConferenceableList(final Call call, final List<Call> conferenceableList) { 1430 waitUntilConditionIsTrueOrTimeout( 1431 new Condition() { 1432 @Override 1433 public Object expected() { 1434 return conferenceableList; 1435 } 1436 1437 @Override 1438 public Object actual() { 1439 return call.getConferenceableCalls(); 1440 } 1441 }, 1442 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1443 "Call: " + call + " does not have the correct conferenceable call list." 1444 ); 1445 } 1446 assertDtmfString(final MockConnection connection, final String dtmfString)1447 void assertDtmfString(final MockConnection connection, final String dtmfString) { 1448 waitUntilConditionIsTrueOrTimeout(new Condition() { 1449 @Override 1450 public Object expected() { 1451 return dtmfString; 1452 } 1453 1454 @Override 1455 public Object actual() { 1456 return connection.getDtmfString(); 1457 } 1458 }, 1459 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1460 "DTMF string should be equivalent to entered DTMF characters: " + dtmfString 1461 ); 1462 } 1463 assertDtmfString(final MockConference conference, final String dtmfString)1464 void assertDtmfString(final MockConference conference, final String dtmfString) { 1465 waitUntilConditionIsTrueOrTimeout(new Condition() { 1466 @Override 1467 public Object expected() { 1468 return dtmfString; 1469 } 1470 1471 @Override 1472 public Object actual() { 1473 return conference.getDtmfString(); 1474 } 1475 }, 1476 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1477 "DTMF string should be equivalent to entered DTMF characters: " + dtmfString 1478 ); 1479 } 1480 assertCallDisplayName(final Call call, final String name)1481 void assertCallDisplayName(final Call call, final String name) { 1482 waitUntilConditionIsTrueOrTimeout( 1483 new Condition() { 1484 @Override 1485 public Object expected() { 1486 return name; 1487 } 1488 1489 @Override 1490 public Object actual() { 1491 return call.getDetails().getCallerDisplayName(); 1492 } 1493 }, 1494 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1495 "Call should have display name: " + name 1496 ); 1497 } 1498 assertCallHandle(final Call call, final Uri expectedHandle)1499 void assertCallHandle(final Call call, final Uri expectedHandle) { 1500 waitUntilConditionIsTrueOrTimeout( 1501 new Condition() { 1502 @Override 1503 public Object expected() { 1504 return expectedHandle; 1505 } 1506 1507 @Override 1508 public Object actual() { 1509 return call.getDetails().getHandle(); 1510 } 1511 }, 1512 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1513 "Call should have handle name: " + expectedHandle 1514 ); 1515 } 1516 assertCallConnectTimeChanged(final Call call, final long time)1517 void assertCallConnectTimeChanged(final Call call, final long time) { 1518 waitUntilConditionIsTrueOrTimeout( 1519 new Condition() { 1520 @Override 1521 public Object expected() { 1522 return true; 1523 } 1524 1525 @Override 1526 public Object actual() { 1527 return call.getDetails().getConnectTimeMillis() != time; 1528 } 1529 }, 1530 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1531 "Call have connect time: " + time 1532 ); 1533 } 1534 assertConnectionCallDisplayName(final Connection connection, final String name)1535 void assertConnectionCallDisplayName(final Connection connection, final String name) { 1536 waitUntilConditionIsTrueOrTimeout( 1537 new Condition() { 1538 @Override 1539 public Object expected() { 1540 return name; 1541 } 1542 1543 @Override 1544 public Object actual() { 1545 return connection.getCallerDisplayName(); 1546 } 1547 }, 1548 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1549 "Connection should have display name: " + name 1550 ); 1551 } 1552 assertDisconnectReason(final Connection connection, final String disconnectReason)1553 void assertDisconnectReason(final Connection connection, final String disconnectReason) { 1554 waitUntilConditionIsTrueOrTimeout( 1555 new Condition() { 1556 @Override 1557 public Object expected() { 1558 return disconnectReason; 1559 } 1560 1561 @Override 1562 public Object actual() { 1563 return connection.getDisconnectCause().getReason(); 1564 } 1565 }, 1566 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1567 "Connection should have been disconnected with reason: " + disconnectReason 1568 ); 1569 } 1570 assertConferenceState(final Conference conference, final int state)1571 void assertConferenceState(final Conference conference, final int state) { 1572 waitUntilConditionIsTrueOrTimeout( 1573 new Condition() { 1574 @Override 1575 public Object expected() { 1576 return state; 1577 } 1578 1579 @Override 1580 public Object actual() { 1581 return conference.getState(); 1582 } 1583 }, 1584 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1585 "Conference should be in state " + state 1586 ); 1587 } 1588 1589 assertOutgoingCallBroadcastReceived(boolean received)1590 void assertOutgoingCallBroadcastReceived(boolean received) { 1591 waitUntilConditionIsTrueOrTimeout( 1592 new Condition() { 1593 @Override 1594 public Object expected() { 1595 return received; 1596 } 1597 1598 @Override 1599 public Object actual() { 1600 return NewOutgoingCallBroadcastReceiver 1601 .isNewOutgoingCallBroadcastReceived(); 1602 } 1603 }, 1604 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1605 received ? "Outgoing Call Broadcast should be received" 1606 : "Outgoing Call Broadcast should not be received" 1607 ); 1608 } 1609 assertCallDetailsConstructed(Call mCall, boolean constructed)1610 void assertCallDetailsConstructed(Call mCall, boolean constructed) { 1611 waitUntilConditionIsTrueOrTimeout( 1612 new Condition() { 1613 @Override 1614 public Object expected() { 1615 return constructed; 1616 } 1617 1618 @Override 1619 public Object actual() { 1620 return mCall != null && mCall.getDetails() != null; 1621 } 1622 }, 1623 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1624 constructed ? "Call Details should be constructed" 1625 : "Call Details should not be constructed" 1626 ); 1627 } 1628 assertCallGatewayConstructed(Call mCall, boolean constructed)1629 void assertCallGatewayConstructed(Call mCall, boolean constructed) { 1630 waitUntilConditionIsTrueOrTimeout( 1631 new Condition() { 1632 @Override 1633 public Object expected() { 1634 return constructed; 1635 } 1636 1637 @Override 1638 public Object actual() { 1639 return mCall != null && mCall.getDetails() != null 1640 && mCall.getDetails().getGatewayInfo() != null; 1641 } 1642 }, 1643 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1644 constructed ? "Call Gateway should be constructed" 1645 : "Call Gateway should not be constructed" 1646 ); 1647 } 1648 assertCallNotNull(Call mCall, boolean notNull)1649 void assertCallNotNull(Call mCall, boolean notNull) { 1650 waitUntilConditionIsTrueOrTimeout( 1651 new Condition() { 1652 @Override 1653 public Object expected() { 1654 return notNull; 1655 } 1656 1657 @Override 1658 public Object actual() { 1659 return mCall != null; 1660 } 1661 }, 1662 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1663 notNull ? "Call should not be null" : "Call should be null" 1664 ); 1665 } 1666 1667 /** 1668 * Checks all fields of two PhoneAccounts for equality, with the exception of the enabled state. 1669 * Should only be called after assertPhoneAccountRegistered when it can be guaranteed 1670 * that the PhoneAccount is registered. 1671 * @param expected The expected PhoneAccount. 1672 * @param actual The actual PhoneAccount. 1673 */ assertPhoneAccountEquals(final PhoneAccount expected, final PhoneAccount actual)1674 void assertPhoneAccountEquals(final PhoneAccount expected, 1675 final PhoneAccount actual) { 1676 assertEquals(expected.getAddress(), actual.getAddress()); 1677 assertEquals(expected.getAccountHandle(), actual.getAccountHandle()); 1678 assertEquals(expected.getCapabilities(), actual.getCapabilities()); 1679 assertTrue(areBundlesEqual(expected.getExtras(), actual.getExtras())); 1680 assertEquals(expected.getHighlightColor(), actual.getHighlightColor()); 1681 assertEquals(expected.getIcon(), actual.getIcon()); 1682 assertEquals(expected.getLabel(), actual.getLabel()); 1683 assertEquals(expected.getShortDescription(), actual.getShortDescription()); 1684 assertEquals(expected.getSubscriptionAddress(), actual.getSubscriptionAddress()); 1685 assertEquals(expected.getSupportedUriSchemes(), actual.getSupportedUriSchemes()); 1686 } 1687 assertPhoneAccountRegistered(final PhoneAccountHandle handle)1688 void assertPhoneAccountRegistered(final PhoneAccountHandle handle) { 1689 waitUntilConditionIsTrueOrTimeout( 1690 new Condition() { 1691 @Override 1692 public Object expected() { 1693 return true; 1694 } 1695 1696 @Override 1697 public Object actual() { 1698 return mTelecomManager.getPhoneAccount(handle) != null; 1699 } 1700 }, 1701 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1702 "Phone account registration failed for " + handle 1703 ); 1704 } 1705 assertPhoneAccountEnabled(final PhoneAccountHandle handle)1706 void assertPhoneAccountEnabled(final PhoneAccountHandle handle) { 1707 waitUntilConditionIsTrueOrTimeout( 1708 new Condition() { 1709 @Override 1710 public Object expected() { 1711 return true; 1712 } 1713 1714 @Override 1715 public Object actual() { 1716 PhoneAccount phoneAccount = mTelecomManager.getPhoneAccount(handle); 1717 return (phoneAccount != null && phoneAccount.isEnabled()); 1718 } 1719 }, 1720 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1721 "Phone account enable failed for " + handle 1722 ); 1723 } 1724 assertPhoneAccountIsDefault(final PhoneAccountHandle handle)1725 void assertPhoneAccountIsDefault(final PhoneAccountHandle handle) { 1726 waitUntilConditionIsTrueOrTimeout( 1727 new Condition() { 1728 @Override 1729 public Object expected() { 1730 return true; 1731 } 1732 1733 @Override 1734 public Object actual() { 1735 PhoneAccountHandle phoneAccountHandle = 1736 mTelecomManager.getUserSelectedOutgoingPhoneAccount(); 1737 return (phoneAccountHandle != null && phoneAccountHandle.equals(handle)); 1738 } 1739 }, 1740 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1741 "Failed to set default phone account to " + handle 1742 ); 1743 } 1744 assertCtsConnectionServiceUnbound()1745 void assertCtsConnectionServiceUnbound() { 1746 if (CtsConnectionService.isBound()) { 1747 assertTrue("CtsConnectionService not yet unbound!", 1748 CtsConnectionService.waitForUnBinding()); 1749 } 1750 } 1751 assertMockInCallServiceUnbound()1752 void assertMockInCallServiceUnbound() { 1753 waitUntilConditionIsTrueOrTimeout( 1754 new Condition() { 1755 @Override 1756 public Object expected() { 1757 return false; 1758 } 1759 1760 @Override 1761 public Object actual() { 1762 return MockInCallService.isServiceBound(); 1763 } 1764 }, 1765 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1766 "MockInCallService not yet unbound!" 1767 ); 1768 } 1769 assertIsOutgoingCallPermitted(boolean isPermitted, PhoneAccountHandle handle)1770 void assertIsOutgoingCallPermitted(boolean isPermitted, PhoneAccountHandle handle) { 1771 waitUntilConditionIsTrueOrTimeout( 1772 new Condition() { 1773 @Override 1774 public Object expected() { 1775 return isPermitted; 1776 } 1777 1778 @Override 1779 public Object actual() { 1780 return mTelecomManager.isOutgoingCallPermitted(handle); 1781 } 1782 }, 1783 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1784 "Expected isOutgoingCallPermitted to be " + isPermitted 1785 ); 1786 } 1787 assertIsIncomingCallPermitted(boolean isPermitted, PhoneAccountHandle handle)1788 void assertIsIncomingCallPermitted(boolean isPermitted, PhoneAccountHandle handle) { 1789 waitUntilConditionIsTrueOrTimeout( 1790 new Condition() { 1791 @Override 1792 public Object expected() { 1793 return isPermitted; 1794 } 1795 1796 @Override 1797 public Object actual() { 1798 return mTelecomManager.isIncomingCallPermitted(handle); 1799 } 1800 }, 1801 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1802 "Expected isIncomingCallPermitted to be " + isPermitted 1803 ); 1804 } 1805 assertIsInCall(boolean isIncall)1806 void assertIsInCall(boolean isIncall) { 1807 waitUntilConditionIsTrueOrTimeout( 1808 new Condition() { 1809 @Override 1810 public Object expected() { 1811 return isIncall; 1812 } 1813 1814 @Override 1815 public Object actual() { 1816 return mTelecomManager.isInCall(); 1817 } 1818 }, 1819 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1820 "Expected isInCall to be " + isIncall 1821 ); 1822 } 1823 assertIsInManagedCall(boolean isIncall)1824 void assertIsInManagedCall(boolean isIncall) { 1825 waitUntilConditionIsTrueOrTimeout( 1826 new Condition() { 1827 @Override 1828 public Object expected() { 1829 return isIncall; 1830 } 1831 1832 @Override 1833 public Object actual() { 1834 return mTelecomManager.isInManagedCall(); 1835 } 1836 }, 1837 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1838 "Expected isInManagedCall to be " + isIncall 1839 ); 1840 } 1841 1842 /** 1843 * Asserts that a call's properties are as expected. 1844 * 1845 * @param call The call. 1846 * @param properties The expected properties. 1847 */ assertCallProperties(final Call call, final int properties)1848 public void assertCallProperties(final Call call, final int properties) { 1849 waitUntilConditionIsTrueOrTimeout( 1850 new Condition() { 1851 @Override 1852 public Object expected() { 1853 return true; 1854 } 1855 1856 @Override 1857 public Object actual() { 1858 return call.getDetails().hasProperty(properties); 1859 } 1860 }, 1861 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1862 "Call should have properties " + properties 1863 ); 1864 } 1865 1866 /** 1867 * Asserts that a call does not have any of the specified call capability bits specified. 1868 * 1869 * @param call The call. 1870 * @param capabilities The capability or capabilities which are not expected. 1871 */ assertDoesNotHaveCallCapabilities(final Call call, final int capabilities)1872 public void assertDoesNotHaveCallCapabilities(final Call call, final int capabilities) { 1873 waitUntilConditionIsTrueOrTimeout( 1874 new Condition() { 1875 @Override 1876 public Object expected() { 1877 return true; 1878 } 1879 1880 @Override 1881 public Object actual() { 1882 int callCapabilities = call.getDetails().getCallCapabilities(); 1883 return !Call.Details.hasProperty(callCapabilities, capabilities); 1884 } 1885 }, 1886 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1887 "Call should not have capabilities " + capabilities 1888 ); 1889 } 1890 1891 /** 1892 * Asserts that a call does not have any of the specified call property bits specified. 1893 * 1894 * @param call The call. 1895 * @param properties The property or properties which are not expected. 1896 */ assertDoesNotHaveCallProperties(final Call call, final int properties)1897 public void assertDoesNotHaveCallProperties(final Call call, final int properties) { 1898 waitUntilConditionIsTrueOrTimeout( 1899 new Condition() { 1900 @Override 1901 public Object expected() { 1902 return true; 1903 } 1904 1905 @Override 1906 public Object actual() { 1907 return !call.getDetails().hasProperty(properties); 1908 } 1909 }, 1910 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1911 "Call should not have properties " + properties 1912 ); 1913 } 1914 1915 /** 1916 * Asserts that the audio manager reports the specified audio mode. 1917 * 1918 * @param audioManager The audio manager to check. 1919 * @param expectedMode The expected audio mode. 1920 */ assertAudioMode(final AudioManager audioManager, final int expectedMode)1921 public void assertAudioMode(final AudioManager audioManager, final int expectedMode) { 1922 waitUntilConditionIsTrueOrTimeout( 1923 new Condition() { 1924 @Override 1925 public Object expected() { 1926 return true; 1927 } 1928 1929 @Override 1930 public Object actual() { 1931 return audioManager.getMode() == expectedMode; 1932 } 1933 }, 1934 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1935 "Audio mode was expected to be " + expectedMode 1936 ); 1937 } 1938 1939 /** 1940 * Asserts that a call's capabilities are as expected. 1941 * 1942 * @param call The call. 1943 * @param capabilities The expected capabiltiies. 1944 */ assertCallCapabilities(final Call call, final int capabilities)1945 public void assertCallCapabilities(final Call call, final int capabilities) { 1946 waitUntilConditionIsTrueOrTimeout( 1947 new Condition() { 1948 @Override 1949 public Object expected() { 1950 return true; 1951 } 1952 1953 @Override 1954 public Object actual() { 1955 return (call.getDetails().getCallCapabilities() & capabilities) == 1956 capabilities; 1957 } 1958 }, 1959 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1960 "Call should have properties " + capabilities 1961 ); 1962 } 1963 getInCallService()1964 MockInCallService getInCallService() { 1965 return (mInCallCallbacks == null) ? null : mInCallCallbacks.getService(); 1966 } 1967 1968 /** 1969 * Asserts that the {@link UiModeManager} mode matches the specified mode. 1970 * 1971 * @param uiMode The expected ui mode. 1972 */ assertUiMode(final int uiMode)1973 public void assertUiMode(final int uiMode) { 1974 waitUntilConditionIsTrueOrTimeout( 1975 new Condition() { 1976 @Override 1977 public Object expected() { 1978 return uiMode; 1979 } 1980 1981 @Override 1982 public Object actual() { 1983 return mUiModeManager.getCurrentModeType(); 1984 } 1985 }, 1986 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1987 "Expected ui mode " + uiMode 1988 ); 1989 } 1990 waitUntilConditionIsTrueOrTimeout(Condition condition, long timeout, String description)1991 void waitUntilConditionIsTrueOrTimeout(Condition condition, long timeout, 1992 String description) { 1993 final long start = System.currentTimeMillis(); 1994 while (!Objects.equals(condition.expected(), condition.actual()) 1995 && System.currentTimeMillis() - start < timeout) { 1996 sleep(50); 1997 } 1998 assertEquals(description, condition.expected(), condition.actual()); 1999 } 2000 2001 /** 2002 * Performs some work, and waits for the condition to be met. If the condition is not met in 2003 * each step of the loop, the work is performed again. 2004 * 2005 * @param work The work to perform. 2006 * @param condition The condition. 2007 * @param timeout The timeout. 2008 * @param description Description of the work being performed. 2009 */ doWorkAndWaitUntilConditionIsTrueOrTimeout(Work work, Condition condition, long timeout, String description)2010 void doWorkAndWaitUntilConditionIsTrueOrTimeout(Work work, Condition condition, long timeout, 2011 String description) { 2012 final long start = System.currentTimeMillis(); 2013 work.doWork(); 2014 while (!condition.expected().equals(condition.actual()) 2015 && System.currentTimeMillis() - start < timeout) { 2016 sleep(50); 2017 work.doWork(); 2018 } 2019 assertEquals(description, condition.expected(), condition.actual()); 2020 } 2021 2022 protected interface Condition { expected()2023 Object expected(); actual()2024 Object actual(); 2025 } 2026 2027 protected interface Work { doWork()2028 void doWork(); 2029 } 2030 areBundlesEqual(Bundle extras, Bundle newExtras)2031 public static boolean areBundlesEqual(Bundle extras, Bundle newExtras) { 2032 if (extras == null || newExtras == null) { 2033 return extras == newExtras; 2034 } 2035 2036 if (extras.size() != newExtras.size()) { 2037 return false; 2038 } 2039 2040 for (String key : extras.keySet()) { 2041 if (key != null) { 2042 final Object value = extras.get(key); 2043 final Object newValue = newExtras.get(key); 2044 if (!Objects.equals(value, newValue)) { 2045 return false; 2046 } 2047 } 2048 } 2049 return true; 2050 } 2051 } 2052