Fix 4g conference call logs are merged together

If the first participant is same with other call logs, these call
logs are treated as group so that shows one call log. In order to avoid
it, compare number separately. Otherwise, avoid to query contact with
post dial string that casues showing contact name for post dial string
if user stores it as contact.

Change-Id: Ifaea5c5c3ed70e5654fcb3ff6372681ae14896ac
CRs-Fixed: 1089412
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 8e58a59..6a447a6 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -536,8 +536,8 @@
             // Lookup contacts with this number
             boolean isConfCallLog = num != null && num.length > 1
                     && DialerUtils.isConferenceURICallLog(phoneNumber, postDialDigits);
-            String queryNumber = isConfCallLog ? phoneNumber : number + postDialDigits;
-            info = mContactInfoCache.getValue(queryNumber,
+            String queryNumber = isConfCallLog ? phoneNumber : number;
+            info = mContactInfoCache.getValue(queryNumber, postDialDigits,
                     countryIso, cachedContactInfo, isConfCallLog);
         }
         CharSequence formattedNumber = info.formattedNumber == null
diff --git a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
index 426615a..667d6b9 100644
--- a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
+++ b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
@@ -47,6 +47,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Locale;
+import java.util.regex.Pattern;
 
 public class CallLogAsyncTaskUtil {
     private static String TAG = CallLogAsyncTaskUtil.class.getSimpleName();
@@ -209,14 +210,20 @@
                     PhoneNumberUtil.canPlaceCallsTo(number, numberPresentation) && !isVoicemail;
             ContactInfo info = ContactInfo.EMPTY;
 
+            Pattern pattern = Pattern.compile("[,;]");
+            String[] num = pattern.split(number);
+            boolean isConf = num != null && num.length > 1
+                    && DialerUtils.isConferenceURICallLog(number, postDialDigits);
+            String phoneNumber = num != null && num.length > 0 ? num[0] : "";
+            String queryNumber = isConf ? number : phoneNumber;
             if (shouldLookupNumber) {
-                ContactInfo lookupInfo = contactInfoHelper.lookupNumber(number, countryIso,
-                    DialerUtils.isConferenceURICallLog(number, postDialDigits));
+                ContactInfo lookupInfo = contactInfoHelper.lookupNumber(queryNumber, postDialDigits,
+                        countryIso, isConf);
                 info = lookupInfo != null ? lookupInfo : ContactInfo.EMPTY;
             }
 
             PhoneCallDetails details = new PhoneCallDetails(
-                    context, number, numberPresentation, info.formattedNumber,
+                    context, queryNumber, numberPresentation, info.formattedNumber,
                     postDialDigits, isVoicemail);
 
             details.viaNumber = viaNumber;
diff --git a/src/com/android/dialer/calllog/CallLogGroupBuilder.java b/src/com/android/dialer/calllog/CallLogGroupBuilder.java
index aa45029..ab9d535 100644
--- a/src/com/android/dialer/calllog/CallLogGroupBuilder.java
+++ b/src/com/android/dialer/calllog/CallLogGroupBuilder.java
@@ -27,6 +27,9 @@
 import com.android.contacts.common.util.DateUtils;
 import com.android.contacts.common.util.PhoneNumberHelper;
 import com.android.dialer.util.AppCompatConstants;
+import com.android.dialer.util.DialerUtils;
+
+import java.util.regex.Pattern;
 
 /**
  * Groups together calls in the call log.  The primary grouping attempts to group together calls
@@ -130,6 +133,8 @@
         int groupCallType = cursor.getInt(CallLogQuery.CALL_TYPE);
         String groupAccountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
         String groupAccountId = cursor.getString(CallLogQuery.ACCOUNT_ID);
+        boolean isGroupConfCallLog = DialerUtils.isConferenceURICallLog(groupNumber,
+                groupPostDialDigits);
         int groupSize = 1;
 
         String number;
@@ -138,6 +143,7 @@
         int callType;
         String accountComponentName;
         String accountId;
+        boolean isNumberConfCallLog = false;
 
         while (cursor.moveToNext()) {
             // Obtain the values for the current call to group.
@@ -149,8 +155,10 @@
             callType = cursor.getInt(CallLogQuery.CALL_TYPE);
             accountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
             accountId = cursor.getString(CallLogQuery.ACCOUNT_ID);
+            isNumberConfCallLog = DialerUtils.isConferenceURICallLog(number, numberPostDialDigits);
 
-            final boolean isSameNumber = equalNumbers(groupNumber, number);
+            final boolean isSameNumber = equalNumbers(groupNumber, isGroupConfCallLog,
+                    number, isNumberConfCallLog);
             final boolean isSamePostDialDigits = groupPostDialDigits.equals(numberPostDialDigits);
             final boolean isSameViaNumbers = groupViaNumbers.equals(numberViaNumbers);
             final boolean isSameAccount = isSameAccount(
@@ -184,6 +192,8 @@
                 groupCallType = callType;
                 groupAccountComponentName = accountComponentName;
                 groupAccountId = accountId;
+                isGroupConfCallLog = DialerUtils.isConferenceURICallLog(groupNumber,
+                        groupPostDialDigits);
             }
 
             // Save the day group associated with the current call.
@@ -224,8 +234,27 @@
 
     @VisibleForTesting
     boolean equalNumbers(String number1, String number2) {
+        return equalNumbers(number1, false, number2, false);
+    }
+
+    boolean equalNumbers(String number1, boolean isConf1, String number2, boolean isConf2) {
         if (PhoneNumberHelper.isUriNumber(number1) || PhoneNumberHelper.isUriNumber(number2)) {
             return compareSipAddresses(number1, number2);
+        } else if (isConf1 && isConf2) {
+            Pattern pattern = Pattern.compile("[,;]");
+            String[] num1 = pattern.split(number1);
+            String[] num2 = pattern.split(number2);
+            if (num1 == null || num2 == null || num1.length != num2.length) {
+                return false;
+            }
+            for (int i = 0; i < num1.length; i++) {
+                if (!PhoneNumberUtils.compare(num1[i], num2[i])) {
+                    return false;
+                }
+            }
+            return true;
+        } else if (isConf1 != isConf2) {
+            return false;
         } else {
             return PhoneNumberUtils.compare(number1, number2);
         }
diff --git a/src/com/android/dialer/calllog/ContactInfoHelper.java b/src/com/android/dialer/calllog/ContactInfoHelper.java
index bcc9e2f..ea39d03 100644
--- a/src/com/android/dialer/calllog/ContactInfoHelper.java
+++ b/src/com/android/dialer/calllog/ContactInfoHelper.java
@@ -78,7 +78,7 @@
      */
     @Nullable
     public ContactInfo lookupNumber(String number, String countryIso) {
-        return lookupNumber(number, countryIso, false);
+        return lookupNumber(number, null, countryIso, false);
     }
 
     /**
@@ -90,11 +90,13 @@
      * If an error occurs during the lookup, it returns null.
      *
      * @param number the number to look up
+     * @param postDialString append into number if required
      * @param countryIso the country associated with this number
      * @param isConfUrlLog whether call log is for Conference URL call
      */
     @Nullable
-    public ContactInfo lookupNumber(String number, String countryIso, boolean isConfUrlCallLog) {
+    public ContactInfo lookupNumber(String number, String postDialString, String countryIso,
+            boolean isConfUrlCallLog) {
 
         if (TextUtils.isEmpty(number)) {
             return null;
@@ -109,13 +111,14 @@
                 // If lookup failed, check if the "username" of the SIP address is a phone number.
                 String username = PhoneNumberHelper.getUsernameFromUriNumber(number);
                 if (PhoneNumberUtils.isGlobalPhoneNumber(username)) {
-                    info = queryContactInfoForPhoneNumber(username, countryIso, true,
+                    info = queryContactInfoForPhoneNumber(username, null, countryIso, true,
                             isConfUrlCallLog);
                 }
             }
         } else {
             // Look for a contact that has the given phone number.
-            info = queryContactInfoForPhoneNumber(number, countryIso, false, isConfUrlCallLog);
+            info = queryContactInfoForPhoneNumber(number, postDialString, countryIso,
+                    false, isConfUrlCallLog);
         }
 
         final ContactInfo updatedInfo;
@@ -127,6 +130,9 @@
             if (info == ContactInfo.EMPTY) {
                 // Did not find a matching contact.
                 updatedInfo = new ContactInfo();
+                if (!isConfUrlCallLog && !TextUtils.isEmpty(postDialString)) {
+                    number += postDialString;
+                }
                 updatedInfo.number = number;
                 updatedInfo.formattedNumber = formatPhoneNumber(number, null, countryIso);
                 updatedInfo.normalizedNumber = PhoneNumberUtils.formatNumberToE164(
@@ -265,8 +271,8 @@
      * <p>
      * If the lookup fails for some other reason, it returns null.
      */
-    private ContactInfo queryContactInfoForPhoneNumber(String number, String countryIso,
-            boolean isSip, boolean isConfUrlLog) {
+    private ContactInfo queryContactInfoForPhoneNumber(String number, String postDialString,
+            String countryIso, boolean isSip, boolean isConfUrlLog) {
         if (TextUtils.isEmpty(number)) {
             return null;
         }
@@ -303,6 +309,9 @@
             }
         }
         if (info != null && info != ContactInfo.EMPTY) {
+            if (!isConfUrlLog && TextUtils.isEmpty(postDialString)) {
+                number += postDialString;
+            }
             info.formattedNumber = formatPhoneNumber(number, null, countryIso);
         } else if (mCachedNumberLookupService != null) {
             CachedContactInfo cacheInfo =
diff --git a/src/com/android/dialer/contactinfo/ContactInfoCache.java b/src/com/android/dialer/contactinfo/ContactInfoCache.java
index af30c10..4fd3013 100644
--- a/src/com/android/dialer/contactinfo/ContactInfoCache.java
+++ b/src/com/android/dialer/contactinfo/ContactInfoCache.java
@@ -76,8 +76,8 @@
 
                 if (req != null) {
                     // Process the request. If the lookup succeeds, schedule a redraw.
-                    needRedraw |= queryContactInfo(req.number, req.countryIso, req.callLogInfo,
-                            req.isConf);
+                    needRedraw |= queryContactInfo(req.number, req.postDialString, req.countryIso,
+                            req.callLogInfo, req.isConf);
                 } else {
                     // Throttle redraw rate by only sending them when there are
                     // more requests.
@@ -131,6 +131,7 @@
     private final LinkedList<ContactInfoRequest> mRequests;
 
     private ExpirableCache<NumberWithCountryIso, ContactInfo> mCache;
+    private ExpirableCache<NumberWithCountryIso, ContactInfo> mCacheFor4gConfCall;
 
     private ContactInfoHelper mContactInfoHelper;
     private QueryThread mContactInfoQueryThread;
@@ -143,37 +144,52 @@
 
         mRequests = new LinkedList<ContactInfoRequest>();
         mCache = ExpirableCache.create(CONTACT_INFO_CACHE_SIZE);
+        mCacheFor4gConfCall = ExpirableCache.create(CONTACT_INFO_CACHE_SIZE);
     }
 
     public ContactInfo getValue(String number, String countryIso, ContactInfo cachedContactInfo) {
-        return getValue(number, countryIso, cachedContactInfo, false);
+        return getValue(number, null, countryIso, cachedContactInfo, false);
     }
 
-    public ContactInfo getValue(String number, String countryIso, ContactInfo cachedContactInfo,
-                boolean isConf) {
-        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso);
-        ExpirableCache.CachedValue<ContactInfo> cachedInfo =
-                mCache.getCachedValue(numberCountryIso);
+    public ContactInfo getValue(String number, String postDialString, String countryIso,
+                ContactInfo cachedContactInfo, boolean isConf) {
+        String phoneNumber = number;
+        if (!isConf && !TextUtils.isEmpty(postDialString)) {
+            phoneNumber += postDialString;
+        }
+        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(phoneNumber, countryIso);
+        ExpirableCache.CachedValue<ContactInfo> cachedInfo = null;
+        if (isConf) {
+            cachedInfo = mCacheFor4gConfCall.getCachedValue(numberCountryIso);
+        } else {
+            cachedInfo = mCache.getCachedValue(numberCountryIso);
+        }
         ContactInfo info = cachedInfo == null ? null : cachedInfo.getValue();
         if (cachedInfo == null) {
-            mCache.put(numberCountryIso, ContactInfo.EMPTY);
+            if (isConf) {
+                mCacheFor4gConfCall.put(numberCountryIso, ContactInfo.EMPTY);
+            } else {
+                mCache.put(numberCountryIso, ContactInfo.EMPTY);
+            }
             // Use the cached contact info from the call log.
             info = cachedContactInfo;
             // The db request should happen on a non-UI thread.
             // Request the contact details immediately since they are currently missing.
-            enqueueRequest(number, countryIso, cachedContactInfo, true, isConf);
+            enqueueRequest(number, postDialString, countryIso, cachedContactInfo, true, isConf);
             // We will format the phone number when we make the background request.
         } else {
             if (cachedInfo.isExpired()) {
                 // The contact info is no longer up to date, we should request it. However, we
                 // do not need to request them immediately.
-                enqueueRequest(number, countryIso, cachedContactInfo, false, isConf);
+                enqueueRequest(number, postDialString, countryIso,
+                        cachedContactInfo, false, isConf);
             } else if (!callLogInfoMatches(cachedContactInfo, info)) {
                 // The call log information does not match the one we have, look it up again.
                 // We could simply update the call log directly, but that needs to be done in a
                 // background thread, so it is easier to simply request a new lookup, which will, as
                 // a side-effect, update the call log.
-                enqueueRequest(number, countryIso, cachedContactInfo, false, isConf);
+                enqueueRequest(number, postDialString, countryIso,
+                        cachedContactInfo, false, isConf);
             }
 
             if (info == ContactInfo.EMPTY) {
@@ -192,12 +208,15 @@
      *
      * The number might be either a SIP address or a phone number.
      *
+     * @param postDialString if required, append into number
+     * @param isConf determine whether it is a 4g conf call log
      * It returns true if it updated the content of the cache and we should therefore tell the
      * view to update its content.
      */
-    private boolean queryContactInfo(String number, String countryIso, ContactInfo callLogInfo,
-            boolean isConf) {
-        final ContactInfo info = mContactInfoHelper.lookupNumber(number, countryIso, isConf);
+    private boolean queryContactInfo(String number, String postDialString, String countryIso,
+            ContactInfo callLogInfo, boolean isConf) {
+        final ContactInfo info = mContactInfoHelper.lookupNumber(number, postDialString,
+                countryIso, isConf);
 
         if (info == null) {
             // The lookup failed, just return without requesting to update the view.
@@ -206,8 +225,17 @@
 
         // Check the existing entry in the cache: only if it has changed we should update the
         // view.
-        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(number, countryIso);
-        ContactInfo existingInfo = mCache.getPossiblyExpired(numberCountryIso);
+        String phoneNumber = number;
+        if (!isConf && !TextUtils.isEmpty(postDialString)) {
+            phoneNumber += postDialString;
+        }
+        NumberWithCountryIso numberCountryIso = new NumberWithCountryIso(phoneNumber, countryIso);
+        ContactInfo existingInfo = null;
+        if (isConf) {
+            existingInfo = mCacheFor4gConfCall.getPossiblyExpired(numberCountryIso);
+        } else {
+            existingInfo = mCache.getPossiblyExpired(numberCountryIso);
+        }
 
         final boolean isRemoteSource = info.sourceType != 0;
 
@@ -222,11 +250,21 @@
 
         // Store the data in the cache so that the UI thread can use to display it. Store it
         // even if it has not changed so that it is marked as not expired.
-        mCache.put(numberCountryIso, info);
+        if (isConf) {
+            mCacheFor4gConfCall.put(numberCountryIso, info);
+        } else {
+            mCache.put(numberCountryIso, info);
+        }
 
         // Update the call log even if the cache it is up-to-date: it is possible that the cache
         // contains the value from a different call log entry.
-        mContactInfoHelper.updateCallLogContactInfo(number, countryIso, info, callLogInfo);
+        if (isConf) {
+            mContactInfoHelper.updateCallLogContactInfo(number, countryIso,
+                    info, callLogInfo);
+        } else {
+            mContactInfoHelper.updateCallLogContactInfo(phoneNumber, countryIso,
+                    info, callLogInfo);
+        }
         return updated;
     }
 
@@ -271,6 +309,7 @@
 
     public void invalidate() {
         mCache.expireAll();
+        mCacheFor4gConfCall.expireAll();
         stopRequestProcessing();
     }
 
@@ -300,7 +339,7 @@
      */
     protected void enqueueRequest(String number, String countryIso, ContactInfo callLogInfo,
             boolean immediate) {
-        enqueueRequest(number, countryIso, callLogInfo, immediate, false);
+        enqueueRequest(number, null, countryIso, callLogInfo, immediate, false);
     }
 
     /**
@@ -311,12 +350,13 @@
      * If the {@code immediate} parameter is true, it will start immediately the thread that looks
      * up the contact information (if it has not been already started). Otherwise, it will be
      * started with a delay. See {@link #START_PROCESSING_REQUESTS_DELAY_MILLIS}.
+     * @param postDialString if required, append into number
      * @param isConf indicate whether call log is for Conference Url call
      */
-    protected void enqueueRequest(String number, String countryIso, ContactInfo callLogInfo,
-            boolean immediate, boolean isConf) {
-        ContactInfoRequest request = new ContactInfoRequest(number, countryIso, callLogInfo,
-                isConf);
+    protected void enqueueRequest(String number, String postDialString, String countryIso,
+            ContactInfo callLogInfo, boolean immediate, boolean isConf) {
+        ContactInfoRequest request = new ContactInfoRequest(number, postDialString, countryIso,
+                callLogInfo, isConf);
         synchronized (mRequests) {
             if (!mRequests.contains(request)) {
                 mRequests.add(request);
diff --git a/src/com/android/dialer/contactinfo/ContactInfoRequest.java b/src/com/android/dialer/contactinfo/ContactInfoRequest.java
index 1171dcf..98208bc 100644
--- a/src/com/android/dialer/contactinfo/ContactInfoRequest.java
+++ b/src/com/android/dialer/contactinfo/ContactInfoRequest.java
@@ -32,14 +32,16 @@
     /** The cached contact information stored in the call log. */
     public final ContactInfo callLogInfo;
     public final boolean isConf;
+    public final String postDialString;
 
     public ContactInfoRequest(String number, String countryIso, ContactInfo callLogInfo) {
-        this(number, countryIso, callLogInfo, false);
+        this(number, null, countryIso, callLogInfo, false);
     }
 
-    public ContactInfoRequest(String number, String countryIso, ContactInfo callLogInfo,
-            boolean isConf) {
+    public ContactInfoRequest(String number, String postDialString, String countryIso,
+            ContactInfo callLogInfo, boolean isConf) {
         this.number = number;
+        this.postDialString = postDialString;
         this.countryIso = countryIso;
         this.callLogInfo = callLogInfo;
         this.isConf = isConf;
@@ -54,6 +56,7 @@
         ContactInfoRequest other = (ContactInfoRequest) obj;
 
         if (!TextUtils.equals(number, other.number)) return false;
+        if (!TextUtils.equals(postDialString, other.postDialString)) return false;
         if (!TextUtils.equals(countryIso, other.countryIso)) return false;
         if (!Objects.equal(callLogInfo, other.callLogInfo)) return false;
 
@@ -67,6 +70,7 @@
         result = prime * result + ((callLogInfo == null) ? 0 : callLogInfo.hashCode());
         result = prime * result + ((countryIso == null) ? 0 : countryIso.hashCode());
         result = prime * result + ((number == null) ? 0 : number.hashCode());
+        result = prime * result + ((postDialString == null) ? 0 : postDialString.hashCode());
         return result;
     }
 }