Send CALL intent directly to Telecom CallIntentProcessor.

TelecomManager#placeCall results in a CALL intent being sent from Telecom
to itself.  If there are delays in the system broadcast queue, the CALL
intent could be held up in the queue causing delays in the outgoing call
flow.

Changing the code so we instead just send the intent directly to the
call intent processor.

Test: Manually reproduced broadcast queue spamming issue and verified that
placeCall API does not block in this case any more.
Bug: 76005593
Merged-In: I4d1292d6fab2a2b7025e3bb9dd2592c7a18a5019
Change-Id: I4d1292d6fab2a2b7025e3bb9dd2592c7a18a5019
(cherry picked from commit 7878497846b9c5f66d3ffbcf45825bff356ef029)
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index f7f3c79..222b694 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -2977,7 +2977,7 @@
         return mOriginalConnectionId;
     }
 
-    ConnectionServiceFocusManager getConnectionServiceFocusManager() {
+    public ConnectionServiceFocusManager getConnectionServiceFocusManager() {
         return mCallsManager.getConnectionServiceFocusManager();
     }
 
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index a72e5b6..2c00941 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -17,6 +17,7 @@
 package com.android.server.telecom;
 
 import static android.Manifest.permission.CALL_PHONE;
+import static android.Manifest.permission.CALL_PRIVILEGED;
 import static android.Manifest.permission.DUMP;
 import static android.Manifest.permission.MODIFY_PHONE_STATE;
 import static android.Manifest.permission.READ_PHONE_STATE;
@@ -1227,12 +1228,20 @@
 
                 final boolean hasCallPermission = mContext.checkCallingPermission(CALL_PHONE) ==
                         PackageManager.PERMISSION_GRANTED;
+                // The Emergency Dialer has call privileged permission and uses this to place
+                // emergency calls.  We ensure permission checks in
+                // NewOutgoingCallIntentBroadcaster#process pass by sending this to
+                // Telecom as an ACTION_CALL_PRIVILEGED intent (which makes sense since the
+                // com.android.phone process has that permission).
+                final boolean hasCallPrivilegedPermission = mContext.checkCallingPermission(
+                        CALL_PRIVILEGED) == PackageManager.PERMISSION_GRANTED;
 
                 synchronized (mLock) {
                     final UserHandle userHandle = Binder.getCallingUserHandle();
                     long token = Binder.clearCallingIdentity();
                     try {
-                        final Intent intent = new Intent(Intent.ACTION_CALL, handle);
+                        final Intent intent = new Intent(hasCallPrivilegedPermission ?
+                                Intent.ACTION_CALL_PRIVILEGED : Intent.ACTION_CALL, handle);
                         if (extras != null) {
                             extras.setDefusable(true);
                             intent.putExtras(extras);
@@ -1240,7 +1249,8 @@
                         mUserCallIntentProcessorFactory.create(mContext, userHandle)
                                 .processIntent(
                                         intent, callingPackage, isSelfManaged ||
-                                                (hasCallAppOp && hasCallPermission));
+                                                (hasCallAppOp && hasCallPermission),
+                                        true /* isLocalInvocation */);
                     } finally {
                         Binder.restoreCallingIdentity(token);
                     }
diff --git a/src/com/android/server/telecom/components/UserCallActivity.java b/src/com/android/server/telecom/components/UserCallActivity.java
index dbee450..ca8fef7 100644
--- a/src/com/android/server/telecom/components/UserCallActivity.java
+++ b/src/com/android/server/telecom/components/UserCallActivity.java
@@ -74,7 +74,7 @@
             // ActivityThread.ActivityClientRecord#intent directly.
             // Modifying directly may be a potential risk when relaunching this activity.
             new UserCallIntentProcessor(this, userHandle).processIntent(new Intent(intent),
-                    getCallingPackage(), true /* hasCallAppOp*/);
+                    getCallingPackage(), true /* hasCallAppOp*/, false /* isLocalInvocation */);
         } finally {
             Log.endSession();
             wakelock.release();
diff --git a/src/com/android/server/telecom/components/UserCallIntentProcessor.java b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
index a95768e..38c14d7 100644
--- a/src/com/android/server/telecom/components/UserCallIntentProcessor.java
+++ b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
@@ -18,15 +18,14 @@
 
 import com.android.server.telecom.CallIntentProcessor;
 import com.android.server.telecom.R;
+import com.android.server.telecom.TelecomSystem;
 import com.android.server.telecom.TelephonyUtil;
 import com.android.server.telecom.UserUtil;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 
-import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -37,7 +36,6 @@
 import android.telecom.VideoProfile;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
-import android.widget.Toast;
 
 // TODO: Needed for move to system service: import com.android.internal.R;
 
@@ -72,9 +70,18 @@
      * Processes intents sent to the activity.
      *
      * @param intent The intent.
+     * @param callingPackageName The package name of the calling app.
+     * @param canCallNonEmergency {@code true} if the caller is permitted to call non-emergency
+     *                            numbers.
+     * @param isLocalInvocation {@code true} if the caller is within the system service (i.e. the
+     *                            caller is {@link com.android.server.telecom.TelecomServiceImpl})
+     *                            and we can skip the re-broadcast of the intent to Telecom.
+     *                            When {@code false}, we need to re-broadcast the intent to Telcom
+     *                            to trampoline it to the system service where the Telecom
+     *                            service resides.
      */
     public void processIntent(Intent intent, String callingPackageName,
-            boolean canCallNonEmergency) {
+            boolean canCallNonEmergency, boolean isLocalInvocation) {
         // Ensure call intents are not processed on devices that are not capable of calling.
         if (!isVoiceCapable()) {
             return;
@@ -85,12 +92,13 @@
         if (Intent.ACTION_CALL.equals(action) ||
                 Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
                 Intent.ACTION_CALL_EMERGENCY.equals(action)) {
-            processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency);
+            processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency,
+                    isLocalInvocation);
         }
     }
 
     private void processOutgoingCallIntent(Intent intent, String callingPackageName,
-            boolean canCallNonEmergency) {
+            boolean canCallNonEmergency, boolean isLocalInvocation) {
         Uri handle = intent.getData();
         String scheme = handle.getScheme();
         String uriString = handle.getSchemeSpecificPart();
@@ -144,7 +152,7 @@
         // Save the user handle of current user before forwarding the intent to primary user.
         intent.putExtra(CallIntentProcessor.KEY_INITIATING_USER, mUserHandle);
 
-        sendBroadcastToReceiver(intent);
+        sendIntentToDestination(intent, isLocalInvocation);
     }
 
     private boolean isDefaultOrSystemDialer(String callingPackageName) {
@@ -174,14 +182,28 @@
     }
 
     /**
-     * Trampolines the intent to the broadcast receiver that runs only as the primary user.
+     * Potentially trampolines the intent to the broadcast receiver that runs only as the primary
+     * user.  If the caller is local to the Telecom service, we send the intent to Telecom without
+     * rebroadcasting it.
      */
