Merge "Ensure self-managed CS can use any URI scheme." into pi-dev am: c3d76c905c
am: 8f87419d91

Change-Id: I1499f4b737a3a59a6c2a95bae1912a0a1758ccf0
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 6f1693a..b5e2958 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -1172,6 +1172,12 @@
             return false;
         }
 
+        if (!PhoneAccount.SCHEME_SIP.equals(getHandle().getScheme()) &&
+                !PhoneAccount.SCHEME_TEL.equals(getHandle().getScheme())) {
+            // Can't log schemes other than SIP or TEL for now.
+            return false;
+        }
+
         return phoneAccount.getExtras() != null && phoneAccount.getExtras().getBoolean(
                 PhoneAccount.EXTRA_LOG_SELF_MANAGED_CALLS, false);
     }
diff --git a/src/com/android/server/telecom/CallIntentProcessor.java b/src/com/android/server/telecom/CallIntentProcessor.java
index d90cba4..ff3b7b2 100644
--- a/src/com/android/server/telecom/CallIntentProcessor.java
+++ b/src/com/android/server/telecom/CallIntentProcessor.java
@@ -101,9 +101,9 @@
         String scheme = handle.getScheme();
         String uriString = handle.getSchemeSpecificPart();
 
-        if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
-            handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ?
-                    PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null);
+        // Ensure sip URIs dialed using TEL scheme get converted to SIP scheme.
+        if (PhoneAccount.SCHEME_TEL.equals(scheme) && PhoneNumberUtils.isUriNumber(uriString)) {
+            handle = Uri.fromParts(PhoneAccount.SCHEME_SIP, uriString, null);
         }
 
         PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
diff --git a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
index a7e21ad..3797c68 100644
--- a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
@@ -144,6 +144,9 @@
                         return;
                     }
 
+                    // TODO: Remove the assumption that phone numbers are either SIP or TEL.
+                    // This does not impact self-managed ConnectionServices as they do not use the
+                    // NewOutgoingCallIntentBroadcaster.
                     Uri resultHandleUri = Uri.fromParts(
                             mPhoneNumberUtilsAdapter.isUriNumber(resultNumber) ?
                                     PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL,
@@ -219,73 +222,88 @@
             }
         }
 
