From 51f2b28ae6a45f57f94e5c9a66081a10aebc8349 Mon Sep 17 00:00:00 2001 From: zachh Date: Fri, 25 Aug 2017 12:19:07 -0700 Subject: Added partial UI to new call log. UI notes: -Updated view holder to show number and basic secondary text -Updated adapter to divide "Today" and "Older" entries -Photo is just an anonymous avatar for now -Clicking anywhere is a no-op Other things done in this CL: -Plumbed a few more columns through the call log framework -Tweaked some column names in the data model (contract) -Cleaned up some existing tests and added some new ones Screenshot: https://screenshot.googleplex.com/DiMscW47AYb This is the complete spec I am working from: https://screenshot.googleplex.com/XLquTek1oHk Bug: 34672501 Test: existing and new Change-Id: Ice0e538e23e59b7d752f47125a5f9da96bf91430 PiperOrigin-RevId: 166508997 --- .../datasources/contacts/ContactsDataSource.java | 4 +- .../systemcalllog/SystemCallLogDataSource.java | 69 +++++++++++++++++----- .../calllog/datasources/util/RowCombiner.java | 13 +++- 3 files changed, 67 insertions(+), 19 deletions(-) (limited to 'java/com/android/dialer/calllog/datasources') diff --git a/java/com/android/dialer/calllog/datasources/contacts/ContactsDataSource.java b/java/com/android/dialer/calllog/datasources/contacts/ContactsDataSource.java index ad824274e..8090cbc62 100644 --- a/java/com/android/dialer/calllog/datasources/contacts/ContactsDataSource.java +++ b/java/com/android/dialer/calllog/datasources/contacts/ContactsDataSource.java @@ -51,7 +51,7 @@ public final class ContactsDataSource implements CallLogDataSource { Assert.isWorkerThread(); // TODO(zachh): Implementation. for (ContentValues contentValues : mutations.getInserts().values()) { - contentValues.put(AnnotatedCallLog.PRIMARY_TEXT, "Placeholder name"); + contentValues.put(AnnotatedCallLog.NAME, "Placeholder name"); } } @@ -64,7 +64,7 @@ public final class ContactsDataSource implements CallLogDataSource { public ContentValues coalesce(List individualRowsSortedByTimestampDesc) { // TODO(zachh): Implementation. return new RowCombiner(individualRowsSortedByTimestampDesc) - .useSingleValueString(AnnotatedCallLog.PRIMARY_TEXT) + .useSingleValueString(AnnotatedCallLog.NAME) .combine(); } diff --git a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java index 94b908f8f..7bf2972c5 100644 --- a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java +++ b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java @@ -37,6 +37,7 @@ import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.text.TextUtils; import android.util.ArraySet; +import com.android.dialer.CallTypes; import com.android.dialer.DialerPhoneNumber; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.AnnotatedCallLog; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog; @@ -84,6 +85,7 @@ public class SystemCallLogDataSource implements CallLogDataSource { LogUtil.i("SystemCallLogDataSource.registerContentObservers", "no call log permissions"); return; } + // TODO(zachh): Need to somehow register observers if user enables permission after launch? appContext .getContentResolver() @@ -104,8 +106,11 @@ public class SystemCallLogDataSource implements CallLogDataSource { * column is unused). This means that we can't detect deletes without scanning the entire table, * which would be too slow. So, we just rely on content observers to trigger rebuilds when any * change is made to the system call log. + * + * Just return false unless the table has never been written to. */ - return false; + return !PreferenceManager.getDefaultSharedPreferences(appContext) + .contains(PREF_LAST_TIMESTAMP_PROCESSED); } @WorkerThread @@ -152,23 +157,41 @@ public class SystemCallLogDataSource implements CallLogDataSource { ContentValues coalescedValues = new RowCombiner(individualRowsSortedByTimestampDesc) .useMostRecentLong(AnnotatedCallLog.TIMESTAMP) + .useMostRecentLong(AnnotatedCallLog.NEW) + .useMostRecentString(AnnotatedCallLog.NUMBER_TYPE_LABEL) + .useMostRecentString(AnnotatedCallLog.GEOCODED_LOCATION) .combine(); // All phone numbers in the provided group should be equivalent (but could be formatted // differently). Arbitrarily show the raw phone number of the most recent call. DialerPhoneNumber mostRecentPhoneNumber = getMostRecentPhoneNumber(individualRowsSortedByTimestampDesc); - coalescedValues.put( - CoalescedAnnotatedCallLog.FORMATTED_NUMBER, - mostRecentPhoneNumber.getRawInput().getNumber()); + if (mostRecentPhoneNumber != null) { + coalescedValues.put( + CoalescedAnnotatedCallLog.FORMATTED_NUMBER, + mostRecentPhoneNumber.getRawInput().getNumber()); + } + + CallTypes.Builder callTypes = CallTypes.newBuilder(); + // Store a maximum of 3 call types since that's all we show to users via icons. + for (int i = 0; i < 3 && i < individualRowsSortedByTimestampDesc.size(); i++) { + callTypes.addType( + individualRowsSortedByTimestampDesc.get(i).getAsInteger(AnnotatedCallLog.TYPE)); + } + coalescedValues.put(CoalescedAnnotatedCallLog.CALL_TYPES, callTypes.build().toByteArray()); + return coalescedValues; } + @Nullable private static DialerPhoneNumber getMostRecentPhoneNumber( List individualRowsSortedByTimestampDesc) { - DialerPhoneNumber dialerPhoneNumber; byte[] protoBytes = individualRowsSortedByTimestampDesc.get(0).getAsByteArray(AnnotatedCallLog.NUMBER); + if (protoBytes == null) { + return null; + } + DialerPhoneNumber dialerPhoneNumber; try { dialerPhoneNumber = DialerPhoneNumber.parseFrom(protoBytes); } catch (InvalidProtocolBufferException e) { @@ -198,10 +221,12 @@ public class SystemCallLogDataSource implements CallLogDataSource { Calls.DATE, Calls.LAST_MODIFIED, Calls.NUMBER, + Calls.TYPE, Calls.COUNTRY_ISO, Calls.CACHED_NUMBER_TYPE, Calls.CACHED_NUMBER_LABEL, Calls.IS_READ, + Calls.NEW, Calls.GEOCODED_LOCATION, Calls.PHONE_ACCOUNT_COMPONENT_NAME, Calls.PHONE_ACCOUNT_ID, @@ -226,10 +251,12 @@ public class SystemCallLogDataSource implements CallLogDataSource { int dateColumn = cursor.getColumnIndexOrThrow(Calls.DATE); int lastModifiedColumn = cursor.getColumnIndexOrThrow(Calls.LAST_MODIFIED); int numberColumn = cursor.getColumnIndexOrThrow(Calls.NUMBER); + int typeColumn = cursor.getColumnIndexOrThrow(Calls.TYPE); int countryIsoColumn = cursor.getColumnIndexOrThrow(Calls.COUNTRY_ISO); int cachedNumberTypeColumn = cursor.getColumnIndexOrThrow(Calls.CACHED_NUMBER_TYPE); int cachedNumberLabelColumn = cursor.getColumnIndexOrThrow(Calls.CACHED_NUMBER_LABEL); int isReadColumn = cursor.getColumnIndexOrThrow(Calls.IS_READ); + int newColumn = cursor.getColumnIndexOrThrow(Calls.NEW); int geocodedLocationColumn = cursor.getColumnIndexOrThrow(Calls.GEOCODED_LOCATION); int phoneAccountComponentColumn = cursor.getColumnIndexOrThrow(Calls.PHONE_ACCOUNT_COMPONENT_NAME); @@ -243,30 +270,40 @@ public class SystemCallLogDataSource implements CallLogDataSource { long id = cursor.getLong(idColumn); long date = cursor.getLong(dateColumn); String numberAsStr = cursor.getString(numberColumn); + long type = cursor.getType(typeColumn); String countryIso = cursor.getString(countryIsoColumn); // TODO(zachh): Decide if should use "cached" columns from call log or recompute. int cachedNumberType = cursor.getInt(cachedNumberTypeColumn); String cachedNumberLabel = cursor.getString(cachedNumberLabelColumn); int isRead = cursor.getInt(isReadColumn); + int isNew = cursor.getInt(newColumn); String geocodedLocation = cursor.getString(geocodedLocationColumn); String phoneAccountComponentName = cursor.getString(phoneAccountComponentColumn); String phoneAccountId = cursor.getString(phoneAccountIdColumn); int features = cursor.getInt(featuresColumn); - byte[] numberAsProtoBytes = - dialerPhoneNumberUtil.parse(numberAsStr, countryIso).toByteArray(); - ContentValues contentValues = new ContentValues(); contentValues.put(AnnotatedCallLog.TIMESTAMP, date); - // TODO(zachh): Need to handle post-dial digits; different on N and M. - contentValues.put(AnnotatedCallLog.NUMBER, numberAsProtoBytes); - - // TODO(zachh): Test this for locales. - contentValues.put( - AnnotatedCallLog.NUMBER_TYPE_LABEL, - Phone.getTypeLabel(appContext.getResources(), cachedNumberType, cachedNumberLabel) - .toString()); + + if (!TextUtils.isEmpty(numberAsStr)) { + byte[] numberAsProtoBytes = + dialerPhoneNumberUtil.parse(numberAsStr, countryIso).toByteArray(); + // TODO(zachh): Need to handle post-dial digits; different on N and M. + contentValues.put(AnnotatedCallLog.NUMBER, numberAsProtoBytes); + } + + contentValues.put(AnnotatedCallLog.TYPE, type); + + // Phone.getTypeLabel returns "Custom" if given (0, null) which is not of any use. Just + // omit setting the label if there's no information for it. + if (cachedNumberType != 0 || cachedNumberLabel != null) { + contentValues.put( + AnnotatedCallLog.NUMBER_TYPE_LABEL, + Phone.getTypeLabel(appContext.getResources(), cachedNumberType, cachedNumberLabel) + .toString()); + } contentValues.put(AnnotatedCallLog.IS_READ, isRead); + contentValues.put(AnnotatedCallLog.NEW, isNew); contentValues.put(AnnotatedCallLog.GEOCODED_LOCATION, geocodedLocation); populatePhoneAccountLabelAndColor( appContext, contentValues, phoneAccountComponentName, phoneAccountId); diff --git a/java/com/android/dialer/calllog/datasources/util/RowCombiner.java b/java/com/android/dialer/calllog/datasources/util/RowCombiner.java index 0c7be1e27..3595a055d 100644 --- a/java/com/android/dialer/calllog/datasources/util/RowCombiner.java +++ b/java/com/android/dialer/calllog/datasources/util/RowCombiner.java @@ -36,12 +36,23 @@ public class RowCombiner { return this; } + /** Use the most recent value for the specified column. */ + public RowCombiner useMostRecentString(String columnName) { + combinedRow.put(columnName, individualRowsSortedByTimestampDesc.get(0).getAsString(columnName)); + return this; + } + /** Asserts that all column values for the given column name are the same, and uses it. */ public RowCombiner useSingleValueString(String columnName) { Iterator iterator = individualRowsSortedByTimestampDesc.iterator(); String singleValue = iterator.next().getAsString(columnName); while (iterator.hasNext()) { - Assert.checkState(iterator.next().getAsString(columnName).equals(singleValue)); + String current = iterator.next().getAsString(columnName); + if (current == null) { + Assert.checkState(singleValue == null); + } else { + Assert.checkState(current.equals(singleValue)); + } } combinedRow.put(columnName, singleValue); return this; -- cgit v1.2.3