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.content.Context.RECEIVER_EXPORTED; 20 import static android.telecom.cts.TestUtils.PACKAGE; 21 import static android.telecom.cts.TestUtils.TAG; 22 import static android.telecom.cts.TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS; 23 24 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; 25 26 import static org.hamcrest.CoreMatchers.equalTo; 27 import static org.hamcrest.CoreMatchers.not; 28 import static org.junit.Assert.assertThat; 29 30 import android.app.AppOpsManager; 31 import android.app.UiAutomation; 32 import android.app.UiModeManager; 33 import android.content.BroadcastReceiver; 34 import android.content.Context; 35 import android.content.Intent; 36 import android.content.IntentFilter; 37 import android.content.pm.PackageManager; 38 import android.content.res.Configuration; 39 import android.database.ContentObserver; 40 import android.database.Cursor; 41 import android.location.LocationManager; 42 import android.media.AudioManager; 43 import android.net.Uri; 44 import android.os.Bundle; 45 import android.os.Handler; 46 import android.os.HandlerThread; 47 import android.os.IBinder; 48 import android.os.Looper; 49 import android.os.Process; 50 import android.os.RemoteException; 51 import android.os.UserHandle; 52 import android.provider.CallLog; 53 import android.telecom.Call; 54 import android.telecom.CallAudioState; 55 import android.telecom.CallEndpoint; 56 import android.telecom.Conference; 57 import android.telecom.Connection; 58 import android.telecom.ConnectionRequest; 59 import android.telecom.InCallService; 60 import android.telecom.PhoneAccount; 61 import android.telecom.PhoneAccountHandle; 62 import android.telecom.TelecomManager; 63 import android.telecom.VideoProfile; 64 import android.telecom.cts.MockInCallService.InCallServiceCallbacks; 65 import android.telecom.cts.carmodetestapp.ICtsCarModeInCallServiceControl; 66 import android.telephony.CarrierConfigManager; 67 import android.telephony.TelephonyCallback; 68 import android.telephony.TelephonyManager; 69 import android.telephony.emergency.EmergencyNumber; 70 import android.test.InstrumentationTestCase; 71 import android.text.TextUtils; 72 import android.util.Log; 73 import android.util.Pair; 74 75 import androidx.test.InstrumentationRegistry; 76 77 import com.android.compatibility.common.util.ShellIdentityUtils; 78 79 import java.util.ArrayList; 80 import java.util.List; 81 import java.util.Map; 82 import java.util.Objects; 83 import java.util.Random; 84 import java.util.concurrent.CountDownLatch; 85 import java.util.concurrent.LinkedBlockingQueue; 86 import java.util.concurrent.Semaphore; 87 import java.util.concurrent.TimeUnit; 88 import java.util.concurrent.TimeoutException; 89 import java.util.stream.Collectors; 90 91 /** 92 * Base class for Telecom CTS tests that require a {@link CtsConnectionService} and 93 * {@link MockInCallService} to verify Telecom functionality. 94 */ 95 public class BaseTelecomTestWithMockServices extends InstrumentationTestCase { 96 97 public static final int FLAG_REGISTER = 0x1; 98 public static final int FLAG_ENABLE = 0x2; 99 public static final int FLAG_SET_DEFAULT = 0x4; 100 public static final int FLAG_PHONE_ACCOUNT_HANDLES_CONTENT_SCHEME = 0x8; 101 102 // Don't accidently use emergency number. 103 private static int sCounter = 5553638; 104 105 //Smaller timeout for checking outgoing connection 106 //Since this called after placeAndVerifyCall 107 private static final long WAIT_FOR_OUTGOING_CONNECTION_TIMEOUT_MS = 2000; 108 109 public static final String TEST_EMERGENCY_NUMBER = "5553637"; 110 public static final Uri TEST_EMERGENCY_URI = Uri.fromParts("tel", TEST_EMERGENCY_NUMBER, null); 111 public static final String PKG_NAME = "android.telecom.cts"; 112 public static final String PERMISSION_PROCESS_OUTGOING_CALLS = 113 "android.permission.PROCESS_OUTGOING_CALLS"; 114 public static final String PERMISSION_PACKAGE_USAGE_STATS = 115 "android.permission.PACKAGE_USAGE_STATS"; 116 117 public static final String OTT_TEST_EVENT_NAME = "test.oem.event_name"; 118 119 Context mContext; 120 TelecomManager mTelecomManager; 121 TelephonyManager mTelephonyManager; 122 CarrierConfigManager mCarrierConfigManager; 123 LocationManager mLocationManager; 124 UiModeManager mUiModeManager; 125 126 TestUtils.InvokeCounter mOnBringToForegroundCounter; 127 TestUtils.InvokeCounter mOnCallAudioStateChangedCounter; 128 TestUtils.InvokeCounter mOnPostDialWaitCounter; 129 TestUtils.InvokeCounter mOnCannedTextResponsesLoadedCounter; 130 TestUtils.InvokeCounter mOnSilenceRingerCounter; 131 TestUtils.InvokeCounter mOnConnectionEventCounter; 132 TestUtils.InvokeCounter mOnExtrasChangedCounter; 133 TestUtils.InvokeCounter mOnPropertiesChangedCounter; 134 TestUtils.InvokeCounter mOnRttModeChangedCounter; 135 TestUtils.InvokeCounter mOnRttStatusChangedCounter; 136 TestUtils.InvokeCounter mOnRttInitiationFailedCounter; 137 TestUtils.InvokeCounter mOnRttRequestCounter; 138 TestUtils.InvokeCounter mOnHandoverCompleteCounter; 139 TestUtils.InvokeCounter mOnHandoverFailedCounter; 140 TestUtils.InvokeCounter mOnPhoneAccountChangedCounter; 141 TestUtils.InvokeCounter mOnCallEndpointChangedCounter; 142 TestUtils.InvokeCounter mOnAvailableEndpointsChangedCounter; 143 TestUtils.InvokeCounter mOnMuteStateChangedCounter; 144 Bundle mPreviousExtras; 145 int mPreviousProperties = -1; 146 PhoneAccountHandle mPreviousPhoneAccountHandle = null; 147 148 InCallServiceCallbacks mInCallCallbacks; 149 String mPreviousDefaultDialer = null; 150 PhoneAccountHandle mPreviousDefaultOutgoingAccount = null; 151 boolean mShouldRestoreDefaultOutgoingAccount = false; 152 MockConnectionService connectionService = null; 153 boolean mIsEmergencyCallingSetup = false; 154 155 HandlerThread mTelephonyCallbackThread; 156 Handler mTelephonyCallbackHandler; 157 TestTelephonyCallback mTelephonyCallback; 158 TestCallStateListener mTestCallStateListener; 159 Handler mHandler; 160 161 /** 162 * Uses the control interface to disable car mode. 163 * @param expectedUiMode 164 */ disableAndVerifyCarMode(ICtsCarModeInCallServiceControl control, int expectedUiMode)165 protected void disableAndVerifyCarMode(ICtsCarModeInCallServiceControl control, 166 int expectedUiMode) { 167 if (control == null) { 168 return; 169 } 170 try { 171 control.disableCarMode(); 172 } catch (RemoteException re) { 173 fail("Bee-boop; can't control the incall service"); 174 } 175 assertUiMode(expectedUiMode); 176 } 177 disconnectAllCallsAndVerify(ICtsCarModeInCallServiceControl controlBinder)178 protected void disconnectAllCallsAndVerify(ICtsCarModeInCallServiceControl controlBinder) { 179 if (controlBinder == null) { 180 return; 181 } 182 try { 183 controlBinder.disconnectCalls(); 184 } catch (RemoteException re) { 185 fail("Bee-boop; can't control the incall service"); 186 } 187 assertCarModeCallCount(controlBinder, 0); 188 } 189 190 /** 191 * Verify the car mode ICS has an expected call count. 192 * @param expected 193 */ assertCarModeCallCount(ICtsCarModeInCallServiceControl control, int expected)194 protected void assertCarModeCallCount(ICtsCarModeInCallServiceControl control, int expected) { 195 waitUntilConditionIsTrueOrTimeout( 196 new Condition() { 197 @Override 198 public Object expected() { 199 return expected; 200 } 201 202 @Override 203 public Object actual() { 204 int callCount = 0; 205 try { 206 callCount = control.getCallCount(); 207 } catch (RemoteException re) { 208 fail("Bee-boop; can't control the incall service"); 209 } 210 return callCount; 211 } 212 }, 213 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 214 "Expected " + expected + " calls." 215 ); 216 } 217 218 static class TestCallStateListener extends TelephonyCallback 219 implements TelephonyCallback.CallStateListener { 220 221 private CountDownLatch mCountDownLatch = new CountDownLatch(1); 222 private int mLastState = -1; 223 224 @Override onCallStateChanged(int state)225 public void onCallStateChanged(int state) { 226 Log.i(TAG, "onCallStateChanged: state=" + state); 227 mLastState = state; 228 mCountDownLatch.countDown(); 229 mCountDownLatch = new CountDownLatch(1); 230 } 231 getCountDownLatch()232 public CountDownLatch getCountDownLatch() { 233 return mCountDownLatch; 234 } 235 getLastState()236 public int getLastState() { 237 return mLastState; 238 } 239 } 240 241 static class TestTelephonyCallback extends TelephonyCallback implements 242 TelephonyCallback.CallStateListener, 243 TelephonyCallback.OutgoingEmergencyCallListener, 244 TelephonyCallback.EmergencyNumberListListener { 245 /** Semaphore released for every callback invocation. */ 246 public Semaphore mCallbackSemaphore = new Semaphore(0); 247 248 List<Integer> mCallStates = new ArrayList<>(); 249 EmergencyNumber mLastOutgoingEmergencyNumber; 250 251 LinkedBlockingQueue<Map<Integer, List<EmergencyNumber>>> mEmergencyNumberListQueue = 252 new LinkedBlockingQueue<>(); 253 254 @Override onCallStateChanged(int state)255 public void onCallStateChanged(int state) { 256 Log.i(TAG, "onCallStateChanged: state=" + state); 257 mCallStates.add(state); 258 mCallbackSemaphore.release(); 259 } 260 261 @Override onOutgoingEmergencyCall(EmergencyNumber emergencyNumber, int subscriptionId)262 public void onOutgoingEmergencyCall(EmergencyNumber emergencyNumber, int subscriptionId) { 263 Log.i(TAG, "onOutgoingEmergencyCall: emergencyNumber=" + emergencyNumber); 264 mLastOutgoingEmergencyNumber = emergencyNumber; 265 mCallbackSemaphore.release(); 266 } 267 268 @Override onEmergencyNumberListChanged( Map<Integer, List<EmergencyNumber>> emergencyNumberList)269 public void onEmergencyNumberListChanged( 270 Map<Integer, List<EmergencyNumber>> emergencyNumberList) { 271 Log.i(TAG, "onEmergencyNumberChanged, total size=" + emergencyNumberList.values() 272 .stream().mapToInt(List::size).sum()); 273 mEmergencyNumberListQueue.offer(emergencyNumberList); 274 } 275 waitForEmergencyNumberListUpdate( long timeoutMillis)276 public Map<Integer, List<EmergencyNumber>> waitForEmergencyNumberListUpdate( 277 long timeoutMillis) throws Throwable { 278 return mEmergencyNumberListQueue.poll(timeoutMillis, TimeUnit.MILLISECONDS); 279 } 280 clearEmergencyNumberQueue()281 public void clearEmergencyNumberQueue() { 282 mEmergencyNumberListQueue.clear(); 283 } 284 } 285 286 boolean mShouldTestTelecom = true; 287 boolean mWatchDevice = false; 288 289 290 @Override setUp()291 protected void setUp() throws Exception { 292 super.setUp(); 293 mContext = getInstrumentation().getContext(); 294 mHandler = new Handler(Looper.getMainLooper()); 295 mShouldTestTelecom = TestUtils.shouldTestTelecom(mContext); 296 if (!mShouldTestTelecom) { 297 return; 298 } 299 300 PackageManager packageManager = mContext.getPackageManager(); 301 mWatchDevice = packageManager != null && packageManager.hasSystemFeature( 302 PackageManager.FEATURE_WATCH); 303 304 // Assume we start in normal mode at the start of all Telecom tests; a failure to leave car 305 // mode in any of the tests would cause subsequent test failures. 306 // For Watch, UI_MODE shouldn't be normal mode. 307 mUiModeManager = mContext.getSystemService(UiModeManager.class); 308 TestUtils.executeShellCommand(getInstrumentation(), "telecom reset-car-mode"); 309 310 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) { 311 assertUiMode(Configuration.UI_MODE_TYPE_WATCH); 312 } else if (mContext.getPackageManager().hasSystemFeature( 313 PackageManager.FEATURE_AUTOMOTIVE)) { 314 assertUiMode(Configuration.UI_MODE_TYPE_CAR); 315 } else { 316 assertUiMode(Configuration.UI_MODE_TYPE_NORMAL); 317 } 318 319 AppOpsManager aom = mContext.getSystemService(AppOpsManager.class); 320 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(aom, 321 (appOpsMan) -> appOpsMan.setUidMode(AppOpsManager.OPSTR_PROCESS_OUTGOING_CALLS, 322 Process.myUid(), AppOpsManager.MODE_ALLOWED)); 323 324 mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); 325 mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); 326 mCarrierConfigManager = (CarrierConfigManager) mContext.getSystemService( 327 Context.CARRIER_CONFIG_SERVICE); 328 mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 329 mPreviousDefaultDialer = TestUtils.getDefaultDialer(getInstrumentation()); 330 TestUtils.setDefaultDialer(getInstrumentation(), PACKAGE); 331 setupCallbacks(); 332 333 // Register a call state listener. 334 mTestCallStateListener = new TestCallStateListener(); 335 CountDownLatch latch = mTestCallStateListener.getCountDownLatch(); 336 mTelephonyManager.registerTelephonyCallback(r -> r.run(), mTestCallStateListener); 337 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 338 // Without telephony, we shouldn't expect any callback to fire, but we should still try 339 // registering telephony callback to at least make sure it doesn't crash. 340 latch.await( 341 TestUtils.WAIT_FOR_PHONE_STATE_LISTENER_REGISTERED_TIMEOUT_S, TimeUnit.SECONDS); 342 } 343 // Create a new thread for the telephony callback. 344 mTelephonyCallbackThread = new HandlerThread("PhoneStateListenerThread"); 345 mTelephonyCallbackThread.start(); 346 mTelephonyCallbackHandler = new Handler(mTelephonyCallbackThread.getLooper()); 347 348 mTelephonyCallback = new TestTelephonyCallback(); 349 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager, 350 (tm) -> tm.registerTelephonyCallback( 351 mTelephonyCallbackHandler::post, 352 mTelephonyCallback)); 353 UiAutomation uiAutomation = 354 InstrumentationRegistry.getInstrumentation().getUiAutomation(); 355 uiAutomation.grantRuntimePermissionAsUser(PKG_NAME, PERMISSION_PROCESS_OUTGOING_CALLS, 356 UserHandle.CURRENT); 357 uiAutomation.grantRuntimePermissionAsUser(PKG_NAME, PERMISSION_PACKAGE_USAGE_STATS, 358 UserHandle.CURRENT); 359 } 360 361 @Override tearDown()362 protected void tearDown() throws Exception { 363 super.tearDown(); 364 if (!mShouldTestTelecom) { 365 return; 366 } 367 // This is not standard, but during teardown, if there is any sort of assertion error, it 368 // will stop teardown and bail early. If this happens, it can put the device into a bad 369 // state because the cleanup steps never fully get run. Save the "first" error that happens 370 // and re-throw it at the end of the tearDown procedure. 371 Throwable assertionError = null; 372 if (!TextUtils.isEmpty(mPreviousDefaultDialer)) { 373 TestUtils.setDefaultDialer(getInstrumentation(), mPreviousDefaultDialer); 374 } 375 unregisterTelephonyCallbacks(); 376 try { 377 cleanupCalls(); 378 if (this.connectionService != null) { 379 assertNumConnections(this.connectionService, 0); 380 } 381 } catch (Throwable t) { 382 assertionError = t; 383 } 384 tearDownConnectionService(TestUtils.TEST_PHONE_ACCOUNT_HANDLE); 385 try { 386 assertCtsConnectionServiceUnbound(); 387 } catch (Throwable t) { 388 if (assertionError == null) assertionError = t; 389 } 390 tearDownEmergencyCalling(); 391 try { 392 assertMockInCallServiceUnbound(); 393 } catch (Throwable t) { 394 // If we haven't unbound, that means there's some dirty state in Telecom that needs 395 // cleaning up. Forcibly unbind and clean up Telecom state so that we don't have a 396 // cascading failure of tests. 397 TestUtils.executeShellCommand(getInstrumentation(), "telecom cleanup-stuck-calls"); 398 if (assertionError == null) assertionError = t; 399 } 400 UiAutomation uiAutomation = 401 InstrumentationRegistry.getInstrumentation().getUiAutomation(); 402 uiAutomation.revokeRuntimePermissionAsUser(PKG_NAME, PERMISSION_PROCESS_OUTGOING_CALLS, 403 UserHandle.CURRENT); 404 // Verify that not phone accounts were left behind after the test. 405 checkForCrossTestIsolationIssues(); 406 // Rethrow the error found in tearDown if any existed. 407 if (assertionError != null) throw new AssertionError(assertionError); 408 } 409 unregisterTelephonyCallbacks()410 public void unregisterTelephonyCallbacks() { 411 if (mTestCallStateListener != null) { 412 mTelephonyManager.unregisterTelephonyCallback(mTestCallStateListener); 413 } 414 if (mTelephonyCallback != null) { 415 mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback); 416 } 417 if (mTelephonyCallbackThread != null) { 418 mTelephonyCallbackThread.quit(); 419 } 420 } 421 setupConnectionService(MockConnectionService connectionService, int flags)422 protected PhoneAccount setupConnectionService(MockConnectionService connectionService, 423 int flags) throws Exception { 424 Log.i(TAG, "Setting up mock connection service"); 425 try { 426 if (connectionService != null) { 427 this.connectionService = connectionService; 428 } else { 429 // Generate a vanilla mock connection service, if not provided. 430 this.connectionService = new MockConnectionService(); 431 } 432 CtsConnectionService.setUp(this.connectionService); 433 434 if ((flags & FLAG_REGISTER) != 0) { 435 if ((flags & FLAG_PHONE_ACCOUNT_HANDLES_CONTENT_SCHEME) != 0) { 436 mTelecomManager.registerPhoneAccount( 437 TestUtils.TEST_PHONE_ACCOUNT_THAT_HANDLES_CONTENT_SCHEME); 438 } else { 439 mTelecomManager.registerPhoneAccount(TestUtils.TEST_PHONE_ACCOUNT); 440 } 441 } 442 if ((flags & FLAG_ENABLE) != 0) { 443 TestUtils.enablePhoneAccount(getInstrumentation(), 444 TestUtils.TEST_PHONE_ACCOUNT_HANDLE); 445 // Wait till the adb commands have executed and account is enabled in Telecom 446 // database. 447 assertPhoneAccountEnabled(TestUtils.TEST_PHONE_ACCOUNT_HANDLE); 448 } 449 450 if ((flags & FLAG_SET_DEFAULT) != 0) { 451 mPreviousDefaultOutgoingAccount = 452 mTelecomManager.getUserSelectedOutgoingPhoneAccount(); 453 mShouldRestoreDefaultOutgoingAccount = true; 454 runWithShellPermissionIdentity(() -> 455 mTelecomManager.setUserSelectedOutgoingPhoneAccount( 456 TestUtils.TEST_PHONE_ACCOUNT_HANDLE)); 457 // Wait till the adb commands have executed and the default has changed. 458 assertPhoneAccountIsDefault(TestUtils.TEST_PHONE_ACCOUNT_HANDLE); 459 } 460 461 } catch (Exception e) { 462 // Clear static cts connection service state: its ok to do this if setUp itself throws. 463 CtsConnectionService.tearDown(); 464 unregisterTelephonyCallbacks(); 465 throw e; 466 } 467 return TestUtils.TEST_PHONE_ACCOUNT; 468 } 469 tearDownConnectionService(PhoneAccountHandle accountHandle)470 protected void tearDownConnectionService(PhoneAccountHandle accountHandle) { 471 Log.i(TAG, "Tearing down mock connection service"); 472 mTelecomManager.unregisterPhoneAccount(accountHandle); 473 CtsConnectionService.tearDown(); 474 if (mShouldRestoreDefaultOutgoingAccount) { 475 runWithShellPermissionIdentity(() -> mTelecomManager 476 .setUserSelectedOutgoingPhoneAccount(mPreviousDefaultOutgoingAccount)); 477 } 478 this.connectionService = null; 479 mPreviousDefaultOutgoingAccount = null; 480 mShouldRestoreDefaultOutgoingAccount = false; 481 } 482 setupForEmergencyCalling(String testNumber)483 protected void setupForEmergencyCalling(String testNumber) throws Exception { 484 TestUtils.setSystemDialerOverride(getInstrumentation()); 485 TestUtils.addTestEmergencyNumber(getInstrumentation(), testNumber); 486 TestUtils.setTestEmergencyPhoneAccountPackageFilter(getInstrumentation(), mContext); 487 // Emergency calls require special capabilities. 488 TestUtils.registerEmergencyPhoneAccount(getInstrumentation(), 489 TestUtils.TEST_EMERGENCY_PHONE_ACCOUNT_HANDLE, 490 TestUtils.ACCOUNT_LABEL + "E", "tel:555-EMER"); 491 mIsEmergencyCallingSetup = true; 492 } 493 tearDownEmergencyCalling()494 protected void tearDownEmergencyCalling() throws Exception { 495 if (!mIsEmergencyCallingSetup) return; 496 497 TestUtils.clearSystemDialerOverride(getInstrumentation()); 498 TestUtils.clearTestEmergencyNumbers(getInstrumentation()); 499 TestUtils.clearTestEmergencyPhoneAccountPackageFilter(getInstrumentation()); 500 mTelecomManager.unregisterPhoneAccount(TestUtils.TEST_EMERGENCY_PHONE_ACCOUNT_HANDLE); 501 } 502 startCallTo(Uri address, PhoneAccountHandle accountHandle)503 protected void startCallTo(Uri address, PhoneAccountHandle accountHandle) { 504 final Intent intent = new Intent(Intent.ACTION_CALL, address); 505 if (accountHandle != null) { 506 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 507 } 508 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 509 mContext.startActivity(intent); 510 } 511 sleep(long ms)512 void sleep(long ms) { 513 try { 514 Thread.sleep(ms); 515 } catch (InterruptedException e) { 516 } 517 } 518 setupCallbacks()519 private void setupCallbacks() { 520 mInCallCallbacks = 521 new InCallServiceCallbacks() { 522 @Override 523 public void onCallAdded(Call call, int numCalls) { 524 Log.i(TAG, "onCallAdded, Call: " + call + ", Num Calls: " + numCalls); 525 this.lock.release(); 526 mPreviousPhoneAccountHandle = call.getDetails().getAccountHandle(); 527 } 528 529 @Override 530 public void onCallRemoved(Call call, int numCalls) { 531 Log.i(TAG, "onCallRemoved, Call: " + call + ", Num Calls: " + numCalls); 532 } 533 534 @Override 535 public void onParentChanged(Call call, Call parent) { 536 Log.i(TAG, "onParentChanged, Call: " + call + ", Parent: " + parent); 537 this.lock.release(); 538 } 539 540 @Override 541 public void onChildrenChanged(Call call, List<Call> children) { 542 Log.i(TAG, "onChildrenChanged, Call: " + call + "Children: " + children); 543 this.lock.release(); 544 } 545 546 @Override 547 public void onConferenceableCallsChanged( 548 Call call, List<Call> conferenceableCalls) { 549 Log.i( 550 TAG, 551 "onConferenceableCallsChanged, Call: " 552 + call 553 + ", Conferenceables: " 554 + conferenceableCalls); 555 } 556 557 @Override 558 public void onDetailsChanged(Call call, Call.Details details) { 559 Log.i(TAG, "onDetailsChanged, Call: " + call + ", Details: " + details); 560 if (!areBundlesEqual(mPreviousExtras, details.getExtras())) { 561 mOnExtrasChangedCounter.invoke(call, details); 562 } 563 mPreviousExtras = details.getExtras(); 564 565 if (mPreviousProperties != details.getCallProperties()) { 566 mOnPropertiesChangedCounter.invoke(call, details); 567 Log.i( 568 TAG, 569 "onDetailsChanged; properties changed from " 570 + Call.Details.propertiesToString(mPreviousProperties) 571 + " to " 572 + Call.Details.propertiesToString( 573 details.getCallProperties())); 574 } 575 mPreviousProperties = details.getCallProperties(); 576 577 if (details.getAccountHandle() != null 578 && !details.getAccountHandle() 579 .equals(mPreviousPhoneAccountHandle)) { 580 mOnPhoneAccountChangedCounter.invoke(call, details.getAccountHandle()); 581 } 582 mPreviousPhoneAccountHandle = details.getAccountHandle(); 583 } 584 585 @Override 586 public void onCallDestroyed(Call call) { 587 Log.i(TAG, "onCallDestroyed, Call: " + call); 588 } 589 590 @Override 591 public void onCallStateChanged(Call call, int newState) { 592 Log.i( 593 TAG, 594 "onCallStateChanged, Call: " + call + ", New State: " + newState); 595 } 596 597 @Override 598 public void onBringToForeground(boolean showDialpad) { 599 mOnBringToForegroundCounter.invoke(showDialpad); 600 } 601 602 @Override 603 public void onCallAudioStateChanged(CallAudioState audioState) { 604 Log.i(TAG, "onCallAudioStateChanged, audioState: " + audioState); 605 mOnCallAudioStateChangedCounter.invoke(audioState); 606 } 607 608 @Override 609 public void onPostDialWait(Call call, String remainingPostDialSequence) { 610 mOnPostDialWaitCounter.invoke(call, remainingPostDialSequence); 611 } 612 613 @Override 614 public void onCannedTextResponsesLoaded( 615 Call call, List<String> cannedTextResponses) { 616 mOnCannedTextResponsesLoadedCounter.invoke(call, cannedTextResponses); 617 } 618 619 @Override 620 public void onConnectionEvent(Call call, String event, Bundle extras) { 621 mOnConnectionEventCounter.invoke(call, event, extras); 622 } 623 624 @Override 625 public void onSilenceRinger() { 626 Log.i(TAG, "onSilenceRinger"); 627 mOnSilenceRingerCounter.invoke(); 628 } 629 630 @Override 631 public void onRttModeChanged(Call call, int mode) { 632 mOnRttModeChangedCounter.invoke(call, mode); 633 } 634 635 @Override 636 public void onRttStatusChanged( 637 Call call, boolean enabled, Call.RttCall rttCall) { 638 mOnRttStatusChangedCounter.invoke(call, enabled, rttCall); 639 } 640 641 @Override 642 public void onRttRequest(Call call, int id) { 643 mOnRttRequestCounter.invoke(call, id); 644 } 645 646 @Override 647 public void onRttInitiationFailure(Call call, int reason) { 648 mOnRttInitiationFailedCounter.invoke(call, reason); 649 } 650 651 @Override 652 public void onHandoverComplete(Call call) { 653 mOnHandoverCompleteCounter.invoke(call); 654 } 655 656 @Override 657 public void onHandoverFailed(Call call, int reason) { 658 mOnHandoverFailedCounter.invoke(call, reason); 659 } 660 661 @Override 662 public void onCallEndpointChanged(CallEndpoint callEndpoint) { 663 Log.i(TAG, "onCallEndpointChanged, callEndpoint: " + callEndpoint); 664 mOnCallEndpointChangedCounter.invoke(callEndpoint); 665 } 666 667 @Override 668 public void onAvailableCallEndpointsChanged( 669 List<CallEndpoint> availableEndpoints) { 670 Log.i(TAG, "onAvailableCallEndpointsChanged"); 671 mOnAvailableEndpointsChangedCounter.invoke(availableEndpoints); 672 } 673 674 @Override 675 public void onMuteStateChanged(boolean isMuted) { 676 Log.i(TAG, "onMuteStateChanged, isMuted: " + isMuted); 677 mOnMuteStateChangedCounter.invoke(isMuted); 678 } 679 }; 680 681 MockInCallService.setCallbacks(mInCallCallbacks); 682 683 // TODO: If more InvokeCounters are added in the future, consider consolidating them into a 684 // single Collection. 685 mOnBringToForegroundCounter = new TestUtils.InvokeCounter("OnBringToForeground"); 686 mOnCallAudioStateChangedCounter = new TestUtils.InvokeCounter("OnCallAudioStateChanged"); 687 mOnPostDialWaitCounter = new TestUtils.InvokeCounter("OnPostDialWait"); 688 mOnCannedTextResponsesLoadedCounter = 689 new TestUtils.InvokeCounter("OnCannedTextResponsesLoaded"); 690 mOnSilenceRingerCounter = new TestUtils.InvokeCounter("OnSilenceRinger"); 691 mOnConnectionEventCounter = new TestUtils.InvokeCounter("OnConnectionEvent"); 692 mOnExtrasChangedCounter = new TestUtils.InvokeCounter("OnDetailsChangedCounter"); 693 mOnPropertiesChangedCounter = new TestUtils.InvokeCounter("OnPropertiesChangedCounter"); 694 mOnRttModeChangedCounter = new TestUtils.InvokeCounter("mOnRttModeChangedCounter"); 695 mOnRttStatusChangedCounter = new TestUtils.InvokeCounter("mOnRttStatusChangedCounter"); 696 mOnRttInitiationFailedCounter = 697 new TestUtils.InvokeCounter("mOnRttInitiationFailedCounter"); 698 mOnRttRequestCounter = new TestUtils.InvokeCounter("mOnRttRequestCounter"); 699 mOnHandoverCompleteCounter = new TestUtils.InvokeCounter("mOnHandoverCompleteCounter"); 700 mOnHandoverFailedCounter = new TestUtils.InvokeCounter("mOnHandoverFailedCounter"); 701 mOnPhoneAccountChangedCounter = new TestUtils.InvokeCounter( 702 "mOnPhoneAccountChangedCounter"); 703 mOnCallEndpointChangedCounter = new TestUtils.InvokeCounter("IcsOnCallEndpointChanged"); 704 mOnAvailableEndpointsChangedCounter = new TestUtils.InvokeCounter( 705 "OnAvailableEndpointsChanged"); 706 mOnMuteStateChangedCounter = new TestUtils.InvokeCounter("OnMuteStateChanged"); 707 } 708 registerAndEnablePhoneAccount(PhoneAccount phoneAccount)709 void registerAndEnablePhoneAccount(PhoneAccount phoneAccount) throws Exception { 710 mTelecomManager.registerPhoneAccount(phoneAccount); 711 TestUtils.enablePhoneAccount(getInstrumentation(), phoneAccount.getAccountHandle()); 712 // Wait till the adb commands have executed and account is enabled in Telecom database. 713 assertPhoneAccountEnabled(phoneAccount.getAccountHandle()); 714 } 715 registerAccountsAndVerify(List<PhoneAccount> accountsToRegister)716 void registerAccountsAndVerify(List<PhoneAccount> accountsToRegister) throws Exception { 717 for (PhoneAccount account : accountsToRegister) { 718 if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { 719 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelecomManager, 720 tm -> tm.registerPhoneAccount(account), 721 "android.permission.REGISTER_SIM_SUBSCRIPTION"); 722 } else { 723 registerAndEnablePhoneAccount(account); 724 } 725 verifyAccountRegistration(account.getAccountHandle(), account); 726 } 727 } 728 unregisterAccountsAndVerify(List<PhoneAccount> accountsToRegister)729 void unregisterAccountsAndVerify(List<PhoneAccount> accountsToRegister) { 730 for (PhoneAccount account : accountsToRegister) { 731 mTelecomManager.unregisterPhoneAccount(account.getAccountHandle()); 732 assertNull(mTelecomManager.getPhoneAccount(account.getAccountHandle())); 733 } 734 } 735 736 /** 737 * helper method to set the default outgoing account handle and verify it was successfully set 738 * 739 * @param handle that will be the new default. 740 */ setDefaultOutgoingPhoneAccountAndVerify(PhoneAccountHandle handle)741 void setDefaultOutgoingPhoneAccountAndVerify(PhoneAccountHandle handle) 742 throws Exception { 743 // set the default outgoing as a self-managed account 744 runWithShellPermissionIdentity(() -> 745 mTelecomManager.setUserSelectedOutgoingPhoneAccount(handle)); 746 747 // assert the self-managed is returned 748 assertEquals(handle, mTelecomManager.getUserSelectedOutgoingPhoneAccount()); 749 } 750 verifyAccountRegistration(PhoneAccountHandle handle, PhoneAccount phoneAccount)751 void verifyAccountRegistration(PhoneAccountHandle handle, PhoneAccount phoneAccount) { 752 // The phone account is registered in the setup method. 753 assertPhoneAccountRegistered(handle); 754 assertPhoneAccountEnabled(handle); 755 PhoneAccount registeredAccount = mTelecomManager.getPhoneAccount(handle); 756 757 // It should exist and be the same as the previously registered one. 758 assertNotNull(registeredAccount); 759 760 // We cannot just check for equality of the PhoneAccount since the one we registered is not 761 // enabled, and the one we get back after registration is. 762 assertPhoneAccountEquals(phoneAccount, registeredAccount); 763 764 // An important assumption is that self-managed PhoneAccounts are automatically 765 // enabled by default. 766 assertTrue("Self-managed PhoneAccounts must be enabled by default.", 767 registeredAccount.isEnabled()); 768 } 769 addAndVerifyNewFailedIncomingCall(Uri incomingHandle, Bundle extras)770 void addAndVerifyNewFailedIncomingCall(Uri incomingHandle, Bundle extras) { 771 assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); 772 int currentCallCount = 0; 773 if (mInCallCallbacks.getService() != null) { 774 currentCallCount = mInCallCallbacks.getService().getCallCount(); 775 } 776 777 if (extras == null) { 778 extras = new Bundle(); 779 } 780 extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, incomingHandle); 781 mTelecomManager.addNewIncomingCall(TestUtils.TEST_PHONE_ACCOUNT_HANDLE, extras); 782 783 if (!connectionService.waitForEvent( 784 MockConnectionService.EVENT_CONNECTION_SERVICE_CREATE_CONNECTION_FAILED)) { 785 fail("Incoming Connection failure indication did not get called."); 786 } 787 788 assertEquals("ConnectionService did not receive failed connection", 789 1, connectionService.failedConnections.size()); 790 791 assertEquals("Address is not correct for failed connection", 792 connectionService.failedConnections.get(0).getAddress(), incomingHandle); 793 794 assertEquals("InCallService should contain the same number of calls.", 795 currentCallCount, 796 mInCallCallbacks.getService().getCallCount()); 797 } 798 799 /** 800 * Puts Telecom in a state where there is an incoming call provided by the 801 * {@link CtsConnectionService} which can be tested. 802 */ addAndVerifyNewIncomingCall(Uri incomingHandle, Bundle extras)803 void addAndVerifyNewIncomingCall(Uri incomingHandle, Bundle extras) { 804 int currentCallCount = addNewIncomingCall(incomingHandle, extras); 805 verifyNewIncomingCall(currentCallCount); 806 } 807 addNewIncomingCall(Uri incomingHandle, Bundle extras)808 int addNewIncomingCall(Uri incomingHandle, Bundle extras) { 809 assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); 810 int currentCallCount = 0; 811 if (mInCallCallbacks.getService() != null) { 812 currentCallCount = mInCallCallbacks.getService().getCallCount(); 813 } 814 815 if (extras == null) { 816 extras = new Bundle(); 817 } 818 extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, incomingHandle); 819 mTelecomManager.addNewIncomingCall(TestUtils.TEST_PHONE_ACCOUNT_HANDLE, extras); 820 821 return currentCallCount; 822 } 823 verifyNewIncomingCall(int currentCallCount)824 void verifyNewIncomingCall(int currentCallCount) { 825 if (mInCallCallbacks.getService() != null 826 && currentCallCount + 1 == mInCallCallbacks.getService().getCallCount()) { 827 // Handle the case where the InCallService has already added a call before tryAcquire 828 // was called. 829 return; 830 } 831 try { 832 if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S, 833 TimeUnit.SECONDS)) { 834 fail("No call added to InCallService."); 835 } 836 } catch (InterruptedException e) { 837 Log.i(TAG, "Test interrupted!"); 838 } 839 840 assertEquals("InCallService should contain 1 more call after adding a call.", 841 currentCallCount + 1, 842 mInCallCallbacks.getService().getCallCount()); 843 } 844 845 /** 846 * Puts Telecom in a state where there is an active call provided by the 847 * {@link CtsConnectionService} which can be tested. 848 */ placeAndVerifyCall()849 void placeAndVerifyCall() { 850 placeAndVerifyCall(null); 851 } 852 placeAndVerifyCallByRedirection(boolean wasCancelled)853 void placeAndVerifyCallByRedirection(boolean wasCancelled) { 854 placeAndVerifyCallByRedirection(null, wasCancelled); 855 } 856 857 /** 858 * Puts Telecom in a state where there is an active call provided by the 859 * {@link CtsConnectionService} which can be tested. 860 */ placeAndVerifyCallByRedirection(Bundle extras, boolean wasCancelled)861 void placeAndVerifyCallByRedirection(Bundle extras, boolean wasCancelled) { 862 int currentCallCount = (getInCallService() == null) ? 0 : getInCallService().getCallCount(); 863 int currentConnections = getNumberOfConnections(); 864 // We expect a new connection if it wasn't cancelled. 865 if (!wasCancelled) { 866 currentConnections++; 867 currentCallCount++; 868 } 869 placeAndVerifyCall(extras, VideoProfile.STATE_AUDIO_ONLY, currentCallCount); 870 // The connectionService.lock is released in 871 // MockConnectionService#onCreateOutgoingConnection, however the connection will not 872 // actually be added to the list of connections in the ConnectionService until shortly 873 // afterwards. So there is still a potential for the lock to be released before it would 874 // be seen by calls to ConnectionService#getAllConnections(). 875 // We will wait here until the list of connections includes one more connection to ensure 876 // that placing the call has fully completed. 877 assertCSConnections(currentConnections); 878 879 // Ensure the new outgoing call broadcast fired for the outgoing call. 880 assertOutgoingCallBroadcastReceived(true); 881 882 // CTS test does not have read call log permission so should not get the phone number. 883 assertNull(NewOutgoingCallBroadcastReceiver.getReceivedNumber()); 884 } 885 886 /** 887 * Puts Telecom in a state where there is an active call provided by the 888 * {@link CtsConnectionService} which can be tested. 889 * 890 * @param videoState the video state of the call. 891 */ placeAndVerifyCall(int videoState)892 void placeAndVerifyCall(int videoState) { 893 placeAndVerifyCall(null, videoState); 894 } 895 896 /** 897 * Puts Telecom in a state where there is an active call provided by the 898 * {@link CtsConnectionService} which can be tested. 899 */ placeAndVerifyCall(Bundle extras)900 void placeAndVerifyCall(Bundle extras) { 901 placeAndVerifyCall(extras, VideoProfile.STATE_AUDIO_ONLY); 902 } 903 904 /** 905 * Puts Telecom in a state where there is an active call provided by the 906 * {@link CtsConnectionService} which can be tested. 907 */ placeAndVerifyCall(Bundle extras, int videoState)908 void placeAndVerifyCall(Bundle extras, int videoState) { 909 int currentCallCount = (getInCallService() == null) ? 0 : getInCallService().getCallCount(); 910 // We expect placing the call adds a new call/connection. 911 int expectedConnections = getNumberOfConnections() + 1; 912 placeAndVerifyCall(extras, videoState, currentCallCount + 1); 913 // The connectionService.lock is released in 914 // MockConnectionService#onCreateOutgoingConnection, however the connection will not 915 // actually be added to the list of connections in the ConnectionService until shortly 916 // afterwards. So there is still a potential for the lock to be released before it would 917 // be seen by calls to ConnectionService#getAllConnections(). 918 // We will wait here until the list of connections includes one more connection to ensure 919 // that placing the call has fully completed. 920 assertCSConnections(expectedConnections); 921 assertOutgoingCallBroadcastReceived(true); 922 923 // CTS test does not have read call log permission so should not get the phone number. 924 assertNull(NewOutgoingCallBroadcastReceiver.getReceivedNumber()); 925 } 926 927 /** 928 * Verifies that a call was not placed 929 */ placeAndVerifyNoCall(Bundle extras)930 void placeAndVerifyNoCall(Bundle extras) { 931 assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); 932 placeNewCallWithPhoneAccount(extras, 0); 933 934 try { 935 if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S, 936 TimeUnit.SECONDS)) { 937 } 938 } catch (InterruptedException e) { 939 Log.i(TAG, "Test interrupted!"); 940 } 941 942 // Make sure any procedures to disconnect existing calls (makeRoomForOutgoingCall) 943 // complete successfully 944 TestUtils.waitOnLocalMainLooper(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 945 TestUtils.waitOnAllHandlers(getInstrumentation()); 946 947 assertNull("Service should be null since call should not have been placed", 948 mInCallCallbacks.getService()); 949 } 950 /** 951 * Puts Telecom in a state where there is an active call provided by the 952 * {@link CtsConnectionService} which can be tested. 953 */ placeAndVerifyCall(Bundle extras, int videoState, int expectedCallCount)954 void placeAndVerifyCall(Bundle extras, int videoState, int expectedCallCount) { 955 assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); 956 placeNewCallWithPhoneAccount(extras, videoState); 957 958 try { 959 if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S, 960 TimeUnit.SECONDS)) { 961 fail("No call added to InCallService."); 962 } 963 } catch (InterruptedException e) { 964 Log.i(TAG, "Test interrupted!"); 965 } 966 967 // Make sure any procedures to disconnect existing calls (makeRoomForOutgoingCall) 968 // complete successfully 969 TestUtils.waitOnLocalMainLooper(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 970 TestUtils.waitOnAllHandlers(getInstrumentation()); 971 972 assertEquals("InCallService should match the expected count.", expectedCallCount, 973 mInCallCallbacks.getService().getCallCount()); 974 } 975 976 /** 977 * Place an emergency call and verify that it has been setup properly. 978 * 979 * @param supportsHold If telecom supports holding emergency calls, this will expect two 980 * calls. If telecom does not support holding emergency calls, this will expect only the 981 * emergency call to be active. 982 * @return The emergency connection 983 */ placeAndVerifyEmergencyCall(boolean supportsHold)984 public Connection placeAndVerifyEmergencyCall(boolean supportsHold) { 985 Bundle extras = new Bundle(); 986 extras.putParcelable(TestUtils.EXTRA_PHONE_NUMBER, TEST_EMERGENCY_URI); 987 // We want to request the active connections vs number of connections because in some cases, 988 // we wait to destroy the underlying connection to prevent race conditions. This will result 989 // in Connections in the DISCONNECTED state. 990 int currentConnectionCount = supportsHold ? 991 getNumberOfActiveConnections() + 1 : getNumberOfActiveConnections(); 992 int currentCallCount = (getInCallService() == null) ? 0 : getInCallService().getCallCount(); 993 currentCallCount = supportsHold ? currentCallCount + 1 : currentCallCount; 994 // The device only supports a max of two calls active at any one time 995 currentCallCount = Math.min(currentCallCount, 2); 996 997 placeAndVerifyCall(extras, VideoProfile.STATE_AUDIO_ONLY, currentCallCount); 998 // The connectionService.lock is released in 999 // MockConnectionService#onCreateOutgoingConnection, however the connection will not 1000 // actually be added to the list of connections in the ConnectionService until shortly 1001 // afterwards. So there is still a potential for the lock to be released before it would 1002 // be seen by calls to ConnectionService#getAllConnections(). 1003 // We will wait here until the list of connections includes one more connection to ensure 1004 // that placing the call has fully completed. 1005 assertActiveCSConnections(currentConnectionCount); 1006 1007 assertOutgoingCallBroadcastReceived(true); 1008 Connection connection = verifyConnectionForOutgoingCall(TEST_EMERGENCY_URI); 1009 TestUtils.waitOnAllHandlers(getInstrumentation()); 1010 return connection; 1011 } 1012 getNumberOfConnections()1013 int getNumberOfConnections() { 1014 return CtsConnectionService.getAllConnectionsFromTelecom().size(); 1015 } 1016 getNumberOfActiveConnections()1017 int getNumberOfActiveConnections() { 1018 return CtsConnectionService.getAllConnectionsFromTelecom().stream() 1019 .filter(c -> c.getState() != Connection.STATE_DISCONNECTED).collect( 1020 Collectors.toSet()).size(); 1021 } 1022 getConnection(Uri address)1023 Connection getConnection(Uri address) { 1024 return CtsConnectionService.getAllConnectionsFromTelecom().stream() 1025 .filter(c -> c.getAddress().equals(address)).findFirst().orElse(null); 1026 } 1027 verifyConnectionForOutgoingCall()1028 MockConnection verifyConnectionForOutgoingCall() { 1029 // Assuming only 1 connection present 1030 return verifyConnectionForOutgoingCall(0); 1031 } 1032 verifyConnectionForOutgoingCall(int connectionIndex)1033 MockConnection verifyConnectionForOutgoingCall(int connectionIndex) { 1034 try { 1035 if (!connectionService.lock.tryAcquire(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1036 TimeUnit.MILLISECONDS)) { 1037 fail("No outgoing call connection requested by Telecom"); 1038 } 1039 } catch (InterruptedException e) { 1040 Log.i(TAG, "Test interrupted!"); 1041 } 1042 1043 assertThat("Telecom should create outgoing connection for outgoing call", 1044 connectionService.outgoingConnections.size(), not(equalTo(0))); 1045 MockConnection connection = connectionService.outgoingConnections.get(connectionIndex); 1046 return connection; 1047 } 1048 verifyConnectionForOutgoingCall(Uri address)1049 MockConnection verifyConnectionForOutgoingCall(Uri address) { 1050 if (!connectionService.waitForEvent( 1051 MockConnectionService.EVENT_CONNECTION_SERVICE_CREATE_CONNECTION)) { 1052 fail("No outgoing call connection requested by Telecom"); 1053 } 1054 assertThat("Telecom should create outgoing connection for outgoing call", 1055 connectionService.outgoingConnections.size(), not(equalTo(0))); 1056 1057 // There is a subtle race condition in ConnectionService. When onCreateIncomingConnection 1058 // or onCreateOutgoingConnection completes, ConnectionService then adds the connection to 1059 // the list of tracked connections. It's very possible for the lock to be released and 1060 // the connection to have not yet been added to the connection list yet. 1061 waitUntilConditionIsTrueOrTimeout(new Condition() { 1062 @Override 1063 public Object expected() { 1064 return true; 1065 } 1066 1067 @Override 1068 public Object actual() { 1069 return getConnection(address) != null; 1070 } 1071 }, 1072 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1073 "Expected call from number " + address); 1074 Connection connection = getConnection(address); 1075 1076 if (connection instanceof MockConnection) { 1077 if (connectionService.outgoingConnections.contains(connection)) { 1078 return (MockConnection) connection; 1079 } 1080 } 1081 return null; 1082 } 1083 verifyNoConnectionForOutgoingCall()1084 void verifyNoConnectionForOutgoingCall() { 1085 try { 1086 if (!connectionService.lock.tryAcquire(WAIT_FOR_OUTGOING_CONNECTION_TIMEOUT_MS, 1087 TimeUnit.MILLISECONDS)) { 1088 } 1089 } catch (InterruptedException e) { 1090 Log.i(TAG, "Test interrupted!"); 1091 } 1092 1093 assertThat("Telecom should not create outgoing connection for outgoing call", 1094 connectionService.outgoingConnections.size(), equalTo(0)); 1095 return; 1096 } 1097 verifyConnectionForIncomingCall()1098 MockConnection verifyConnectionForIncomingCall() { 1099 // Assuming only 1 connection present 1100 return verifyConnectionForIncomingCall(0); 1101 } 1102 verifyConnectionForIncomingCall(int connectionIndex)1103 MockConnection verifyConnectionForIncomingCall(int connectionIndex) { 1104 try { 1105 if (!connectionService.lock.tryAcquire(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1106 TimeUnit.MILLISECONDS)) { 1107 fail("No outgoing call connection requested by Telecom"); 1108 } 1109 } catch (InterruptedException e) { 1110 Log.i(TAG, "Test interrupted!"); 1111 } 1112 1113 assertThat("Telecom should create incoming connections for incoming calls", 1114 connectionService.incomingConnections.size(), not(equalTo(0))); 1115 MockConnection connection = connectionService.incomingConnections.get(connectionIndex); 1116 setAndVerifyConnectionForIncomingCall(connection); 1117 return connection; 1118 } 1119 verifyConference(int permit)1120 MockConference verifyConference(int permit) { 1121 try { 1122 if (!connectionService.lock.tryAcquire(permit, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1123 TimeUnit.MILLISECONDS)) { 1124 fail("No conference requested by Telecom"); 1125 } 1126 } catch (InterruptedException e) { 1127 Log.i(TAG, "Test interrupted!"); 1128 } 1129 return connectionService.conferences.get(0); 1130 } 1131 setAndVerifyConnectionForIncomingCall(MockConnection connection)1132 void setAndVerifyConnectionForIncomingCall(MockConnection connection) { 1133 if (connection.getState() == Connection.STATE_ACTIVE) { 1134 // If the connection is already active (like if it got picked up immediately), don't 1135 // bother with setting it back to ringing. 1136 return; 1137 } 1138 connection.setRinging(); 1139 assertConnectionState(connection, Connection.STATE_RINGING); 1140 } 1141 setAndVerifyConferenceablesForOutgoingConnection(int connectionIndex)1142 void setAndVerifyConferenceablesForOutgoingConnection(int connectionIndex) { 1143 assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); 1144 // Make all other outgoing connections as conferenceable with this connection. 1145 MockConnection connection = connectionService.outgoingConnections.get(connectionIndex); 1146 List<Connection> confConnections = 1147 new ArrayList<>(connectionService.outgoingConnections.size()); 1148 for (Connection c : connectionService.outgoingConnections) { 1149 if (c != connection) { 1150 confConnections.add(c); 1151 } 1152 } 1153 connection.setConferenceableConnections(confConnections); 1154 assertEquals(connection.getConferenceables(), confConnections); 1155 } 1156 addConferenceCall(Call call1, Call call2)1157 void addConferenceCall(Call call1, Call call2) { 1158 assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); 1159 int currentConfCallCount = 0; 1160 if (mInCallCallbacks.getService() != null) { 1161 currentConfCallCount = mInCallCallbacks.getService().getConferenceCallCount(); 1162 } 1163 // Verify that the calls have each other on their conferenceable list before proceeding 1164 List<Call> callConfList = new ArrayList<>(); 1165 callConfList.add(call2); 1166 assertCallConferenceableList(call1, callConfList); 1167 1168 callConfList.clear(); 1169 callConfList.add(call1); 1170 assertCallConferenceableList(call2, callConfList); 1171 1172 call1.conference(call2); 1173 1174 /** 1175 * We should have 1 onCallAdded, 2 onChildrenChanged and 2 onParentChanged invoked, so 1176 * we should have 5 available permits on the incallService lock. 1177 */ 1178 try { 1179 if (!mInCallCallbacks.lock.tryAcquire(5, 3, TimeUnit.SECONDS)) { 1180 fail("Conference addition failed."); 1181 } 1182 } catch (InterruptedException e) { 1183 Log.i(TAG, "Test interrupted!"); 1184 } 1185 1186 assertEquals("InCallService should contain 1 more call after adding a conf call.", 1187 currentConfCallCount + 1, 1188 mInCallCallbacks.getService().getConferenceCallCount()); 1189 } 1190 splitFromConferenceCall(Call call1)1191 void splitFromConferenceCall(Call call1) { 1192 assertEquals("Lock should have no permits!", 0, mInCallCallbacks.lock.availablePermits()); 1193 1194 call1.splitFromConference(); 1195 /** 1196 * We should have 1 onChildrenChanged and 1 onParentChanged invoked, so 1197 * we should have 2 available permits on the incallService lock. 1198 */ 1199 try { 1200 if (!mInCallCallbacks.lock.tryAcquire(2, 3, TimeUnit.SECONDS)) { 1201 fail("Conference split failed"); 1202 } 1203 } catch (InterruptedException e) { 1204 Log.i(TAG, "Test interrupted!"); 1205 } 1206 } 1207 verifyConferenceForOutgoingCall()1208 MockConference verifyConferenceForOutgoingCall() { 1209 try { 1210 if (!connectionService.lock.tryAcquire(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1211 TimeUnit.MILLISECONDS)) { 1212 fail("No outgoing conference requested by Telecom"); 1213 } 1214 } catch (InterruptedException e) { 1215 Log.i(TAG, "Test interrupted!"); 1216 } 1217 // Return the newly created conference object to the caller 1218 MockConference conference = connectionService.conferences.get(0); 1219 setAndVerifyConferenceForOutgoingCall(conference); 1220 return conference; 1221 } 1222 verifyAdhocConferenceCall()1223 Pair<Conference, ConnectionRequest> verifyAdhocConferenceCall() { 1224 try { 1225 if (!connectionService.lock.tryAcquire(2, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1226 TimeUnit.MILLISECONDS)) { 1227 fail("No conference requested by Telecom"); 1228 } 1229 } catch (InterruptedException e) { 1230 Log.i(TAG, "Test interrupted!"); 1231 } 1232 return new Pair<>(connectionService.conferences.get(0), 1233 connectionService.connectionRequest); 1234 } 1235 setAndVerifyConferenceForOutgoingCall(MockConference conference)1236 void setAndVerifyConferenceForOutgoingCall(MockConference conference) { 1237 conference.setActive(); 1238 assertConferenceState(conference, Connection.STATE_ACTIVE); 1239 } 1240 verifyCallStateListener(int expectedCallState)1241 void verifyCallStateListener(int expectedCallState) throws InterruptedException { 1242 mTestCallStateListener.getCountDownLatch().await( 1243 TestUtils.WAIT_FOR_PHONE_STATE_LISTENER_CALLBACK_TIMEOUT_S, TimeUnit.SECONDS); 1244 assertEquals(expectedCallState, mTestCallStateListener.getLastState()); 1245 } 1246 verifyPhoneStateListenerCallbacksForCall(int expectedCallState, String expectedNumber)1247 void verifyPhoneStateListenerCallbacksForCall(int expectedCallState, String expectedNumber) 1248 throws Exception { 1249 assertTrue(mTelephonyCallback.mCallbackSemaphore.tryAcquire( 1250 TestUtils.WAIT_FOR_PHONE_STATE_LISTENER_CALLBACK_TIMEOUT_S, TimeUnit.SECONDS)); 1251 // At this point we can only be sure that we got AN update, but not necessarily the one we 1252 // are looking for; wait until we see the state we want before verifying further. 1253 waitUntilConditionIsTrueOrTimeout(new Condition() { 1254 @Override 1255 public Object expected() { 1256 return true; 1257 } 1258 1259 @Override 1260 public Object actual() { 1261 return mTelephonyCallback.mCallStates 1262 .stream() 1263 .filter(p -> p == expectedCallState) 1264 .count() > 0; 1265 } 1266 }, 1267 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1268 "Expected call state " + expectedCallState + " and number " 1269 + expectedNumber); 1270 1271 1272 // Get the most recent callback; it is possible that there was an initial state reported due 1273 // to the fact that TelephonyManager will sometimes give an initial state back to the caller 1274 // when the listener is registered. 1275 int callState = mTelephonyCallback.mCallStates.get( 1276 mTelephonyCallback.mCallStates.size() - 1); 1277 assertEquals(expectedCallState, callState); 1278 // Note: We do NOT check the phone number here. Due to changes in how the phone state 1279 // broadcast is sent, the caller may receive multiple broadcasts, and the number will be 1280 // present in one or the other. We waited for a full matching broadcast above so we can 1281 // be sure the number was reported as expected. 1282 } 1283 verifyPhoneStateListenerCallbacksForEmergencyCall(String expectedNumber)1284 void verifyPhoneStateListenerCallbacksForEmergencyCall(String expectedNumber) 1285 throws Exception { 1286 assertTrue(mTelephonyCallback.mCallbackSemaphore.tryAcquire( 1287 TestUtils.WAIT_FOR_PHONE_STATE_LISTENER_CALLBACK_TIMEOUT_S, TimeUnit.SECONDS)); 1288 // At this point we can only be sure that we got AN update, but not necessarily the one we 1289 // are looking for; wait until we see the state we want before verifying further. 1290 waitUntilConditionIsTrueOrTimeout(new Condition() { 1291 @Override 1292 public Object expected() { 1293 return true; 1294 } 1295 1296 @Override 1297 public Object actual() { 1298 return mTelephonyCallback 1299 .mLastOutgoingEmergencyNumber != null 1300 && mTelephonyCallback 1301 .mLastOutgoingEmergencyNumber.getNumber() 1302 .equals(expectedNumber); 1303 } 1304 }, 1305 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1306 "Expected emergency number: " + expectedNumber); 1307 1308 assertEquals(mTelephonyCallback.mLastOutgoingEmergencyNumber.getNumber(), 1309 expectedNumber); 1310 } 1311 1312 /** 1313 * Disconnect the created test call and verify that Telecom has cleared all calls. 1314 */ cleanupCalls()1315 void cleanupCalls() { 1316 if (mInCallCallbacks != null && mInCallCallbacks.getService() != null) { 1317 mInCallCallbacks.getService().disconnectAllConferenceCalls(); 1318 mInCallCallbacks.getService().disconnectAllCalls(); 1319 // This method relies on assertions at the end, otherwise it can skip important 1320 // cleanup when the assertion causes the method to return early. 1321 assertNumConferenceCalls(mInCallCallbacks.getService(), 0); 1322 assertNumCalls(mInCallCallbacks.getService(), 0); 1323 } 1324 } 1325 1326 /** 1327 * Place a new outgoing call via the {@link CtsConnectionService} 1328 */ placeNewCallWithPhoneAccount(Bundle extras, int videoState)1329 private void placeNewCallWithPhoneAccount(Bundle extras, int videoState) { 1330 if (extras == null) { 1331 extras = new Bundle(); 1332 } 1333 if (!extras.containsKey(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE)) { 1334 extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, 1335 TestUtils.TEST_PHONE_ACCOUNT_HANDLE); 1336 } 1337 1338 if (!VideoProfile.isAudioOnly(videoState)) { 1339 extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState); 1340 } 1341 Uri number; 1342 if (extras.containsKey(TestUtils.EXTRA_PHONE_NUMBER)) { 1343 number = extras.getParcelable(TestUtils.EXTRA_PHONE_NUMBER); 1344 } else { 1345 number = createTestNumber(); 1346 } 1347 mTelecomManager.placeCall(number, extras); 1348 } 1349 1350 /** 1351 * Create a new number each time for a new test. Telecom has special logic to reuse certain 1352 * calls if multiple calls to the same number are placed within a short period of time which 1353 * can cause certain tests to fail. 1354 */ createTestNumber()1355 Uri createTestNumber() { 1356 return Uri.fromParts("tel", String.valueOf(++sCounter), null); 1357 } 1358 1359 /** 1360 * Creates a new random phone number in the range: 1361 * 000-000-0000 1362 * to 1363 * 999-999-9999 1364 * @return Randomized phone number. 1365 */ createRandomTestNumber()1366 Uri createRandomTestNumber() { 1367 return Uri.fromParts("tel", String.format("16%05d", new Random().nextInt(99999)) 1368 + String.format("%04d", new Random().nextInt(9999)), null); 1369 } 1370 getTestNumber()1371 public static Uri getTestNumber() { 1372 return Uri.fromParts("tel", String.valueOf(sCounter), null); 1373 } 1374 isLoggedCall(PhoneAccountHandle handle)1375 public boolean isLoggedCall(PhoneAccountHandle handle) { 1376 PhoneAccount phoneAccount = mTelecomManager.getPhoneAccount(handle); 1377 Bundle extras = phoneAccount.getExtras(); 1378 if (extras == null) { 1379 extras = new Bundle(); 1380 } 1381 boolean isSelfManaged = (phoneAccount.getCapabilities() 1382 & PhoneAccount.CAPABILITY_SELF_MANAGED) == PhoneAccount.CAPABILITY_SELF_MANAGED; 1383 // Calls are logged if: 1384 // 1. They're not self-managed 1385 // 2. They're self-managed and are configured to request logging. 1386 return (!isSelfManaged 1387 || (isSelfManaged 1388 && extras.getBoolean(PhoneAccount.EXTRA_LOG_SELF_MANAGED_CALLS) 1389 && (phoneAccount.getSupportedUriSchemes().contains(PhoneAccount.SCHEME_TEL) 1390 || phoneAccount.getSupportedUriSchemes().contains(PhoneAccount.SCHEME_SIP)))); 1391 } 1392 getCallLogEntryLatch()1393 public CountDownLatch getCallLogEntryLatch() { 1394 CountDownLatch changeLatch = new CountDownLatch(1); 1395 mContext.getContentResolver().registerContentObserver( 1396 CallLog.Calls.CONTENT_URI, true, 1397 new ContentObserver(mHandler) { 1398 @Override 1399 public void onChange(boolean selfChange, Uri uri) { 1400 mContext.getContentResolver().unregisterContentObserver(this); 1401 changeLatch.countDown(); 1402 super.onChange(selfChange); 1403 } 1404 }); 1405 return changeLatch; 1406 } 1407 verifyCallLogging( Uri testNumber, int expectedLogType, PhoneAccountHandle handle)1408 public void verifyCallLogging( 1409 Uri testNumber, int expectedLogType, PhoneAccountHandle handle) { 1410 CountDownLatch logLatch = getCallLogEntryLatch(); 1411 Cursor logCursor = getLatestCallLogCursorIfMatchesUri(logLatch, true /*isCallLogged*/, 1412 testNumber); 1413 assertNotNull("Call log entry not found for test number", logCursor); 1414 1415 int typeIndex = logCursor.getColumnIndex(CallLog.Calls.TYPE); 1416 int type = logCursor.getInt(typeIndex); 1417 assertEquals("recorded type does not match expected", expectedLogType, type); 1418 1419 int phoneAccountIdIndex = logCursor.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_ID); 1420 String phoneAccountId = logCursor.getString(phoneAccountIdIndex); 1421 assertEquals("recorded account ID does not match expected", 1422 handle.getId(), phoneAccountId); 1423 1424 int phoneAccountComponentNameIndex = logCursor.getColumnIndex( 1425 CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME); 1426 String phoneAccountComponentName = logCursor.getString(phoneAccountComponentNameIndex); 1427 assertEquals("recorded account component name does not match expected", 1428 handle.getComponentName().flattenToString(), phoneAccountComponentName); 1429 } 1430 getLatestCallLogCursorIfMatchesUri(CountDownLatch latch, boolean newLogExpected, Uri testNumber)1431 public Cursor getLatestCallLogCursorIfMatchesUri(CountDownLatch latch, boolean newLogExpected, 1432 Uri testNumber) { 1433 if (newLogExpected) { 1434 // Wait for the content observer to report that we have gotten a new call log entry. 1435 try { 1436 latch.await(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, TimeUnit.MILLISECONDS); 1437 } catch (InterruptedException ie) { 1438 fail("Expected log latch"); 1439 } 1440 } 1441 1442 // Query the latest entry into the call log. 1443 Cursor callsCursor = mContext.getContentResolver().query(CallLog.Calls.CONTENT_URI, null, 1444 null, null, CallLog.Calls._ID + " DESC limit 1;"); 1445 int numberIndex = callsCursor.getColumnIndex(CallLog.Calls.NUMBER); 1446 if (callsCursor.moveToNext()) { 1447 String number = callsCursor.getString(numberIndex); 1448 if (testNumber.getSchemeSpecificPart().equals(number)) { 1449 return callsCursor; 1450 } else { 1451 // Last call log entry doesnt match expected number. 1452 return null; 1453 } 1454 } 1455 // No Calls 1456 return null; 1457 } 1458 1459 /** 1460 * @return A test Parcelable with some basic values as well as a Binder that just responds with 1461 * the same thing that was sent to it. 1462 */ createTestParcelable()1463 TestParcelable createTestParcelable() { 1464 return new TestParcelable(42, "a test string", 1465 new ITestInterface.Stub() { 1466 @Override 1467 public String testLoopback(String testString) { 1468 return testString; 1469 } 1470 }); 1471 } 1472 1473 /** 1474 * Send a relatively complex Bundle that will go through Telecom as a call or connection event. 1475 * @param parcelable TestParcelable created with {@link #createTestParcelable()} 1476 */ 1477 Bundle createTestBundle(TestParcelable parcelable) { 1478 Bundle bundle = new Bundle(); 1479 bundle.putInt(TestParcelable.VAL_1_KEY, parcelable.mVal1); 1480 bundle.putString(TestParcelable.VAL_2_KEY, parcelable.mVal2); 1481 bundle.putBinder(TestParcelable.VAL_3_KEY, parcelable.mVal3); 1482 parcelable.copyIntoBundle(bundle); 1483 return bundle; 1484 } 1485 1486 /** 1487 * Verify the bundle created in {@link #createTestBundle} is correct. 1488 * @param receivedBundle The Bundle that was received 1489 * @param originalParcelable The original Parcelable created as part of 1490 * {@link #createTestBundle} 1491 */ 1492 void verifyTestBundle(Bundle receivedBundle, TestParcelable originalParcelable) { 1493 assertNotNull(receivedBundle); 1494 // We have to set the classloader here to the classloader of the test app or we will not 1495 // be able to unparcel. 1496 receivedBundle.setClassLoader(mContext.getClassLoader()); 1497 assertEquals(originalParcelable.mVal1, receivedBundle.getInt(TestParcelable.VAL_1_KEY)); 1498 assertEquals(originalParcelable.mVal2, receivedBundle.getString(TestParcelable.VAL_2_KEY)); 1499 IBinder testBinder = receivedBundle.getBinder(TestParcelable.VAL_3_KEY); 1500 assertNotNull(testBinder); 1501 assertEquals(originalParcelable.mVal3, testBinder); 1502 TestParcelable resultParcelable = null; 1503 try { 1504 resultParcelable = TestParcelable.getFromBundle(receivedBundle); 1505 } catch (Exception e) { 1506 fail("could not retrieve parcelable: " + e); 1507 } 1508 assertNotNull(resultParcelable); 1509 assertEquals(originalParcelable, resultParcelable); 1510 // Test Binder references that were received work properly 1511 try { 1512 ITestInterface testInterface = ITestInterface.Stub.asInterface(testBinder); 1513 assertEquals("testString", testInterface.testLoopback("testString")); 1514 testInterface = ITestInterface.Stub.asInterface(resultParcelable.mVal3); 1515 assertEquals("testString", testInterface.testLoopback("testString")); 1516 } catch (RemoteException e) { 1517 // this should not happen since it is accessing the local process 1518 fail("could not test IBinder due to Exception: " + e); 1519 } 1520 } 1521 1522 void assertNumCalls(final MockInCallService inCallService, final int numCalls) { 1523 waitUntilConditionIsTrueOrTimeout(new Condition() { 1524 @Override 1525 public Object expected() { 1526 return numCalls; 1527 } 1528 @Override 1529 public Object actual() { 1530 return inCallService.getCallCount(); 1531 } 1532 }, 1533 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1534 "InCallService should contain " + numCalls + " calls." 1535 ); 1536 } 1537 1538 void assertNumCalls_OrICSUnbound(final MockInCallService inCallService, final int numCalls) { 1539 waitUntilConditionIsTrueOrTimeout(new Condition() { 1540 @Override 1541 public Object expected() { 1542 return true; 1543 } 1544 1545 @Override 1546 public Object actual() { 1547 return inCallService == null || numCalls == inCallService.getCallCount(); 1548 } 1549 }, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, "InCallService should contain " + numCalls 1550 + " calls or the ICS should be unbound (meaning the call is destroyed)." 1551 ); 1552 } 1553 1554 void assertNumConferenceCalls(final MockInCallService inCallService, final int numCalls) { 1555 waitUntilConditionIsTrueOrTimeout(new Condition() { 1556 @Override 1557 public Object expected() { 1558 return numCalls; 1559 } 1560 @Override 1561 public Object actual() { 1562 return inCallService.getConferenceCallCount(); 1563 } 1564 }, 1565 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1566 "InCallService should contain " + numCalls + " conference calls." 1567 ); 1568 } 1569 1570 void assertActiveCSConnections(final int numConnections) { 1571 waitUntilConditionIsTrueOrTimeout(new Condition() { 1572 @Override 1573 public Object expected() { 1574 return numConnections; 1575 } 1576 1577 @Override 1578 public Object actual() { 1579 return getNumberOfActiveConnections(); 1580 } 1581 }, 1582 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1583 "ConnectionService should contain " + numConnections + " connections." 1584 ); 1585 } 1586 1587 void assertCSConnections(final int numConnections) { 1588 waitUntilConditionIsTrueOrTimeout(new Condition() { 1589 @Override 1590 public Object expected() { 1591 return numConnections; 1592 } 1593 1594 @Override 1595 public Object actual() { 1596 return CtsConnectionService 1597 .getAllConnectionsFromTelecom() 1598 .size(); 1599 } 1600 }, 1601 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1602 "ConnectionService should contain " + numConnections + " connections." 1603 ); 1604 } 1605 1606 void assertNumConnections(final MockConnectionService connService, final int numConnections) { 1607 waitUntilConditionIsTrueOrTimeout(new Condition() { 1608 @Override 1609 public Object expected() { 1610 return numConnections; 1611 } 1612 @Override 1613 public Object actual() { 1614 return connService.getAllConnections().size(); 1615 } 1616 }, 1617 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1618 "ConnectionService should contain " + numConnections + " connections." 1619 ); 1620 } 1621 1622 void assertMuteState(final InCallService incallService, final boolean isMuted) { 1623 waitUntilConditionIsTrueOrTimeout( 1624 new Condition() { 1625 @Override 1626 public Object expected() { 1627 return isMuted; 1628 } 1629 1630 @Override 1631 public Object actual() { 1632 final CallAudioState state = incallService.getCallAudioState(); 1633 return state == null ? null : state.isMuted(); 1634 } 1635 }, 1636 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1637 "Phone's mute state should be: " + isMuted 1638 ); 1639 } 1640 1641 void assertMuteState(final Connection connection, final boolean isMuted) { 1642 waitUntilConditionIsTrueOrTimeout( 1643 new Condition() { 1644 @Override 1645 public Object expected() { 1646 return isMuted; 1647 } 1648 1649 @Override 1650 public Object actual() { 1651 final CallAudioState state = connection.getCallAudioState(); 1652 return state == null ? null : state.isMuted(); 1653 } 1654 }, 1655 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1656 "Connection's mute state should be: " + isMuted 1657 ); 1658 } 1659 1660 /** 1661 * Asserts that a call video state is as expected. 1662 * 1663 * @param call The call. 1664 * @param videoState The expected video state. 1665 */ 1666 void assertVideoState(final Call call, final int videoState) { 1667 waitUntilConditionIsTrueOrTimeout( 1668 new Condition() { 1669 @Override 1670 public Object expected() { 1671 return videoState; 1672 } 1673 1674 @Override 1675 public Object actual() { 1676 return call.getDetails().getVideoState(); 1677 } 1678 }, 1679 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1680 "Call should be in videoState " + videoState 1681 ); 1682 } 1683 1684 void assertAudioRoute(final InCallService incallService, final int route) { 1685 waitUntilConditionIsTrueOrTimeout( 1686 new Condition() { 1687 @Override 1688 public Object expected() { 1689 return route; 1690 } 1691 1692 @Override 1693 public Object actual() { 1694 final CallAudioState state = incallService.getCallAudioState(); 1695 return state == null ? null : state.getRoute(); 1696 } 1697 }, 1698 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1699 "Phone's audio route should be: " + route 1700 ); 1701 } 1702 1703 void assertNotAudioRoute(final InCallService incallService, final int route) { 1704 waitUntilConditionIsTrueOrTimeout( 1705 new Condition() { 1706 @Override 1707 public Object expected() { 1708 return new Boolean(true); 1709 } 1710 1711 @Override 1712 public Object actual() { 1713 final CallAudioState state = incallService.getCallAudioState(); 1714 return route != state.getRoute(); 1715 } 1716 }, 1717 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1718 "Phone's audio route should not be: " + route 1719 ); 1720 } 1721 1722 void assertAudioRoute(final MockConnection connection, final int route) { 1723 waitUntilConditionIsTrueOrTimeout( 1724 new Condition() { 1725 @Override 1726 public Object expected() { 1727 return route; 1728 } 1729 1730 @Override 1731 public Object actual() { 1732 final CallAudioState state = ((Connection) connection).getCallAudioState(); 1733 return state == null ? null : state.getRoute(); 1734 } 1735 }, 1736 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1737 "Connection's audio route should be: " + route 1738 ); 1739 } 1740 1741 void assertConnectionState(final Connection connection, final int state) { 1742 waitUntilConditionIsTrueOrTimeout( 1743 new Condition() { 1744 @Override 1745 public Object expected() { 1746 return state; 1747 } 1748 1749 @Override 1750 public Object actual() { 1751 return connection.getState(); 1752 } 1753 }, 1754 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1755 "Connection should be in state " + state 1756 ); 1757 } 1758 1759 void assertCallState(final Call call, final int state) { 1760 waitUntilConditionIsTrueOrTimeout( 1761 new Condition() { 1762 @Override 1763 public Object expected() { 1764 return true; 1765 } 1766 1767 @Override 1768 public Object actual() { 1769 return call.getState() == state && call.getDetails().getState() == state; 1770 } 1771 }, 1772 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1773 "Expected state: " + state + ", callState=" + call.getState() + ", detailState=" 1774 + call.getDetails().getState() 1775 ); 1776 } 1777 1778 void assertCallConferenceableList(final Call call, final List<Call> conferenceableList) { 1779 waitUntilConditionIsTrueOrTimeout( 1780 new Condition() { 1781 @Override 1782 public Object expected() { 1783 return conferenceableList; 1784 } 1785 1786 @Override 1787 public Object actual() { 1788 return call.getConferenceableCalls(); 1789 } 1790 }, 1791 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1792 "Call: " + call + " does not have the correct conferenceable call list." 1793 ); 1794 } 1795 1796 void assertDtmfString(final MockConnection connection, final String dtmfString) { 1797 waitUntilConditionIsTrueOrTimeout(new Condition() { 1798 @Override 1799 public Object expected() { 1800 return dtmfString; 1801 } 1802 1803 @Override 1804 public Object actual() { 1805 return connection.getDtmfString(); 1806 } 1807 }, 1808 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1809 "DTMF string should be equivalent to entered DTMF characters: " + dtmfString 1810 ); 1811 } 1812 1813 void assertDtmfString(final MockConference conference, final String dtmfString) { 1814 waitUntilConditionIsTrueOrTimeout(new Condition() { 1815 @Override 1816 public Object expected() { 1817 return dtmfString; 1818 } 1819 1820 @Override 1821 public Object actual() { 1822 return conference.getDtmfString(); 1823 } 1824 }, 1825 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1826 "DTMF string should be equivalent to entered DTMF characters: " + dtmfString 1827 ); 1828 } 1829 1830 void assertCallDisplayName(final Call call, final String name) { 1831 waitUntilConditionIsTrueOrTimeout( 1832 new Condition() { 1833 @Override 1834 public Object expected() { 1835 return name; 1836 } 1837 1838 @Override 1839 public Object actual() { 1840 return call.getDetails().getCallerDisplayName(); 1841 } 1842 }, 1843 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1844 "Call should have display name: " + name 1845 ); 1846 } 1847 1848 void assertCallHandle(final Call call, final Uri expectedHandle) { 1849 waitUntilConditionIsTrueOrTimeout( 1850 new Condition() { 1851 @Override 1852 public Object expected() { 1853 return expectedHandle; 1854 } 1855 1856 @Override 1857 public Object actual() { 1858 return call.getDetails().getHandle(); 1859 } 1860 }, 1861 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1862 "Call should have handle name: " + expectedHandle 1863 ); 1864 } 1865 1866 void assertCallConnectTimeChanged(final Call call, final long time) { 1867 waitUntilConditionIsTrueOrTimeout( 1868 new Condition() { 1869 @Override 1870 public Object expected() { 1871 return true; 1872 } 1873 1874 @Override 1875 public Object actual() { 1876 return call.getDetails().getConnectTimeMillis() != time; 1877 } 1878 }, 1879 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1880 "Call have connect time: " + time 1881 ); 1882 } 1883 1884 void assertConnectionCallDisplayName(final Connection connection, final String name) { 1885 waitUntilConditionIsTrueOrTimeout( 1886 new Condition() { 1887 @Override 1888 public Object expected() { 1889 return name; 1890 } 1891 1892 @Override 1893 public Object actual() { 1894 return connection.getCallerDisplayName(); 1895 } 1896 }, 1897 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1898 "Connection should have display name: " + name 1899 ); 1900 } 1901 1902 void assertDisconnectReason(final Connection connection, final String disconnectReason) { 1903 waitUntilConditionIsTrueOrTimeout( 1904 new Condition() { 1905 @Override 1906 public Object expected() { 1907 return disconnectReason; 1908 } 1909 1910 @Override 1911 public Object actual() { 1912 return connection.getDisconnectCause().getReason(); 1913 } 1914 }, 1915 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1916 "Connection should have been disconnected with reason: " + disconnectReason 1917 ); 1918 } 1919 1920 void assertConferenceState(final Conference conference, final int state) { 1921 waitUntilConditionIsTrueOrTimeout( 1922 new Condition() { 1923 @Override 1924 public Object expected() { 1925 return state; 1926 } 1927 1928 @Override 1929 public Object actual() { 1930 return conference.getState(); 1931 } 1932 }, 1933 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1934 "Conference should be in state " + state 1935 ); 1936 } 1937 1938 1939 void assertOutgoingCallBroadcastReceived(boolean received) { 1940 waitUntilConditionIsTrueOrTimeout( 1941 new Condition() { 1942 @Override 1943 public Object expected() { 1944 return received; 1945 } 1946 1947 @Override 1948 public Object actual() { 1949 return NewOutgoingCallBroadcastReceiver 1950 .isNewOutgoingCallBroadcastReceived(); 1951 } 1952 }, 1953 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1954 received ? "Outgoing Call Broadcast should be received" 1955 : "Outgoing Call Broadcast should not be received" 1956 ); 1957 } 1958 1959 void assertCallDetailsConstructed(Call mCall, boolean constructed) { 1960 waitUntilConditionIsTrueOrTimeout( 1961 new Condition() { 1962 @Override 1963 public Object expected() { 1964 return constructed; 1965 } 1966 1967 @Override 1968 public Object actual() { 1969 return mCall != null && mCall.getDetails() != null; 1970 } 1971 }, 1972 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1973 constructed ? "Call Details should be constructed" 1974 : "Call Details should not be constructed" 1975 ); 1976 } 1977 1978 void assertCallGatewayConstructed(Call mCall, boolean constructed) { 1979 waitUntilConditionIsTrueOrTimeout( 1980 new Condition() { 1981 @Override 1982 public Object expected() { 1983 return constructed; 1984 } 1985 1986 @Override 1987 public Object actual() { 1988 return mCall != null && mCall.getDetails() != null 1989 && mCall.getDetails().getGatewayInfo() != null; 1990 } 1991 }, 1992 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 1993 constructed ? "Call Gateway should be constructed" 1994 : "Call Gateway should not be constructed" 1995 ); 1996 } 1997 1998 void assertCallNotNull(Call mCall, boolean notNull) { 1999 waitUntilConditionIsTrueOrTimeout( 2000 new Condition() { 2001 @Override 2002 public Object expected() { 2003 return notNull; 2004 } 2005 2006 @Override 2007 public Object actual() { 2008 return mCall != null; 2009 } 2010 }, 2011 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2012 notNull ? "Call should not be null" : "Call should be null" 2013 ); 2014 } 2015 2016 /** 2017 * Checks all fields of two PhoneAccounts for equality, with the exception of the enabled state. 2018 * Should only be called after assertPhoneAccountRegistered when it can be guaranteed 2019 * that the PhoneAccount is registered. 2020 * @param expected The expected PhoneAccount. 2021 * @param actual The actual PhoneAccount. 2022 */ 2023 void assertPhoneAccountEquals(final PhoneAccount expected, 2024 final PhoneAccount actual) { 2025 assertEquals(expected.getAddress(), actual.getAddress()); 2026 assertEquals(expected.getAccountHandle(), actual.getAccountHandle()); 2027 assertEquals(expected.getCapabilities(), actual.getCapabilities()); 2028 assertTrue(areBundlesEqual(expected.getExtras(), actual.getExtras())); 2029 assertEquals(expected.getHighlightColor(), actual.getHighlightColor()); 2030 assertEquals(expected.getIcon(), actual.getIcon()); 2031 assertEquals(expected.getLabel(), actual.getLabel()); 2032 assertEquals(expected.getShortDescription(), actual.getShortDescription()); 2033 assertEquals(expected.getSubscriptionAddress(), actual.getSubscriptionAddress()); 2034 assertEquals(expected.getSupportedUriSchemes(), actual.getSupportedUriSchemes()); 2035 } 2036 2037 void assertPhoneAccountRegistered(final PhoneAccountHandle handle) { 2038 waitUntilConditionIsTrueOrTimeout( 2039 new Condition() { 2040 @Override 2041 public Object expected() { 2042 return true; 2043 } 2044 2045 @Override 2046 public Object actual() { 2047 return mTelecomManager.getPhoneAccount(handle) != null; 2048 } 2049 }, 2050 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2051 "Phone account registration failed for " + handle 2052 ); 2053 } 2054 2055 void assertPhoneAccountEnabled(final PhoneAccountHandle handle) { 2056 waitUntilConditionIsTrueOrTimeout( 2057 new Condition() { 2058 @Override 2059 public Object expected() { 2060 return true; 2061 } 2062 2063 @Override 2064 public Object actual() { 2065 PhoneAccount phoneAccount = mTelecomManager.getPhoneAccount(handle); 2066 return (phoneAccount != null && phoneAccount.isEnabled()); 2067 } 2068 }, 2069 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2070 "Phone account enable failed for " + handle 2071 ); 2072 } 2073 2074 void assertPhoneAccountIsDefault(final PhoneAccountHandle handle) { 2075 waitUntilConditionIsTrueOrTimeout( 2076 new Condition() { 2077 @Override 2078 public Object expected() { 2079 return true; 2080 } 2081 2082 @Override 2083 public Object actual() { 2084 PhoneAccountHandle phoneAccountHandle = 2085 mTelecomManager.getUserSelectedOutgoingPhoneAccount(); 2086 return (phoneAccountHandle != null && phoneAccountHandle.equals(handle)); 2087 } 2088 }, 2089 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2090 "Failed to set default phone account to " + handle 2091 ); 2092 } 2093 2094 void assertCtsConnectionServiceUnbound() { 2095 if (CtsConnectionService.isServiceRegisteredToTelecom()) { 2096 assertTrue("CtsConnectionService not yet unbound!", 2097 CtsConnectionService.waitForUnBinding()); 2098 } 2099 } 2100 2101 void assertMockInCallServiceUnbound() { 2102 waitUntilConditionIsTrueOrTimeout( 2103 new Condition() { 2104 @Override 2105 public Object expected() { 2106 return false; 2107 } 2108 2109 @Override 2110 public Object actual() { 2111 return MockInCallService.isServiceBound(); 2112 } 2113 }, 2114 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2115 "MockInCallService not yet unbound!" 2116 ); 2117 } 2118 2119 void assertIsOutgoingCallPermitted(boolean isPermitted, PhoneAccountHandle handle) { 2120 waitUntilConditionIsTrueOrTimeout( 2121 new Condition() { 2122 @Override 2123 public Object expected() { 2124 return isPermitted; 2125 } 2126 2127 @Override 2128 public Object actual() { 2129 return mTelecomManager.isOutgoingCallPermitted(handle); 2130 } 2131 }, 2132 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2133 "Expected isOutgoingCallPermitted to be " + isPermitted 2134 ); 2135 } 2136 2137 void assertIsIncomingCallPermitted(boolean isPermitted, PhoneAccountHandle handle) { 2138 waitUntilConditionIsTrueOrTimeout( 2139 new Condition() { 2140 @Override 2141 public Object expected() { 2142 return isPermitted; 2143 } 2144 2145 @Override 2146 public Object actual() { 2147 return mTelecomManager.isIncomingCallPermitted(handle); 2148 } 2149 }, 2150 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2151 "Expected isIncomingCallPermitted to be " + isPermitted 2152 ); 2153 } 2154 2155 void assertIsInCall(boolean isIncall) { 2156 waitUntilConditionIsTrueOrTimeout( 2157 new Condition() { 2158 @Override 2159 public Object expected() { 2160 return isIncall; 2161 } 2162 2163 @Override 2164 public Object actual() { 2165 return mTelecomManager.isInCall(); 2166 } 2167 }, 2168 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2169 "Expected isInCall to be " + isIncall 2170 ); 2171 } 2172 2173 boolean waitForIsInCall(boolean isInCall) { 2174 return waitForCondition( 2175 new Condition() { 2176 @Override 2177 public Object expected() { 2178 return isInCall; 2179 } 2180 2181 @Override 2182 public Object actual() { 2183 return mTelecomManager.isInManagedCall(); 2184 } 2185 }, 2186 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 2187 } 2188 2189 void assertIsInManagedCall(boolean isIncall) { 2190 waitUntilConditionIsTrueOrTimeout( 2191 new Condition() { 2192 @Override 2193 public Object expected() { 2194 return isIncall; 2195 } 2196 2197 @Override 2198 public Object actual() { 2199 return mTelecomManager.isInManagedCall(); 2200 } 2201 }, 2202 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2203 "Expected isInManagedCall to be " + isIncall 2204 ); 2205 } 2206 2207 /** 2208 * Asserts that a call's properties are as expected. 2209 * 2210 * @param call The call. 2211 * @param properties The expected properties. 2212 */ 2213 public void assertCallProperties(final Call call, final int properties) { 2214 waitUntilConditionIsTrueOrTimeout( 2215 new Condition() { 2216 @Override 2217 public Object expected() { 2218 return true; 2219 } 2220 2221 @Override 2222 public Object actual() { 2223 return call.getDetails().hasProperty(properties); 2224 } 2225 }, 2226 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2227 "Call should have properties " + properties 2228 ); 2229 } 2230 2231 /** 2232 * Asserts that a call does not have any of the specified call capability bits specified. 2233 * 2234 * @param call The call. 2235 * @param capabilities The capability or capabilities which are not expected. 2236 */ 2237 public void assertDoesNotHaveCallCapabilities(final Call call, final int capabilities) { 2238 waitUntilConditionIsTrueOrTimeout( 2239 new Condition() { 2240 @Override 2241 public Object expected() { 2242 return true; 2243 } 2244 2245 @Override 2246 public Object actual() { 2247 int callCapabilities = call.getDetails().getCallCapabilities(); 2248 return !Call.Details.hasProperty(callCapabilities, capabilities); 2249 } 2250 }, 2251 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2252 "Call should not have capabilities " + capabilities 2253 ); 2254 } 2255 2256 /** 2257 * Asserts that a call does not have any of the specified call property bits specified. 2258 * 2259 * @param call The call. 2260 * @param properties The property or properties which are not expected. 2261 */ 2262 public void assertDoesNotHaveCallProperties(final Call call, final int properties) { 2263 waitUntilConditionIsTrueOrTimeout( 2264 new Condition() { 2265 @Override 2266 public Object expected() { 2267 return true; 2268 } 2269 2270 @Override 2271 public Object actual() { 2272 return !call.getDetails().hasProperty(properties); 2273 } 2274 }, 2275 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2276 "Call should not have properties " + properties 2277 ); 2278 } 2279 2280 /** 2281 * Asserts that the audio manager reports the specified audio mode. 2282 * 2283 * @param audioManager The audio manager to check. 2284 * @param expectedMode The expected audio mode. 2285 */ 2286 public void assertAudioMode(final AudioManager audioManager, final int expectedMode) { 2287 waitUntilConditionIsTrueOrTimeout( 2288 new Condition() { 2289 @Override 2290 public Object expected() { 2291 return true; 2292 } 2293 2294 @Override 2295 public Object actual() { 2296 return audioManager.getMode() == expectedMode; 2297 } 2298 }, 2299 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2300 "Audio mode was expected to be " + expectedMode 2301 ); 2302 } 2303 2304 /** 2305 * Asserts that a call's capabilities are as expected. 2306 * 2307 * @param call The call. 2308 * @param capabilities The expected capabiltiies. 2309 */ 2310 public void assertCallCapabilities(final Call call, final int capabilities) { 2311 waitUntilConditionIsTrueOrTimeout( 2312 new Condition() { 2313 @Override 2314 public Object expected() { 2315 return true; 2316 } 2317 2318 @Override 2319 public Object actual() { 2320 return (call.getDetails().getCallCapabilities() & capabilities) == 2321 capabilities; 2322 } 2323 }, 2324 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2325 "Call should have properties " + capabilities 2326 ); 2327 } 2328 2329 MockInCallService getInCallService() { 2330 return (mInCallCallbacks == null) ? null : mInCallCallbacks.getService(); 2331 } 2332 2333 public void waitOnInCallService() { 2334 waitUntilConditionIsTrueOrTimeout(new Condition() { 2335 @Override 2336 public Object expected() { 2337 return true; 2338 } 2339 2340 @Override 2341 public Object actual() { 2342 return mInCallCallbacks.getService() != null; 2343 } 2344 }, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, "MockInCallService failed to get Call"); 2345 } 2346 2347 /** 2348 * Asserts that the {@link UiModeManager} mode matches the specified mode. 2349 * 2350 * @param uiMode The expected ui mode. 2351 */ 2352 public void assertUiMode(final int uiMode) { 2353 waitUntilConditionIsTrueOrTimeout( 2354 new Condition() { 2355 @Override 2356 public Object expected() { 2357 return uiMode; 2358 } 2359 2360 @Override 2361 public Object actual() { 2362 return mUiModeManager.getCurrentModeType(); 2363 } 2364 }, 2365 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2366 "Expected ui mode " + uiMode 2367 ); 2368 } 2369 void assertEndpointType(final InCallService incallService, final int type) { 2370 waitUntilConditionIsTrueOrTimeout( 2371 new Condition() { 2372 @Override 2373 public Object expected() { 2374 return type; 2375 } 2376 2377 @Override 2378 public Object actual() { 2379 final CallEndpoint endpoint = incallService.getCurrentCallEndpoint(); 2380 return endpoint == null ? null : endpoint.getEndpointType(); 2381 } 2382 }, 2383 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2384 "Phone's call endpoint type should be: " + type 2385 ); 2386 } 2387 2388 void assertEndpointType(final MockConnection connection, final int type) { 2389 waitUntilConditionIsTrueOrTimeout( 2390 new Condition() { 2391 @Override 2392 public Object expected() { 2393 return type; 2394 } 2395 2396 @Override 2397 public Object actual() { 2398 final CallEndpoint endpoint = 2399 ((Connection) connection).getCurrentCallEndpoint(); 2400 return endpoint == null ? null : endpoint.getEndpointType(); 2401 } 2402 }, 2403 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2404 "Connection's call endpoint type should be: " + type 2405 ); 2406 } 2407 2408 void assertMuteEndpoint(final MockInCallService incallService, final boolean isMuted) { 2409 waitUntilConditionIsTrueOrTimeout( 2410 new Condition() { 2411 @Override 2412 public Object expected() { 2413 return isMuted; 2414 } 2415 2416 @Override 2417 public Object actual() { 2418 return incallService.getEndpointMuteState(); 2419 } 2420 }, 2421 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2422 "Phone's mute state should be: " + isMuted 2423 ); 2424 } 2425 2426 void assertMuteEndpoint(final MockConnection connection, final boolean isMuted) { 2427 waitUntilConditionIsTrueOrTimeout( 2428 new Condition() { 2429 @Override 2430 public Object expected() { 2431 return isMuted; 2432 } 2433 2434 @Override 2435 public Object actual() { 2436 return connection.getEndpointMuteState(); 2437 } 2438 }, 2439 WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, 2440 "Connection's mute state should be: " + isMuted 2441 ); 2442 } 2443 2444 boolean waitForCondition(Condition condition, long timeout) { 2445 final long start = System.currentTimeMillis(); 2446 while (!Objects.equals(condition.expected(), condition.actual()) 2447 && System.currentTimeMillis() - start < timeout) { 2448 sleep(50); 2449 } 2450 return Objects.equals(condition.expected(), condition.actual()); 2451 } 2452 2453 void waitUntilConditionIsTrueOrTimeout(Condition condition, long timeout, String description) { 2454 waitForCondition(condition, timeout); 2455 assertEquals(description, condition.expected(), condition.actual()); 2456 } 2457 2458 /** 2459 * Performs some work, and waits for the condition to be met. If the condition is not met in 2460 * each step of the loop, the work is performed again. 2461 * 2462 * @param work The work to perform. 2463 * @param condition The condition. 2464 * @param timeout The timeout. 2465 * @param description Description of the work being performed. 2466 */ 2467 void doWorkAndWaitUntilConditionIsTrueOrTimeout(Work work, Condition condition, long timeout, 2468 String description) { 2469 final long start = System.currentTimeMillis(); 2470 work.doWork(); 2471 while (!condition.expected().equals(condition.actual()) 2472 && System.currentTimeMillis() - start < timeout) { 2473 sleep(50); 2474 work.doWork(); 2475 } 2476 assertEquals(description, condition.expected(), condition.actual()); 2477 } 2478 2479 protected interface Condition { 2480 Object expected(); 2481 Object actual(); 2482 } 2483 2484 protected interface Work { 2485 void doWork(); 2486 } 2487 2488 public static boolean areBundlesEqual(Bundle extras, Bundle newExtras) { 2489 if (extras == null || newExtras == null) { 2490 return extras == newExtras; 2491 } 2492 2493 if (extras.size() != newExtras.size()) { 2494 return false; 2495 } 2496 2497 for (String key : extras.keySet()) { 2498 if (key != null) { 2499 final Object value = extras.get(key); 2500 final Object newValue = newExtras.get(key); 2501 if (!Objects.equals(value, newValue)) { 2502 return false; 2503 } 2504 } 2505 } 2506 return true; 2507 } 2508 2509 /** 2510 * Change the enabled state of a package and wait for confirmation that it has happened. 2511 * @param enabledSettings The component enabled settings. 2512 * @throws InterruptedException 2513 * @throws TimeoutException 2514 */ 2515 public void setComponentEnabledSettingsAndWaitForBroadcasts( 2516 PackageManager.ComponentEnabledSetting enabledSettings) 2517 throws InterruptedException, TimeoutException { 2518 final String enabledComponentName = enabledSettings.getComponentName().flattenToString(); 2519 final PackageManager packageManager = mContext.getPackageManager(); 2520 final IntentFilter filter = new IntentFilter(); 2521 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 2522 filter.addDataScheme("package"); 2523 2524 if (packageManager.getComponentEnabledSetting( 2525 enabledSettings.getComponentName()) == enabledSettings.getEnabledState()) { 2526 // enabled state already correct 2527 return; 2528 } 2529 2530 final CountDownLatch latch = new CountDownLatch(1 /* count */); 2531 final BroadcastReceiver br = new BroadcastReceiver() { 2532 @Override 2533 public void onReceive(Context context, Intent intent) { 2534 final String packageName = intent.getData() != null 2535 ? intent.getData().getSchemeSpecificPart() : null; 2536 final String[] receivedComponents = intent.getStringArrayExtra( 2537 Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); 2538 if (packageName == null) { 2539 return; 2540 } 2541 2542 for (String componentString : receivedComponents) { 2543 // Use contains since the componentstring is just the class name, not the full 2544 // component name sometimes. 2545 if (enabledComponentName.contains(componentString)) { 2546 latch.countDown(); 2547 break; 2548 } 2549 } 2550 } 2551 }; 2552 mContext.registerReceiver(br, filter, RECEIVER_EXPORTED); 2553 try { 2554 mContext.getPackageManager().setComponentEnabledSettings(List.of(enabledSettings)); 2555 long TIMEOUT_MS = 10000; 2556 if ((enabledSettings.getEnabledFlags() & PackageManager.DONT_KILL_APP) == 0) { 2557 TIMEOUT_MS = WAIT_FOR_STATE_CHANGE_TIMEOUT_MS; 2558 } else { 2559 TIMEOUT_MS = WAIT_FOR_STATE_CHANGE_TIMEOUT_MS + 10000; 2560 } 2561 if (!latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 2562 throw new TimeoutException("Package changed broadcasts for " + enabledSettings 2563 + " not received in " + TIMEOUT_MS + "ms"); 2564 } 2565 assertEquals(packageManager.getComponentEnabledSetting( 2566 enabledSettings.getComponentName()), enabledSettings.getEnabledState()); 2567 } finally { 2568 mContext.unregisterReceiver(br); 2569 } 2570 } 2571 2572 /** 2573 * Make sure we don't have any registered phone accounts from the Telecom CTS tests lingering 2574 * around. 2575 */ 2576 private void checkForCrossTestIsolationIssues() { 2577 TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); 2578 // Use shell identity so we can clean up some of the other test ones from the sub-apps that 2579 // are part of Telecom CTS. This gives us modify phone state so we can unregister anything. 2580 ShellIdentityUtils.invokeWithShellPermissions(() -> { 2581 List<PhoneAccount> allPhoneAccounts = telecomManager.getAllPhoneAccounts(); 2582 StringBuilder failures = new StringBuilder(); 2583 allPhoneAccounts.stream() 2584 .filter(a -> TestUtils.TEST_PACKAGES.contains( 2585 a.getAccountHandle().getComponentName().getPackageName())) 2586 .forEach(fa -> { 2587 // We will unregister it so other tests can continue. 2588 telecomManager.unregisterPhoneAccount(fa.getAccountHandle()); 2589 // And we will mark this test a failure so that we can clean up this mess. 2590 failures.append("Cross test isolation issue; phone account " + fa 2591 + " was still registered at the test end test.\n"); 2592 }); 2593 if (!failures.isEmpty()) { 2594 // Log a warning instead of failing. These test isolation issues are a game of 2595 // whack a mole. 2596 Log.w(TAG, failures.toString()); 2597 } 2598 }); 2599 } 2600 } 2601