-        String number = mPhoneNumberUtilsAdapter.getNumberFromIntent(intent, mContext);
-        if (TextUtils.isEmpty(number)) {
-            Log.w(this, "Empty number obtained from the call intent.");
-            return DisconnectCause.NO_PHONE_NUMBER_SUPPLIED;
-        }
-
-        boolean isUriNumber = mPhoneNumberUtilsAdapter.isUriNumber(number);
-        if (!isUriNumber) {
-            number = mPhoneNumberUtilsAdapter.convertKeypadLettersToDigits(number);
-            number = mPhoneNumberUtilsAdapter.stripSeparators(number);
-        }
-
-        final boolean isPotentialEmergencyNumber = isPotentialEmergencyNumber(number);
-        Log.v(this, "isPotentialEmergencyNumber = %s", isPotentialEmergencyNumber);
-
-        rewriteCallIntentAction(intent, isPotentialEmergencyNumber);
-        action = intent.getAction();
-        // True for certain types of numbers that are not intended to be intercepted or modified
-        // by third parties (e.g. emergency numbers).
-        boolean callImmediately = false;
-
-        if (Intent.ACTION_CALL.equals(action)) {
-            if (isPotentialEmergencyNumber) {
-                if (!mIsDefaultOrSystemPhoneApp) {
-                    Log.w(this, "Cannot call potential emergency number %s with CALL Intent %s "
-                            + "unless caller is system or default dialer.", number, intent);
-                    launchSystemDialer(intent.getData());
-                    return DisconnectCause.OUTGOING_CANCELED;
-                } else {
-                    callImmediately = true;
-                }
-            }
-        } 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.", number, intent);
-                return DisconnectCause.OUTGOING_CANCELED;
-            }
-            callImmediately = true;
-        } else {
-            Log.w(this, "Unhandled Intent %s. Ignoring and not placing call.", intent);
-            return DisconnectCause.INVALID_NUMBER;
-        }
-
-        // True for all managed calls, false for self-managed calls.
-        boolean sendNewOutgoingCallBroadcast = true;
         PhoneAccountHandle targetPhoneAccount = mIntent.getParcelableExtra(
                 TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
+        boolean isSelfManaged = false;
         if (targetPhoneAccount != null) {
             PhoneAccount phoneAccount =
                     mCallsManager.getPhoneAccountRegistrar().getPhoneAccountUnchecked(
                             targetPhoneAccount);
-            if (phoneAccount != null && phoneAccount.isSelfManaged()) {
-                callImmediately = true;
-                sendNewOutgoingCallBroadcast = false;
-                Log.i(this, "Skipping NewOutgoingCallBroadcast for self-managed call.");
+            if (phoneAccount != null) {
+                isSelfManaged = phoneAccount.isSelfManaged();
             }
         }
 
-        if (callImmediately) {
+        String number = "";
+        // True for certain types of numbers that are not intended to be intercepted or modified
+        // by third parties (e.g. emergency numbers).
+        boolean callImmediately = false;
+        // True for all managed calls, false for self-managed calls.
+        boolean sendNewOutgoingCallBroadcast = true;
+        Uri callingAddress = handle;
+
+        if (!isSelfManaged) {
+            // Placing a managed call
+            number = mPhoneNumberUtilsAdapter.getNumberFromIntent(intent, mContext);
+            if (TextUtils.isEmpty(number)) {
+                Log.w(this, "Empty number obtained from the call intent.");
+                return DisconnectCause.NO_PHONE_NUMBER_SUPPLIED;
+            }
+
+            // TODO: Cleanup this dialing code; it makes the assumption that we're dialing with a
+            // SIP or TEL URI.
+            boolean isUriNumber = mPhoneNumberUtilsAdapter.isUriNumber(number);
+            if (!isUriNumber) {
+                number = mPhoneNumberUtilsAdapter.convertKeypadLettersToDigits(number);
+                number = mPhoneNumberUtilsAdapter.stripSeparators(number);
+            }
+
+            final boolean isPotentialEmergencyNumber = isPotentialEmergencyNumber(number);
+            Log.v(this, "isPotentialEmergencyNumber = %s", isPotentialEmergencyNumber);
+
+            rewriteCallIntentAction(intent, isPotentialEmergencyNumber);
+            action = intent.getAction();
+
+            if (Intent.ACTION_CALL.equals(action)) {
+                if (isPotentialEmergencyNumber) {
+                    if (!mIsDefaultOrSystemPhoneApp) {
+                        Log.w(this, "Cannot call potential emergency number %s with CALL Intent %s "
+                                + "unless caller is system or default dialer.", number, intent);
+                        launchSystemDialer(intent.getData());
+                        return DisconnectCause.OUTGOING_CANCELED;
+                    } else {
+                        callImmediately = true;
+                    }
+                }
+            } 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.", number, intent);
+                    return DisconnectCause.OUTGOING_CANCELED;
+                }
+                callImmediately = true;
+            } else {
+                Log.w(this, "Unhandled Intent %s. Ignoring and not placing call.", intent);
+                return DisconnectCause.INVALID_NUMBER;
+            }
+
+            // TODO: Support dialing using URIs instead of just assuming SIP or TEL.
             String scheme = isUriNumber ? PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL;
+            callingAddress = Uri.fromParts(scheme, number, null);
+        } else {
+            // Self-managed call.
+            callImmediately = true;
+            sendNewOutgoingCallBroadcast = false;
+            Log.i(this, "Skipping NewOutgoingCallBroadcast for self-managed call.");
+        }
+
+        if (callImmediately) {
             boolean speakerphoneOn = mIntent.getBooleanExtra(
                     TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
             int videoState = mIntent.getIntExtra(
                     TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
                     VideoProfile.STATE_AUDIO_ONLY);
-            placeOutgoingCallImmediately(mCall, Uri.fromParts(scheme, number, null), null,
+            placeOutgoingCallImmediately(mCall, callingAddress, null,
                     speakerphoneOn, videoState);
 
             // Don't return but instead continue and send the ACTION_NEW_OUTGOING_CALL broadcast
diff --git a/src/com/android/server/telecom/components/UserCallIntentProcessor.java b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
index 38c14d7..1a76043 100644
--- a/src/com/android/server/telecom/components/UserCallIntentProcessor.java
+++ b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
@@ -103,9 +103,9 @@
         String scheme = handle.getScheme();
         String uriString = handle.getSchemeSpecificPart();
 
-        if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
-            handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ?
-                    PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null);
+        // Ensure sip URIs dialed using TEL scheme get converted to SIP scheme.
+        if (PhoneAccount.SCHEME_TEL.equals(scheme) && PhoneNumberUtils.isUriNumber(uriString)) {
+            handle = Uri.fromParts(PhoneAccount.SCHEME_SIP, uriString, null);
         }
 
         // Check DISALLOW_OUTGOING_CALLS restriction. Note: We are skipping this check in a managed
diff --git a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
index ec80911..7fee263 100644
--- a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
+++ b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
@@ -583,6 +583,7 @@
                                     || TextUtils.isEmpty(handleString)) {
                                 handle = null;
                             } else {
+                                // TODO: Remove the assumption that numbers are SIP or TEL only.
                                 handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(handleString) ?
                                         PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL,
                                                 handleString, null);
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
index 8518adc..4b5fa57 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
@@ -48,6 +48,7 @@
     public static String SELF_MANAGED_ACCOUNT_2 = "2";
     public static String SELF_MANAGED_NAME_1 = "SuperCall";
     public static String SELF_MANAGED_NAME_2 = "Mega Call";
+    public static String CUSTOM_URI_SCHEME = "custom";
 
     private static SelfManagedCallList sInstance;
     private static ComponentName COMPONENT_NAME = new ComponentName(
@@ -112,6 +113,7 @@
         PhoneAccount.Builder builder = PhoneAccount.builder(handle, name)
                 .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
                 .addSupportedUriScheme(PhoneAccount.SCHEME_SIP)
+                .addSupportedUriScheme(CUSTOM_URI_SCHEME)
                 .setAddress(address)
                 .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED |
                         PhoneAccount.CAPABILITY_VIDEO_CALLING |
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index 9cc2b87..01d312b 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -437,6 +437,7 @@
         MockitoAnnotations.initMocks(this);
         when(mResources.getConfiguration()).thenReturn(mResourceConfiguration);
         when(mResources.getString(anyInt())).thenReturn("");
+        when(mResources.getStringArray(anyInt())).thenReturn(new String[0]);
         mResourceConfiguration.setLocale(Locale.TAIWAN);
 
         // TODO: Move into actual tests