-    private boolean sendBroadcastToReceiver(Intent intent) {
+    private boolean sendIntentToDestination(Intent intent, boolean isLocalInvocation) {
         intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false);
         intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         intent.setClass(mContext, PrimaryCallReceiver.class);
-        Log.d(this, "Sending broadcast as user to CallReceiver");
-        mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+        if (isLocalInvocation) {
+            // We are invoking this from TelecomServiceImpl, so TelecomSystem is available.  Don't
+            // bother trampolining the intent, just sent it directly to the call intent processor.
+            // TODO: We should not be using an intent here; this whole flows needs cleanup.
+            Log.i(this, "sendIntentToDestination: send intent to Telecom directly.");
+            synchronized (TelecomSystem.getInstance().getLock()) {
+                TelecomSystem.getInstance().getCallIntentProcessor().processIntent(intent);
+            }
+        } else {
+            // We're calling from the UserCallActivity, so the TelecomSystem is not in the same
+            // process; we need to trampoline to TelecomSystem in the system server process.
+            Log.i(this, "sendIntentToDestination: trampoline to Telecom.");
+            mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+        }
         return true;
     }
 
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index 9302eaa..e304d34 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -442,6 +442,7 @@
 
     @LargeTest
     @Test
+    @FlakyTest
     public void testIncomingCallFromBlockedNumberIsRejected() throws Exception {
         String phoneNumber = "650-555-1212";
         blockNumber(phoneNumber);
@@ -986,19 +987,37 @@
     }
 
     /**
-     * Basic test to ensure that when there are other calls, we do not permit outgoing calls by a
-     * self managed CS.
+     * Ensure if there is a holdable call ongoing we'll be able to place another call.
      * @throws Exception
      */
     @LargeTest
     @Test
