Merge "Handle P-Associated-Uris which are SIP uris in conference host check." into rvc-qpr-dev
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 76cdd53..82a393d 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -16,6 +16,7 @@
 
 package com.android.services.telephony;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
@@ -28,6 +29,7 @@
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
 import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
 import android.util.Pair;
 
 import com.android.ims.internal.ConferenceParticipant;
@@ -1259,58 +1261,79 @@
     }
 
     /**
+     * Extracts a phone number from a {@link Uri}.
+     * <p>
+     * Phone numbers can be represented either as a TEL URI or a SIP URI.
+     * For conference event packages, RFC3261 specifies how participants can be identified using a
+     * SIP URI.
+     * A valid SIP uri has the format: sip:user:password@host:port;uri-parameters?headers
+     * Per RFC3261, the "user" can be a telephone number.
+     * For example: sip:1650555121;phone-context=blah.com@host.com
+     * In this case, the phone number is in the user field of the URI, and the parameters can be
+     * ignored.
+     *
+     * A SIP URI can also specify a phone number in a format similar to:
+     * sip:+1-212-555-1212@something.com;user=phone
+     * In this case, the phone number is again in user field and the parameters can be ignored.
+     * We can get the user field in these instances by splitting the string on the @, ;, or :
+     * and looking at the first found item.
+     * @param handle The URI containing a SIP or TEL formatted phone number.
+     * @return extracted phone number.
+     */
+    private static @NonNull String extractPhoneNumber(@NonNull Uri handle) {
+        // Number is always in the scheme specific part, regardless of whether this is a TEL or SIP
+        // URI.
+        String number = handle.getSchemeSpecificPart();
+        // Get anything before the @ for the SIP case.
+        String[] numberParts = number.split("[@;:]");
+
+        if (numberParts.length == 0) {
+            Log.v(LOG_TAG, "extractPhoneNumber(N) : no number in handle");
+            return "";
+        }
+        return numberParts[0];
+    }
+
+    /**
      * Determines if the passed in participant handle is the same as the conference host's handle.
      * Starts with a simple equality check.  However, the handles from a conference event package
      * will be a SIP uri, so we need to pull that apart to look for the participant's phone number.
      *
-     * @param hostHandles The handle(s) of the connection hosting the conference.
+     * @param hostHandles The handle(s) of the connection hosting the conference, typically obtained
+     *                    from P-Associated-Uri entries.
      * @param handle The handle of the conference participant.
      * @return {@code true} if the host's handle matches the participant's handle, {@code false}
      *      otherwise.
      */
