summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/calllog/database
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/dialer/calllog/database')
-rw-r--r--java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java50
-rw-r--r--java/com/android/dialer/calllog/database/Coalescer.java151
-rw-r--r--java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java12
3 files changed, 144 insertions, 69 deletions
diff --git a/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java b/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
index 7fc474a98..3ca76ee23 100644
--- a/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
+++ b/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
@@ -29,16 +29,12 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Build;
-import android.provider.CallLog.Calls;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract;
import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.AnnotatedCallLog;
-import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
-import com.android.dialer.metrics.Metrics;
-import com.android.dialer.metrics.MetricsComponent;
import java.util.ArrayList;
import java.util.Arrays;
@@ -50,7 +46,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
private static final int ANNOTATED_CALL_LOG_TABLE_CODE = 1;
private static final int ANNOTATED_CALL_LOG_TABLE_ID_CODE = 2;
private static final int ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE = 3;
- private static final int COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE = 4;
private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
@@ -65,10 +60,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
AnnotatedCallLogContract.AUTHORITY,
AnnotatedCallLog.DISTINCT_PHONE_NUMBERS,
ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE);
- uriMatcher.addURI(
- AnnotatedCallLogContract.AUTHORITY,
- CoalescedAnnotatedCallLog.TABLE,
- COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE);
}
private AnnotatedCallLogDatabaseHelper databaseHelper;
@@ -142,33 +133,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
LogUtil.w("AnnotatedCallLogContentProvider.query", "cursor was null");
}
return cursor;
- case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE:
- Assert.checkArgument(
- projection == CoalescedAnnotatedCallLog.ALL_COLUMNS,
- "only ALL_COLUMNS projection supported for coalesced call log");
- Assert.checkArgument(selection == null, "selection not supported for coalesced call log");
- Assert.checkArgument(
- selectionArgs == null, "selection args not supported for coalesced call log");
- Assert.checkArgument(sortOrder == null, "sort order not supported for coalesced call log");
- MetricsComponent.get(getContext()).metrics().startTimer(Metrics.NEW_CALL_LOG_COALESCE);
- try (Cursor allAnnotatedCallLogRows =
- queryBuilder.query(
- db,
- null,
- String.format("%s != ?", CoalescedAnnotatedCallLog.CALL_TYPE),
- new String[] {Integer.toString(Calls.VOICEMAIL_TYPE)},
- null,
- null,
- AnnotatedCallLog.TIMESTAMP + " DESC")) {
- Cursor coalescedRows =
- CallLogDatabaseComponent.get(getContext())
- .coalescer()
- .coalesce(allAnnotatedCallLogRows);
- coalescedRows.setNotificationUri(
- getContext().getContentResolver(), CoalescedAnnotatedCallLog.CONTENT_URI);
- MetricsComponent.get(getContext()).metrics().stopTimer(Metrics.NEW_CALL_LOG_COALESCE);
- return coalescedRows;
- }
default:
throw new IllegalArgumentException("Unknown uri: " + uri);
}
@@ -207,8 +171,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
break;
case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE:
throw new UnsupportedOperationException();
- case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE:
- throw new UnsupportedOperationException("coalesced call log does not support inserting");
default:
throw new IllegalArgumentException("Unknown uri: " + uri);
}
@@ -245,8 +207,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
break;
case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE:
throw new UnsupportedOperationException();
- case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE:
- throw new UnsupportedOperationException("coalesced call log does not support deleting");
default:
throw new IllegalArgumentException("Unknown uri: " + uri);
}
@@ -300,7 +260,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
}
return rows;
case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE:
- case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE:
throw new UnsupportedOperationException();
default:
throw new IllegalArgumentException("Unknown uri: " + uri);
@@ -336,9 +295,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
break;
case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE:
throw new UnsupportedOperationException();
- case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE:
- throw new UnsupportedOperationException(
- "coalesced call log does not support applyBatch");
default:
throw new IllegalArgumentException("Unknown uri: " + operation.getUri());
}
@@ -380,10 +336,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
}
private void notifyChange(Uri uri) {
- getContext().getContentResolver().notifyChange(uri, null);
- // Any time the annotated call log changes, we need to also notify observers of the
- // CoalescedAnnotatedCallLog, since that is just a massaged in-memory view of the real annotated
- // call log table.
- getContext().getContentResolver().notifyChange(CoalescedAnnotatedCallLog.CONTENT_URI, null);
+ getContext().getContentResolver().notifyChange(uri, /* observer = */ null);
}
}
diff --git a/java/com/android/dialer/calllog/database/Coalescer.java b/java/com/android/dialer/calllog/database/Coalescer.java
index 8a16be2da..a889b9fe6 100644
--- a/java/com/android/dialer/calllog/database/Coalescer.java
+++ b/java/com/android/dialer/calllog/database/Coalescer.java
@@ -22,17 +22,25 @@ import android.provider.CallLog.Calls;
import android.support.annotation.NonNull;
import android.support.annotation.WorkerThread;
import android.telecom.PhoneAccountHandle;
+import android.text.TextUtils;
import com.android.dialer.CoalescedIds;
import com.android.dialer.DialerPhoneNumber;
+import com.android.dialer.NumberAttributes;
import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.AnnotatedCallLog;
import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog;
import com.android.dialer.calllog.datasources.CallLogDataSource;
import com.android.dialer.calllog.datasources.DataSources;
+import com.android.dialer.calllog.model.CoalescedRow;
import com.android.dialer.common.Assert;
+import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor;
import com.android.dialer.compat.telephony.TelephonyManagerCompat;
+import com.android.dialer.metrics.FutureTimer;
+import com.android.dialer.metrics.Metrics;
import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil;
import com.android.dialer.telecom.TelecomUtil;
import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.protobuf.InvalidProtocolBufferException;
import java.util.ArrayList;
import java.util.List;
@@ -41,32 +49,76 @@ import java.util.Objects;
import javax.inject.Inject;
/**
- * Coalesces call log rows by combining some adjacent rows.
+ * Coalesces rows in {@link AnnotatedCallLog} by combining adjacent rows.
*
* <p>Applies the logic that determines which adjacent rows should be coalesced, and then delegates
* to each data source to determine how individual columns should be aggregated.
*/
public class Coalescer {
+
+ // Indexes for CoalescedAnnotatedCallLog.ALL_COLUMNS
+ private static final int ID = 0;
+ private static final int TIMESTAMP = 1;
+ private static final int NUMBER = 2;
+ private static final int FORMATTED_NUMBER = 3;
+ private static final int NUMBER_PRESENTATION = 4;
+ private static final int IS_READ = 5;
+ private static final int NEW = 6;
+ private static final int GEOCODED_LOCATION = 7;
+ private static final int PHONE_ACCOUNT_COMPONENT_NAME = 8;
+ private static final int PHONE_ACCOUNT_ID = 9;
+ private static final int FEATURES = 10;
+ private static final int NUMBER_ATTRIBUTES = 11;
+ private static final int IS_VOICEMAIL_CALL = 12;
+ private static final int VOICEMAIL_CALL_TAG = 13;
+ private static final int CALL_TYPE = 14;
+ private static final int COALESCED_IDS = 15;
+
private final DataSources dataSources;
+ private final FutureTimer futureTimer;
+ private final ListeningExecutorService backgroundExecutorService;
@Inject
- Coalescer(DataSources dataSources) {
+ Coalescer(
+ @BackgroundExecutor ListeningExecutorService backgroundExecutorService,
+ DataSources dataSources,
+ FutureTimer futureTimer) {
+ this.backgroundExecutorService = backgroundExecutorService;
this.dataSources = dataSources;
+ this.futureTimer = futureTimer;
+ }
+
+ /**
+ * Given rows from {@link AnnotatedCallLog}, combine adjacent ones which should be collapsed for
+ * display purposes.
+ *
+ * @param allAnnotatedCallLogRowsSortedByTimestampDesc {@link AnnotatedCallLog} rows sorted in
+ * descending order of timestamp.
+ * @return a future of a {@link MatrixCursor} containing the {@link CoalescedAnnotatedCallLog}
+ * rows to display
+ */
+ public ListenableFuture<Cursor> coalesce(
+ @NonNull Cursor allAnnotatedCallLogRowsSortedByTimestampDesc) {
+ ListenableFuture<Cursor> coalescingFuture =
+ backgroundExecutorService.submit(
+ () -> coalesceInternal(Assert.isNotNull(allAnnotatedCallLogRowsSortedByTimestampDesc)));
+ futureTimer.applyTiming(coalescingFuture, Metrics.NEW_CALL_LOG_COALESCE);
+ return coalescingFuture;
}
/**
- * Reads the entire {@link AnnotatedCallLog} database into memory from the provided {@code
- * allAnnotatedCallLog} parameter and then builds and returns a new {@link MatrixCursor} which is
- * the result of combining adjacent rows which should be collapsed for display purposes.
+ * Reads the entire {@link AnnotatedCallLog} into memory from the provided cursor and then builds
+ * and returns a new {@link MatrixCursor} of {@link CoalescedAnnotatedCallLog}, which is the
+ * result of combining adjacent rows which should be collapsed for display purposes.
*
- * @param allAnnotatedCallLogRowsSortedByTimestampDesc all {@link AnnotatedCallLog} rows, sorted
- * by timestamp descending
+ * @param allAnnotatedCallLogRowsSortedByTimestampDesc {@link AnnotatedCallLog} rows sorted in
+ * descending order of timestamp.
* @return a new {@link MatrixCursor} containing the {@link CoalescedAnnotatedCallLog} rows to
* display
*/
@WorkerThread
@NonNull
- Cursor coalesce(@NonNull Cursor allAnnotatedCallLogRowsSortedByTimestampDesc) {
+ private Cursor coalesceInternal(Cursor allAnnotatedCallLogRowsSortedByTimestampDesc) {
Assert.isWorkerThread();
// Note: This method relies on rowsShouldBeCombined to determine which rows should be combined,
@@ -77,7 +129,7 @@ public class Coalescer {
MatrixCursor allCoalescedRowsMatrixCursor =
new MatrixCursor(
CoalescedAnnotatedCallLog.ALL_COLUMNS,
- Assert.isNotNull(allAnnotatedCallLogRowsSortedByTimestampDesc).getCount());
+ allAnnotatedCallLogRowsSortedByTimestampDesc.getCount());
if (!allAnnotatedCallLogRowsSortedByTimestampDesc.moveToFirst()) {
return allCoalescedRowsMatrixCursor;
@@ -252,4 +304,85 @@ public class Coalescer {
rowBuilder.add(entry.getKey(), entry.getValue());
}
}
+
+ /**
+ * Creates a new {@link CoalescedRow} based on the data at the provided cursor's current position.
+ *
+ * <p>The provided cursor should be one for {@link CoalescedAnnotatedCallLog}.
+ */
+ public static CoalescedRow toRow(Cursor coalescedAnnotatedCallLogCursor) {
+ DialerPhoneNumber number;
+ try {
+ number = DialerPhoneNumber.parseFrom(coalescedAnnotatedCallLogCursor.getBlob(NUMBER));
+ } catch (InvalidProtocolBufferException e) {
+ throw new IllegalStateException("Couldn't parse DialerPhoneNumber bytes");
+ }
+
+ CoalescedIds coalescedIds;
+ try {
+ coalescedIds = CoalescedIds.parseFrom(coalescedAnnotatedCallLogCursor.getBlob(COALESCED_IDS));
+ } catch (InvalidProtocolBufferException e) {
+ throw new IllegalStateException("Couldn't parse CoalescedIds bytes");
+ }
+
+ NumberAttributes numberAttributes;
+ try {
+ numberAttributes =
+ NumberAttributes.parseFrom(coalescedAnnotatedCallLogCursor.getBlob(NUMBER_ATTRIBUTES));
+ } catch (InvalidProtocolBufferException e) {
+ throw new IllegalStateException("Couldn't parse NumberAttributes bytes");
+ }
+
+ CoalescedRow.Builder coalescedRowBuilder =
+ CoalescedRow.newBuilder()
+ .setId(coalescedAnnotatedCallLogCursor.getLong(ID))
+ .setTimestamp(coalescedAnnotatedCallLogCursor.getLong(TIMESTAMP))
+ .setNumber(number)
+ .setNumberPresentation(coalescedAnnotatedCallLogCursor.getInt(NUMBER_PRESENTATION))
+ .setIsRead(coalescedAnnotatedCallLogCursor.getInt(IS_READ) == 1)
+ .setIsNew(coalescedAnnotatedCallLogCursor.getInt(NEW) == 1)
+ .setFeatures(coalescedAnnotatedCallLogCursor.getInt(FEATURES))
+ .setCallType(coalescedAnnotatedCallLogCursor.getInt(CALL_TYPE))
+ .setNumberAttributes(numberAttributes)
+ .setIsVoicemailCall(coalescedAnnotatedCallLogCursor.getInt(IS_VOICEMAIL_CALL) == 1)
+ .setCoalescedIds(coalescedIds);
+
+ String formattedNumber = coalescedAnnotatedCallLogCursor.getString(FORMATTED_NUMBER);
+ if (!TextUtils.isEmpty(formattedNumber)) {
+ coalescedRowBuilder.setFormattedNumber(formattedNumber);
+ }
+
+ String geocodedLocation = coalescedAnnotatedCallLogCursor.getString(GEOCODED_LOCATION);
+ if (!TextUtils.isEmpty(geocodedLocation)) {
+ coalescedRowBuilder.setGeocodedLocation(geocodedLocation);
+ }
+
+ String phoneAccountComponentName =
+ coalescedAnnotatedCallLogCursor.getString(PHONE_ACCOUNT_COMPONENT_NAME);
+ if (!TextUtils.isEmpty(phoneAccountComponentName)) {
+ coalescedRowBuilder.setPhoneAccountComponentName(
+ coalescedAnnotatedCallLogCursor.getString(PHONE_ACCOUNT_COMPONENT_NAME));
+ }
+
+ String phoneAccountId = coalescedAnnotatedCallLogCursor.getString(PHONE_ACCOUNT_ID);
+ if (!TextUtils.isEmpty(phoneAccountId)) {
+ coalescedRowBuilder.setPhoneAccountId(phoneAccountId);
+ }
+
+ String voicemailCallTag = coalescedAnnotatedCallLogCursor.getString(VOICEMAIL_CALL_TAG);
+ if (!TextUtils.isEmpty(voicemailCallTag)) {
+ coalescedRowBuilder.setVoicemailCallTag(voicemailCallTag);
+ }
+
+ return coalescedRowBuilder.build();
+ }
+
+ /**
+ * Returns the timestamp at the provided cursor's current position.
+ *
+ * <p>The provided cursor should be one for {@link CoalescedAnnotatedCallLog}.
+ */
+ public static long getTimestamp(Cursor coalescedAnnotatedCallLogCursor) {
+ return coalescedAnnotatedCallLogCursor.getLong(TIMESTAMP);
+ }
}
diff --git a/java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java b/java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java
index ee888d196..8ca151c64 100644
--- a/java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java
+++ b/java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java
@@ -225,7 +225,7 @@ public class AnnotatedCallLogContract {
/**
* An unique id to associate this call log row to a {@link android.telecom.Call}.
*
- * <p>For pre-Q device, this is same as {@link TIMESTAMP}.
+ * <p>For pre-Q device, this is same as {@link #TIMESTAMP}.
*
* <p>For Q+ device, this will be copied from {@link android.provider.CallLog.Calls}.
*
@@ -244,16 +244,6 @@ public class AnnotatedCallLogContract {
*/
public static final class CoalescedAnnotatedCallLog implements CommonColumns {
- public static final String TABLE = "CoalescedAnnotatedCallLog";
-
- /** The content URI for this table. */
- public static final Uri CONTENT_URI =
- Uri.withAppendedPath(AnnotatedCallLogContract.CONTENT_URI, TABLE);
-
- /** The MIME type of a {@link android.content.ContentProvider#getType(Uri)} single entry. */
- public static final String CONTENT_ITEM_TYPE =
- "vnd.android.cursor.item/coalesced_annotated_call_log";
-
/**
* IDs of rows in {@link AnnotatedCallLog} that are coalesced into one row in {@link
* CoalescedAnnotatedCallLog}, encoded as a {@link com.android.dialer.CoalescedIds} proto.