-    public void testIsOutgoingCallPermittedOngoing() throws Exception {
-        // Start a regular call; the self-managed CS can't make a call now.
+    public void testIsOutgoingCallPermittedOngoingHoldable() throws Exception {
+        // Start a regular call; the self-managed CS can make a call now since ongoing call can be
+        // held
         IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
         assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
 
-        assertFalse(mTelecomSystem.getTelecomServiceImpl().getBinder()
+        assertTrue(mTelecomSystem.getTelecomServiceImpl().getBinder()
+                .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle()));
+    }
+
+    /**
+     * Ensure if there is an unholdable call we can't place another call.
+     * @throws Exception
+     */
+    @LargeTest
+    @Test
+    public void testIsOutgoingCallPermittedOngoingUnHoldable() throws Exception {
+        // Start a regular call; the self-managed CS can't make a call now because the ongoing call
+        // can't be held.
+        mConnectionServiceFixtureA.mConnectionServiceDelegate.mCapabilities = 0;
+        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+
+        assertTrue(mTelecomSystem.getTelecomServiceImpl().getBinder()
                 .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle()));
     }
 
@@ -1009,6 +1028,7 @@
      */
     @LargeTest
     @Test
+    @FlakyTest
     public void testDisconnectSelfManaged() throws Exception {
         // Add a self-managed call.
         PhoneAccountHandle phoneAccountHandle = mPhoneAccountSelfManaged.getAccountHandle();
diff --git a/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java b/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
index be8b9b9..48319ad 100644
--- a/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
+++ b/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.telecom.tests;
 
+import static com.android.server.telecom.tests.TelecomSystemTest.TEST_TIMEOUT;
+
 import android.content.ComponentName;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
@@ -27,6 +29,7 @@
 
 import com.android.server.telecom.Call;
 import com.android.server.telecom.CallIdMapper;
+import com.android.server.telecom.ConnectionServiceFocusManager;
 import com.android.server.telecom.ConnectionServiceRepository;
 import com.android.server.telecom.ConnectionServiceWrapper;
 import com.android.server.telecom.CreateConnectionProcessor;
@@ -40,15 +43,20 @@
 import org.junit.runners.JUnit4;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -70,6 +78,8 @@
     CreateConnectionResponse mMockCreateConnectionResponse;
     @Mock
     Call mMockCall;
+    @Mock
+    ConnectionServiceFocusManager mConnectionServiceFocusManager;
 
     CreateConnectionProcessor mTestCreateConnectionProcessor;
 
@@ -80,6 +90,22 @@
         MockitoAnnotations.initMocks(this);
         mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
 
+        when(mMockCall.getConnectionServiceFocusManager()).thenReturn(
+                mConnectionServiceFocusManager);
+        doAnswer(new Answer<Void>() {
+                     @Override
+                     public Void answer(InvocationOnMock invocation) {
+                         Object[] args = invocation.getArguments();
+                         ConnectionServiceFocusManager.CallFocus focus =
+                                 (ConnectionServiceFocusManager.CallFocus) args[0];
+                         ConnectionServiceFocusManager.RequestFocusCallback callback =
+                                 (ConnectionServiceFocusManager.RequestFocusCallback) args[1];
+                         callback.onRequestFocusDone(focus);
+                         return null;
+                     }
+                 }
+                ).when(mConnectionServiceFocusManager).requestFocus(any(), any());
+
         mTestCreateConnectionProcessor = new CreateConnectionProcessor(mMockCall,
                 mMockConnectionServiceRepository, mMockCreateConnectionResponse,
                 mMockAccountRegistrar, mContext);
@@ -151,7 +177,8 @@
         verify(mMockCall).setConnectionManagerPhoneAccount(eq(callManagerPAHandle));
         verify(mMockCall).setTargetPhoneAccount(eq(pAHandle));
         verify(mMockCall).setConnectionService(eq(service));
-        verify(service).createConnection(eq(mMockCall), any(CreateConnectionResponse.class));
+        verify(service).createConnection(eq(mMockCall),
+                any(CreateConnectionResponse.class));
         // Notify successful connection to call
         CallIdMapper mockCallIdMapper = mock(CallIdMapper.class);
         mTestCreateConnectionProcessor.handleCreateConnectionSuccess(mockCallIdMapper, null);
@@ -177,6 +204,8 @@
         reset(mMockCall);
         reset(service);
 
+        when(mMockCall.getConnectionServiceFocusManager()).thenReturn(
+                mConnectionServiceFocusManager);
         // Notify that the ConnectionManager has denied the call.
         when(mMockCall.getConnectionManagerPhoneAccount()).thenReturn(callManagerPAHandle);
         when(mMockCall.getConnectionService()).thenReturn(service);
@@ -213,6 +242,8 @@
         reset(mMockCall);
         reset(service);
 
+        when(mMockCall.getConnectionServiceFocusManager()).thenReturn(
+                mConnectionServiceFocusManager);
         // Notify that the ConnectionManager has rejected the call.
         when(mMockCall.getConnectionManagerPhoneAccount()).thenReturn(callManagerPAHandle);
         when(mMockCall.getConnectionService()).thenReturn(service);
@@ -268,6 +299,9 @@
         mTestCreateConnectionProcessor.process();
         reset(mMockCall);
         reset(service);
+
+        when(mMockCall.getConnectionServiceFocusManager()).thenReturn(
+                mConnectionServiceFocusManager);
         when(mMockCall.isEmergencyCall()).thenReturn(true);
 
         // When Notify SIM connection fails, fall back to connection manager
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index 5963f8f..cbca5e1 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -17,6 +17,7 @@
 package com.android.server.telecom.tests;
 
 import static android.Manifest.permission.CALL_PHONE;
+import static android.Manifest.permission.CALL_PRIVILEGED;
 import static android.Manifest.permission.MODIFY_PHONE_STATE;
 import static android.Manifest.permission.READ_PHONE_STATE;
 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
@@ -91,6 +92,9 @@
 
 @RunWith(JUnit4.class)
 public class TelecomServiceImplTest extends TelecomTestCase {
+
+    public static final String TEST_PACKAGE = "com.test";
+
     public static class CallIntentProcessAdapterFake implements CallIntentProcessor.Adapter {
         @Override
         public void processOutgoingCallIntent(Context context, CallsManager callsManager,
@@ -645,6 +649,8 @@
                 .thenReturn(AppOpsManager.MODE_ALLOWED);
         doReturn(PackageManager.PERMISSION_GRANTED)
                 .when(mContext).checkCallingPermission(CALL_PHONE);
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(mContext).checkCallingPermission(CALL_PRIVILEGED);
 
         mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE);
         placeCallTestHelper(handle, extras, true);
@@ -660,6 +666,8 @@
                 .thenReturn(AppOpsManager.MODE_IGNORED);
         doReturn(PackageManager.PERMISSION_GRANTED)
                 .when(mContext).checkCallingPermission(CALL_PHONE);
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(mContext).checkCallingPermission(CALL_PRIVILEGED);
 
         mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE);
         placeCallTestHelper(handle, extras, false);
@@ -675,6 +683,8 @@
                 .thenReturn(AppOpsManager.MODE_ALLOWED);
         doReturn(PackageManager.PERMISSION_DENIED)
                 .when(mContext).checkCallingPermission(CALL_PHONE);
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(mContext).checkCallingPermission(CALL_PRIVILEGED);
 
         mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE);
         placeCallTestHelper(handle, extras, false);
@@ -684,7 +694,7 @@
             boolean shouldNonEmergencyBeAllowed) {
         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
         verify(mUserCallIntentProcessor).processIntent(intentCaptor.capture(), anyString(),
-                eq(shouldNonEmergencyBeAllowed));
+                eq(shouldNonEmergencyBeAllowed), eq(true));
         Intent capturedIntent = intentCaptor.getValue();
         assertEquals(Intent.ACTION_CALL, capturedIntent.getAction());
         assertEquals(expectedHandle, capturedIntent.getData());
