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