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