@@ -707,7 +717,7 @@
         }
 
         verify(mUserCallIntentProcessor, never())
-                .processIntent(any(Intent.class), anyString(), anyBoolean());
+                .processIntent(any(Intent.class), anyString(), anyBoolean(), eq(true));
     }
 
     @SmallTest
@@ -843,8 +853,8 @@
         Call call = mock(Call.class);
         when(call.getState()).thenReturn(CallState.RINGING);
         when(mFakeCallsManager.getForegroundCall()).thenReturn(call);
-        assertTrue(mTSIBinder.endCall(null));
-        verify(call).reject(false, null);
+        assertTrue(mTSIBinder.endCall(TEST_PACKAGE));
+        verify(call).reject(eq(false), isNull(), eq(TEST_PACKAGE));
     }
 
     @SmallTest
@@ -853,8 +863,8 @@
         Call call = mock(Call.class);
         when(call.getState()).thenReturn(CallState.ACTIVE);
         when(mFakeCallsManager.getForegroundCall()).thenReturn(call);
-        assertTrue(mTSIBinder.endCall(null));
-        verify(call).disconnect();
+        assertTrue(mTSIBinder.endCall(TEST_PACKAGE));
+        verify(call).disconnect(eq(0L), eq(TEST_PACKAGE));
     }
 
     @SmallTest
