From 17b8bd14b9cf67b7353f9287045fdc10fd1e93fb Mon Sep 17 00:00:00 2001 From: zachh Date: Fri, 19 Jan 2018 10:54:19 -0800 Subject: Improved support for post dial digits in new call log. -Don't ever coalesce rows with different post-dial digits -Made matching of unparsable numbers a little more intelligent by comparing national/postdial portions which have undialable characters removed (rather than exact string match) -Read and append the post-dial digits from the system call log when building DialerPhoneNumbers to place in the AnnotatedCallLog. Note: PhoneNumberUtil will parse numbers with exactly one post-dial character, but not more than one. -Use post-dial digits when building the AnnotatedCallLog's FORMATTED_NUMBER value -Display the formatted number in CallDetails when the name is missing, instead of the unformatted number -Don't set the displayNumber in CallDetails when the name is missing, because we are showing the (formatted) number via the nameOrNumber field. -Treat numbers with post-dial digits as invalid in PartitionedNumbers; batch operations are not possible with these numbers because their normalized representations strip the post-dial digits (and they are significant for contact matching) Bug: 70989632 Test: unit and manual PiperOrigin-RevId: 182557754 Change-Id: Idcdefce0946a189e5b350a53ec2a16a96a8d4552 --- .../android/dialer/calllog/database/Coalescer.java | 13 ++----- .../systemcalllog/SystemCallLogDataSource.java | 22 +++++++---- .../android/dialer/calllog/ui/menu/Modules.java | 10 ++--- .../phonenumberproto/DialerPhoneNumberUtil.java | 43 ++++++++++++++++++---- .../phonenumberproto/PartitionedNumbers.java | 19 +++++++++- 5 files changed, 78 insertions(+), 29 deletions(-) (limited to 'java/com/android') diff --git a/java/com/android/dialer/calllog/database/Coalescer.java b/java/com/android/dialer/calllog/database/Coalescer.java index 3c2585e01..b10dea24a 100644 --- a/java/com/android/dialer/calllog/database/Coalescer.java +++ b/java/com/android/dialer/calllog/database/Coalescer.java @@ -156,6 +156,10 @@ public class Coalescer { return false; } + if (!meetsAssistedDialingCriteria(row1, row2)) { + return false; + } + DialerPhoneNumber number1; DialerPhoneNumber number2; try { @@ -172,15 +176,6 @@ public class Coalescer { } catch (InvalidProtocolBufferException e) { throw Assert.createAssertionFailException("error parsing DialerPhoneNumber proto", e); } - - if (!number1.hasDialerInternalPhoneNumber() || !number2.hasDialerInternalPhoneNumber()) { - // An empty number should not be combined with any other number. - return false; - } - - if (!meetsAssistedDialingCriteria(row1, row2)) { - return false; - } return dialerPhoneNumberUtil.isMatch(number1, number2); } diff --git a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java index 34e6069f0..ee169e1d2 100644 --- a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java +++ b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java @@ -235,7 +235,7 @@ public class SystemCallLogDataSource implements CallLogDataSource { new String[] { Calls._ID, Calls.DATE, - Calls.LAST_MODIFIED, + Calls.LAST_MODIFIED, // TODO(a bug): Not available in M Calls.NUMBER, Calls.TYPE, Calls.COUNTRY_ISO, @@ -248,8 +248,10 @@ public class SystemCallLogDataSource implements CallLogDataSource { Calls.GEOCODED_LOCATION, Calls.PHONE_ACCOUNT_COMPONENT_NAME, Calls.PHONE_ACCOUNT_ID, - Calls.FEATURES + Calls.FEATURES, + Calls.POST_DIAL_DIGITS, // TODO(a bug): Not available in M }, + // TODO(a bug): LAST_MODIFIED not available on M Calls.LAST_MODIFIED + " > ? AND " + Voicemails.DELETED + " = 0", new String[] {String.valueOf(previousTimestampProcessed)}, Calls.LAST_MODIFIED + " DESC LIMIT 1000")) { @@ -282,6 +284,7 @@ public class SystemCallLogDataSource implements CallLogDataSource { cursor.getColumnIndexOrThrow(Calls.PHONE_ACCOUNT_COMPONENT_NAME); int phoneAccountIdColumn = cursor.getColumnIndexOrThrow(Calls.PHONE_ACCOUNT_ID); int featuresColumn = cursor.getColumnIndexOrThrow(Calls.FEATURES); + int postDialDigitsColumn = cursor.getColumnIndexOrThrow(Calls.POST_DIAL_DIGITS); // The cursor orders by LAST_MODIFIED DESC, so the first result is the most recent timestamp // processed. @@ -302,19 +305,24 @@ public class SystemCallLogDataSource implements CallLogDataSource { String phoneAccountComponentName = cursor.getString(phoneAccountComponentColumn); String phoneAccountId = cursor.getString(phoneAccountIdColumn); int features = cursor.getInt(featuresColumn); + String postDialDigits = cursor.getString(postDialDigitsColumn); ContentValues contentValues = new ContentValues(); contentValues.put(AnnotatedCallLog.TIMESTAMP, date); if (!TextUtils.isEmpty(numberAsStr)) { + String numberWithPostDialDigits = + postDialDigits == null ? numberAsStr : numberAsStr + postDialDigits; DialerPhoneNumber dialerPhoneNumber = - dialerPhoneNumberUtil.parse(numberAsStr, countryIso); + dialerPhoneNumberUtil.parse(numberWithPostDialDigits, countryIso); contentValues.put(AnnotatedCallLog.NUMBER, dialerPhoneNumber.toByteArray()); - contentValues.put( - AnnotatedCallLog.FORMATTED_NUMBER, - PhoneNumberUtils.formatNumber(numberAsStr, countryIso)); - // TODO(zachh): Need to handle post-dial digits; different on N and M. + String formattedNumber = + PhoneNumberUtils.formatNumber(numberWithPostDialDigits, countryIso); + if (formattedNumber == null) { + formattedNumber = numberWithPostDialDigits; + } + contentValues.put(AnnotatedCallLog.FORMATTED_NUMBER, formattedNumber); } else { contentValues.put( AnnotatedCallLog.NUMBER, DialerPhoneNumber.getDefaultInstance().toByteArray()); diff --git a/java/com/android/dialer/calllog/ui/menu/Modules.java b/java/com/android/dialer/calllog/ui/menu/Modules.java index fd0606ee0..67e51689d 100644 --- a/java/com/android/dialer/calllog/ui/menu/Modules.java +++ b/java/com/android/dialer/calllog/ui/menu/Modules.java @@ -130,17 +130,17 @@ final class Modules { if (!row.numberAttributes().getName().isEmpty()) { dialerContactBuilder.setNameOrNumber(row.numberAttributes().getName()); - } else if (!TextUtils.isEmpty(originalNumber)) { - dialerContactBuilder.setNameOrNumber(originalNumber); + if (row.formattedNumber() != null) { + dialerContactBuilder.setDisplayNumber(row.formattedNumber()); + } + } else if (!TextUtils.isEmpty(row.formattedNumber())) { + dialerContactBuilder.setNameOrNumber(row.formattedNumber()); } dialerContactBuilder.setNumberLabel(row.numberAttributes().getNumberTypeLabel()); dialerContactBuilder.setPhotoUri(row.numberAttributes().getPhotoUri()); dialerContactBuilder.setContactUri(row.numberAttributes().getLookupUri()); - if (row.formattedNumber() != null) { - dialerContactBuilder.setDisplayNumber(row.formattedNumber()); - } return dialerContactBuilder.build(); } } diff --git a/java/com/android/dialer/phonenumberproto/DialerPhoneNumberUtil.java b/java/com/android/dialer/phonenumberproto/DialerPhoneNumberUtil.java index d37f7fa1d..4e7d30031 100644 --- a/java/com/android/dialer/phonenumberproto/DialerPhoneNumberUtil.java +++ b/java/com/android/dialer/phonenumberproto/DialerPhoneNumberUtil.java @@ -103,9 +103,19 @@ public class DialerPhoneNumberUtil { } /** - * Returns true if the two numbers were parseable by libphonenumber and are a {@link - * MatchType#SHORT_NSN_MATCH} or {@link MatchType#NSN_MATCH} or {@link MatchType#EXACT_MATCH} or - * if they have the same raw input. + * Returns true if the two numbers: + * + * + * + *

