Merge "Eliminate dependence on broadcasts to trampoline calls to Telecom."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b17c6f3..17c9698 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -295,12 +295,6 @@
                 android:exported="false"
                 android:process=":ui" />
 
-        <receiver android:name=".components.PrimaryCallReceiver"
-                android:exported="true"
-                android:permission="android.permission.MODIFY_PHONE_STATE"
-                android:process="system">
-        </receiver>
-
         <service android:name=".components.BluetoothPhoneService"
                 android:singleUser="true"
                 android:process="system">
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 602920c..ab36585 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -1472,6 +1472,33 @@
                 Log.endSession();
             }
         }
+
+        /**
+         * See {@link TelecomManager#handleCallIntent(Intent)} ()}
+         */
+        @Override
+        public void handleCallIntent(Intent intent) {
+            try {
+                Log.startSession("TSI.hCI");
+                synchronized (mLock) {
+                    int callingUid = Binder.getCallingUid();
+
+                    long token = Binder.clearCallingIdentity();
+                    if (callingUid != Process.myUid()) {
+                        throw new SecurityException("handleCallIntent is for Telecom only");
+                    }
+                    try {
+                        Log.i(this, "handleCallIntent: handling call intent");
+                        mCallIntentProcessorAdapter.processOutgoingCallIntent(mContext,
+                                mCallsManager, intent);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+            } finally {
+                Log.endSession();
+            }
+        }
     };
 
     /**
diff --git a/src/com/android/server/telecom/components/PrimaryCallReceiver.java b/src/com/android/server/telecom/components/PrimaryCallReceiver.java
deleted file mode 100644
index f19a243..0000000
--- a/src/com/android/server/telecom/components/PrimaryCallReceiver.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.android.server.telecom.components;
-
-import com.android.server.telecom.TelecomSystem;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.telecom.Log;
-
-/**
- * Single point of entry for all outgoing and incoming calls. {@link UserCallIntentProcessor} serves
- * as a trampoline that captures call intents for individual users and forwards it to
- * the {@link PrimaryCallReceiver} which interacts with the rest of Telecom, both of which run only as
- * the primary user.
- */
-public class PrimaryCallReceiver extends BroadcastReceiver implements TelecomSystem.Component {
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        Log.startSession("PCR.oR");
-        synchronized (getTelecomSystem().getLock()) {
-            getTelecomSystem().getCallIntentProcessor().processIntent(intent);
-        }
-        Log.endSession();
-    }
-
-    @Override
-    public TelecomSystem getTelecomSystem() {
-        return TelecomSystem.getInstance();
-    }
-}
diff --git a/src/com/android/server/telecom/components/UserCallIntentProcessor.java b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
index 0c8525f..6a8f8c8 100644
--- a/src/com/android/server/telecom/components/UserCallIntentProcessor.java
+++ b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
@@ -189,14 +189,13 @@
     }
 
     /**
-     * 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.
+     * Potentially trampolines the intent to Telecom via TelecomServiceImpl.
+     * If the caller is local to the Telecom service, we send the intent to Telecom without
+     * sending it through TelecomServiceImpl.
      */
     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);
         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.
@@ -209,7 +208,8 @@
             // 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);
+            TelecomManager tm = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+            tm.handleCallIntent(intent);
         }
         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 c7c5675..e863d27 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -1053,8 +1053,13 @@
                 mConnectionServiceFixtureA);
 
         // Should have reverted back to earpiece.
-        assertEquals(CallAudioState.ROUTE_EARPIECE,
-                mInCallServiceFixtureX.mCallAudioState.getRoute());
+        assertTrueWithTimeout(new Predicate<Void>() {
+            @Override
+            public boolean apply(Void aVoid) {
+                return mInCallServiceFixtureX.mCallAudioState.getRoute()
+                        == CallAudioState.ROUTE_EARPIECE;
+            }
+        });
     }
 
     /**
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index ad00456..25110e8 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -682,11 +682,6 @@
         Context localAppContext = mComponentContextFixture.getTestDouble().getApplicationContext();
         new UserCallIntentProcessor(localAppContext, userHandle).processIntent(
                 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.
-        verify(localAppContext).sendBroadcastAsUser(actionCallIntent, UserHandle.SYSTEM);
-        mTelecomSystem.getCallIntentProcessor().processIntent(actionCallIntent);
         // Wait for handler to start CallerInfo lookup.
         waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
         // Send the CallerInfo lookup reply.