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