If either number is not parseable, returns true if their raw inputs have the same network + * and post-dial portions. + * + *

An empty number is never considered to match another number. * * @see PhoneNumberUtil#isNumberMatch(PhoneNumber, PhoneNumber) */ @@ -115,15 +125,34 @@ public class DialerPhoneNumberUtil { Assert.isWorkerThread(); if (!Assert.isNotNull(firstNumberIn).hasDialerInternalPhoneNumber() || !Assert.isNotNull(secondNumberIn).hasDialerInternalPhoneNumber()) { - return firstNumberIn.getRawInput().equals(secondNumberIn.getRawInput()); + // An empty number should not be combined with any other number. + if (firstNumberIn.getRawInput().getNumber().isEmpty() + || secondNumberIn.getRawInput().getNumber().isEmpty()) { + return false; + } + // Both the network and post-dial portions of the number should match. + return sameNetworkPortion(firstNumberIn, secondNumberIn) + && samePostDialPortion(firstNumberIn, secondNumberIn); } MatchType matchType = isNumberMatch( firstNumberIn.getDialerInternalPhoneNumber(), secondNumberIn.getDialerInternalPhoneNumber()); - return matchType == MatchType.SHORT_NSN_MATCH - || matchType == MatchType.NSN_MATCH - || matchType == MatchType.EXACT_MATCH; + + return (matchType == MatchType.SHORT_NSN_MATCH + || matchType == MatchType.NSN_MATCH + || matchType == MatchType.EXACT_MATCH) + && samePostDialPortion(firstNumberIn, secondNumberIn); + } + + private static boolean sameNetworkPortion(DialerPhoneNumber number1, DialerPhoneNumber number2) { + return PhoneNumberUtils.extractNetworkPortion(number1.getRawInput().getNumber()) + .equals(PhoneNumberUtils.extractNetworkPortion(number2.getRawInput().getNumber())); + } + + private static boolean samePostDialPortion(DialerPhoneNumber number1, DialerPhoneNumber number2) { + return PhoneNumberUtils.extractPostDialPortion(number1.getRawInput().getNumber()) + .equals(PhoneNumberUtils.extractPostDialPortion(number2.getRawInput().getNumber())); } /** diff --git a/java/com/android/dialer/phonenumberproto/PartitionedNumbers.java b/java/com/android/dialer/phonenumberproto/PartitionedNumbers.java index 4c8ac2f21..0a4aafaf7 100644 --- a/java/com/android/dialer/phonenumberproto/PartitionedNumbers.java +++ b/java/com/android/dialer/phonenumberproto/PartitionedNumbers.java @@ -20,6 +20,7 @@ import android.support.annotation.NonNull; import android.support.annotation.WorkerThread; import android.support.v4.util.ArrayMap; import android.support.v4.util.ArraySet; +import android.telephony.PhoneNumberUtils; import com.android.dialer.DialerPhoneNumber; import com.android.dialer.common.Assert; import com.google.common.base.Optional; @@ -49,7 +50,18 @@ public final class PartitionedNumbers { for (DialerPhoneNumber dialerPhoneNumber : dialerPhoneNumbers) { Optional optValidE164 = dialerPhoneNumberUtil.formatToValidE164(dialerPhoneNumber); - if (optValidE164.isPresent()) { + /* + * Numbers with post-dial digits are considered valid and can be converted to E164, but their + * post dial digits are lost in the process. Similarly, if a contact's number has a post-dial + * digits, the normalized version of it stored in the contacts database does not include the + * post dial digits. + * + * A number with post-dial digits should not match a contact whose number does not have + * post-dial digits, which means that we cannot normalize such numbers for use in bulk lookup. + * Treat them as invalid which will cause them to be processed individually using + * ContactsContract.PHONE_LOOKUP. + */ + if (optValidE164.isPresent() && !hasPostDialDigits(dialerPhoneNumber)) { String validE164 = optValidE164.get(); Set currentNumbers = e164MapBuilder.get(validE164); if (currentNumbers == null) { @@ -72,6 +84,11 @@ public final class PartitionedNumbers { invalidNumbersToDialerPhoneNumbers = makeImmutable(invalidMapBuilder); } + private boolean hasPostDialDigits(DialerPhoneNumber dialerPhoneNumber) { + return !PhoneNumberUtils.extractPostDialPortion(dialerPhoneNumber.getRawInput().getNumber()) + .isEmpty(); + } + /** Returns the set of invalid numbers from the original DialerPhoneNumbers */ @NonNull public ImmutableSet invalidNumbers() { -- cgit v1.2.3