Allow the system dialer to make emergency calls via ACTION_CALL

Bug: 6948882
Change-Id: Ic2e886f1a10620199c2e4503de603b2b80694e28
diff --git a/src/com/android/telecomm/CallActivity.java b/src/com/android/telecomm/CallActivity.java
index 6e83173..eb65c25 100644
--- a/src/com/android/telecomm/CallActivity.java
+++ b/src/com/android/telecomm/CallActivity.java
@@ -17,18 +17,33 @@
 package com.android.telecomm;
 
 import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.Bundle;
 import android.telecomm.PhoneAccountHandle;
 import android.telecomm.TelecommManager;
+import android.telecomm.TelecommManager;
+import android.text.TextUtils;
 
 /**
  * Activity that handles system CALL actions and forwards them to {@link CallsManager}.
  * Handles all three CALL action types: CALL, CALL_PRIVILEGED, and CALL_EMERGENCY.
+ *
+ * Pre-L, the only way apps were were allowed to make outgoing emergency calls was the
+ * ACTION_CALL_PRIVILEGED action (which requires the system only CALL_PRIVILEGED permission).
+ *
+ * In L, any app that has the CALL_PRIVILEGED permission can continue to make outgoing emergency
+ * calls via ACTION_CALL_PRIVILEGED.
+ *
+ * In addition, the default dialer (identified via {@link TelecommManager#getDefaultPhoneApp()}
+ * will also be granted the ability to make emergency outgoing calls using the CALL action. In
+ * order to do this, it must call startActivityForResult on the CALL intent to allow its package
+ * name to be passed to {@link CallActivity}. Calling startActivity will continue to work on all
+ * non-emergency numbers just like it did pre-L.
  */
 public class CallActivity extends Activity {
-
     private CallsManager mCallsManager = CallsManager.getInstance();
 
     /**
@@ -90,9 +105,10 @@
      * @param intent Call intent containing data about the handle to call.
      */
     private void processOutgoingCallIntent(Intent intent) {
-        NewOutgoingCallIntentBroadcaster broadcaster =
-                new NewOutgoingCallIntentBroadcaster(mCallsManager, intent);
-        broadcaster.processIntent();
+        NewOutgoingCallIntentBroadcaster broadcaster = new NewOutgoingCallIntentBroadcaster(
+                mCallsManager, intent, isDefaultDialer());
+        final boolean success = broadcaster.processIntent();
+        setResult(success ? RESULT_OK : RESULT_CANCELED);
     }
 
     /**
@@ -125,4 +141,17 @@
                 phoneAccountHandle.getComponentName());
         mCallsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
     }
+
+    private boolean isDefaultDialer() {
+        final String packageName = getCallingPackage();
+        if (TextUtils.isEmpty(packageName)) {
+            return false;
+        }
+
+        final TelecommManager telecommManager =
+                (TelecommManager) getSystemService(Context.TELECOMM_SERVICE);
+        final ComponentName defaultPhoneApp = telecommManager.getDefaultPhoneApp();
+        return (defaultPhoneApp != null
+                && TextUtils.equals(defaultPhoneApp.getPackageName(), packageName));
+    }
 }
diff --git a/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java b/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
index d99d976..e819bd3 100644
--- a/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/telecomm/NewOutgoingCallIntentBroadcaster.java
@@ -70,10 +70,17 @@
 
     private final CallsManager mCallsManager;
     private final Intent mIntent;
+    /*
+     * Whether or not the outgoing call intent originated from the default phone application. If
+     * so, it will be allowed to make emergency calls, even with the ACTION_CALL intent.
+     */
+    private final boolean mIsDefaultOrSystemPhoneApp;
 
-    NewOutgoingCallIntentBroadcaster(CallsManager callsManager, Intent intent) {
+    NewOutgoingCallIntentBroadcaster(CallsManager callsManager, Intent intent,
+            boolean isDefaultPhoneApp) {
         mCallsManager = callsManager;
         mIntent = intent;
+        mIsDefaultOrSystemPhoneApp = isDefaultPhoneApp;
     }
 
     /**
@@ -134,8 +141,10 @@
      * - CALL (intent launched by all third party dialers)
      * - CALL_PRIVILEGED (intent launched by system apps e.g. system Dialer, voice Dialer)
      * - CALL_EMERGENCY (intent launched by lock screen emergency dialer)
+     *
+     * @return whether or not the caller was allowed to start the outgoing call.
      */
-    void processIntent() {
+    boolean processIntent() {
         Log.v(this, "Processing call intent in OutgoingCallIntentBroadcaster.");
 
         final Context context = TelecommApp.getInstance();
@@ -145,7 +154,7 @@
 
         if (TextUtils.isEmpty(handle)) {
             Log.w(this, "Empty handle obtained from the call intent.");
-            return;
+            return false;
         }
 
         boolean isUriNumber = PhoneNumberUtils.isUriNumber(handle);
@@ -166,21 +175,25 @@
         String action = intent.getAction();
         if (Intent.ACTION_CALL.equals(action)) {
             if (isPotentialEmergencyNumber) {
-                Log.w(this, "Cannot call potential emergency number %s with CALL Intent %s.",
-                        handle, intent);
-                launchSystemDialer(context, intent.getData());
+                if (!mIsDefaultOrSystemPhoneApp) {
+                    Log.w(this, "Cannot call potential emergency number %s with CALL Intent %s "
+                            + "unless caller is system or default dialer.", handle, intent);
+                    launchSystemDialer(context, intent.getData());
+                    return false;
+                } else {
+                    callImmediately = true;
+                }
             }
-            callImmediately = false;
         } else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {
             if (!isPotentialEmergencyNumber) {
                 Log.w(this, "Cannot call non-potential-emergency number %s with EMERGENCY_CALL "
                         + "Intent %s.", handle, intent);
-                return;
+                return false;
             }
             callImmediately = true;
         } else {
             Log.w(this, "Unhandled Intent %s. Ignoring and not placing call.", intent);
-            return;
+            return false;
         }
 
         if (callImmediately) {
@@ -202,6 +215,7 @@
         }
 
         broadcastIntent(intent, handle, context, !callImmediately);
+        return true;
     }
 
     /**