@@ -864,8 +874,8 @@
         when(call.getState()).thenReturn(CallState.ACTIVE);
         when(mFakeCallsManager.getFirstCallWithState(any()))
                 .thenReturn(call);
-        assertTrue(mTSIBinder.endCall(null));
-        verify(call).disconnect();
+        assertTrue(mTSIBinder.endCall(TEST_PACKAGE));
+        verify(call).disconnect(eq(0L), eq(TEST_PACKAGE));
     }
 
     @SmallTest
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index b26143d..4cf7644 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.isNotNull;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyBoolean;
@@ -593,6 +594,9 @@
         startOutgoingPhoneCallPendingCreateConnection(number, phoneAccountHandle,
                 connectionServiceFixture, initiatingUser, videoState);
 
+        verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
+                .createConnectionComplete(anyString(), any());
+
         return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls,
                 phoneAccountHandle, connectionServiceFixture);
     }
@@ -669,7 +673,7 @@
         final UserHandle userHandle = initiatingUser;
         Context localAppContext = mComponentContextFixture.getTestDouble().getApplicationContext();
         new UserCallIntentProcessor(localAppContext, userHandle).processIntent(
-                actionCallIntent, null, true /* hasCallAppOp*/);
+                actionCallIntent, null, true /* hasCallAppOp*/, false /* isLocal */);
         // UserCallIntentProcessor's mContext.sendBroadcastAsUser(...) will call to an empty method
         // as to not actually try to send an intent to PrimaryCallReceiver. We verify that it was
         // called correctly in order to continue.
@@ -758,13 +762,16 @@
             int startingNumCalls, PhoneAccountHandle phoneAccountHandle,
             ConnectionServiceFixture connectionServiceFixture) throws Exception {
 
-        assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size());
+        // Wait for the focus tracker.
+        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
 
         verify(connectionServiceFixture.getTestDouble())
                 .createConnection(eq(phoneAccountHandle), anyString(), any(ConnectionRequest.class),
                         eq(false)/*isIncoming*/, anyBoolean(), any());
         // Wait for handleCreateConnectionComplete
         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
+        assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size());
+
         // Wait for the callback in ConnectionService#onAdapterAttached to execute.
         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
 
@@ -833,7 +840,6 @@
         verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
                 .createConnectionComplete(anyString(), any());
 
-
         // Process the CallerInfo lookup reply
         mCallerInfoAsyncQueryFactoryFixture.mRequests.forEach(
                 CallerInfoAsyncQueryFactoryFixture.Request::reply);
@@ -847,7 +853,7 @@
                 anyString(),
                 eq(BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER),
                 eq(number),
-                isNull(Bundle.class));
+                isNotNull(Bundle.class));
 
         // For the case of incoming calls, Telecom connecting the InCall services and adding the
         // Call is triggered by the async completion of the CallerInfoAsyncQuery. Once the Call
@@ -968,10 +974,10 @@
                     .answerCall(ids.mCallId, videoState);
 
             if (!VideoProfile.isVideo(videoState)) {
-                verify(connectionServiceFixture.getTestDouble())
+                verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
                         .answer(eq(ids.mConnectionId), any());
             } else {
-                verify(connectionServiceFixture.getTestDouble())
+                verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
                         .answerVideo(eq(ids.mConnectionId), eq(videoState), any());
             }
         }