-    private boolean isParticipantHost(Uri[] hostHandles, Uri handle) {
+    @VisibleForTesting
+    public static boolean isParticipantHost(Uri[] hostHandles, Uri handle) {
         // If there is no host handle or no participant handle, bail early.
         if (hostHandles == null || hostHandles.length == 0 || handle == null) {
-            Log.v(this, "isParticipantHost(N) : host or participant uri null");
+            Log.v(LOG_TAG, "isParticipantHost(N) : host or participant uri null");
             return false;
         }
 
-        // Conference event package participants are identified using SIP URIs (see RFC3261).
-        // A valid SIP uri has the format: sip:user:password@host:port;uri-parameters?headers
-        // Per RFC3261, the "user" can be a telephone number.
-        // For example: sip:1650555121;phone-context=blah.com@host.com
-        // In this case, the phone number is in the user field of the URI, and the parameters can be
-        // ignored.
-        //
-        // A SIP URI can also specify a phone number in a format similar to:
-        // sip:+1-212-555-1212@something.com;user=phone
-        // In this case, the phone number is again in user field and the parameters can be ignored.
-        // We can get the user field in these instances by splitting the string on the @, ;, or :
-        // and looking at the first found item.
-
-        String number = handle.getSchemeSpecificPart();
-        String numberParts[] = number.split("[@;:]");
-
-        if (numberParts.length == 0) {
-            Log.v(this, "isParticipantHost(N) : no number in participant handle");
+        String number = extractPhoneNumber(handle);
+        // If we couldn't extract the participant's number, then we can't determine if it is the
+        // host or not.
+        if (TextUtils.isEmpty(number)) {
             return false;
         }
-        number = numberParts[0];
 
         for (Uri hostHandle : hostHandles) {
             if (hostHandle == null) {
                 continue;
             }
-            // The host number will be a tel: uri.  Per RFC3966, the part after tel: is the phone
-            // number.
-            String hostNumber = hostHandle.getSchemeSpecificPart();
+            // Similar to the CEP participant data, the host identity in the P-Associated-Uri could
+            // be a SIP URI or a TEL URI.
+            String hostNumber = extractPhoneNumber(hostHandle);
 
             // Use a loose comparison of the phone numbers.  This ensures that numbers that differ
             // by special characters are counted as equal.
             // E.g. +16505551212 would be the same as 16505551212
             boolean isHost = PhoneNumberUtils.compare(hostNumber, number);
 
-            Log.v(this, "isParticipantHost(%s) : host: %s, participant %s", (isHost ? "Y" : "N"),
+            Log.v(LOG_TAG, "isParticipantHost(%s) : host: %s, participant %s", (isHost ? "Y" : "N"),
                     Rlog.pii(LOG_TAG, hostNumber), Rlog.pii(LOG_TAG, number));
 
             if (isHost) {
diff --git a/tests/src/com/android/services/telephony/ImsConferenceTest.java b/tests/src/com/android/services/telephony/ImsConferenceTest.java
index f13d709..7e6488d 100644
--- a/tests/src/com/android/services/telephony/ImsConferenceTest.java
+++ b/tests/src/com/android/services/telephony/ImsConferenceTest.java
@@ -16,6 +16,8 @@
 
 package com.android.services.telephony;
 
+import static junit.framework.Assert.assertTrue;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -573,4 +575,40 @@
         assertEquals(0, imsConference.getNumberOfParticipants());
         verify(mConferenceHost.mMockCall).hangup();
     }
+
+    /**
+     * Verifies that an ImsConference can handle SIP and TEL URIs for both the P-Associated-Uri and
+     * conference event package identities.
+     */
+    @Test
+    public void testIsParticipantHost() {
+        // Simplest case, assume P-Associated-Uri is a tel URI and that the CEP participant is also
+        // a tel URI.
+        assertTrue(ImsConference.isParticipantHost(new Uri[] {
+                        Uri.parse("tel:+8616505551234")},
+                Uri.parse("tel:+8616505551234")));
+
+        // Assume P-Associated-Uri is a tel URI and the CEP participant is a sip URI.
+        assertTrue(ImsConference.isParticipantHost(new Uri[] {
+                        Uri.parse("tel:+8616505551234")},
+                Uri.parse("sip:+8616505551234@bj.ims.mnc011.mcc460.3gppnetwork.org")));
+
+        // Assume P-Associated-Uri is a sip URI and the CEP participant is a tel URI.
+        assertTrue(ImsConference.isParticipantHost(new Uri[] {
+                        Uri.parse("sip:+8616505551234@bj.ims.mnc011.mcc460.3gppnetwork.org")},
+                Uri.parse("tel:+8616505551234")));
+
+        // Assume both P-Associated-Uri and the CEP participant are SIP URIs.
+        assertTrue(ImsConference.isParticipantHost(new Uri[] {
+                        Uri.parse("sip:+8616505551234@bj.ims.mnc011.mcc460.3gppnetwork.org")},
+                Uri.parse("sip:+8616505551234@bj.ims.mnc011.mcc460.3gppnetwork.org")));
+
+        // Corner cases
+        assertFalse(ImsConference.isParticipantHost(new Uri[] {
+                        Uri.parse("tel:+8616505551234")}, Uri.fromParts("", "", "")));
+        assertFalse(ImsConference.isParticipantHost(new Uri[] {
+                        Uri.parse("tel:+8616505551234")}, null));
+        assertFalse(ImsConference.isParticipantHost(null, null));
+        assertFalse(ImsConference.isParticipantHost(new Uri[0], null));
+    }
 }