Loading java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java +1 −49 Original line number Original line Diff line number Diff line Loading @@ -29,16 +29,12 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.net.Uri; import android.os.Build; import android.os.Build; import android.provider.CallLog.Calls; import android.support.annotation.NonNull; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.Nullable; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract; 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.AnnotatedCallLog; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog; import com.android.dialer.common.Assert; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; 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.ArrayList; import java.util.Arrays; import java.util.Arrays; Loading @@ -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_CODE = 1; private static final int ANNOTATED_CALL_LOG_TABLE_ID_CODE = 2; 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 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); private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); Loading @@ -65,10 +60,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { AnnotatedCallLogContract.AUTHORITY, AnnotatedCallLogContract.AUTHORITY, AnnotatedCallLog.DISTINCT_PHONE_NUMBERS, AnnotatedCallLog.DISTINCT_PHONE_NUMBERS, ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE); ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE); uriMatcher.addURI( AnnotatedCallLogContract.AUTHORITY, CoalescedAnnotatedCallLog.TABLE, COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE); } } private AnnotatedCallLogDatabaseHelper databaseHelper; private AnnotatedCallLogDatabaseHelper databaseHelper; Loading Loading @@ -142,33 +133,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { LogUtil.w("AnnotatedCallLogContentProvider.query", "cursor was null"); LogUtil.w("AnnotatedCallLogContentProvider.query", "cursor was null"); } } return cursor; 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: default: throw new IllegalArgumentException("Unknown uri: " + uri); throw new IllegalArgumentException("Unknown uri: " + uri); } } Loading Loading @@ -207,8 +171,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { break; break; case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: throw new UnsupportedOperationException(); throw new UnsupportedOperationException(); case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE: throw new UnsupportedOperationException("coalesced call log does not support inserting"); default: default: throw new IllegalArgumentException("Unknown uri: " + uri); throw new IllegalArgumentException("Unknown uri: " + uri); } } Loading Loading @@ -245,8 +207,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { break; break; case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: throw new UnsupportedOperationException(); throw new UnsupportedOperationException(); case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE: throw new UnsupportedOperationException("coalesced call log does not support deleting"); default: default: throw new IllegalArgumentException("Unknown uri: " + uri); throw new IllegalArgumentException("Unknown uri: " + uri); } } Loading Loading @@ -300,7 +260,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { } } return rows; return rows; case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE: throw new UnsupportedOperationException(); throw new UnsupportedOperationException(); default: default: throw new IllegalArgumentException("Unknown uri: " + uri); throw new IllegalArgumentException("Unknown uri: " + uri); Loading Loading @@ -336,9 +295,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { break; break; case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: throw new UnsupportedOperationException(); throw new UnsupportedOperationException(); case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE: throw new UnsupportedOperationException( "coalesced call log does not support applyBatch"); default: default: throw new IllegalArgumentException("Unknown uri: " + operation.getUri()); throw new IllegalArgumentException("Unknown uri: " + operation.getUri()); } } Loading Loading @@ -380,10 +336,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { } } private void notifyChange(Uri uri) { private void notifyChange(Uri uri) { getContext().getContentResolver().notifyChange(uri, null); getContext().getContentResolver().notifyChange(uri, /* observer = */ 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); } } } } java/com/android/dialer/calllog/database/Coalescer.java +142 −9 Original line number Original line Diff line number Diff line Loading @@ -22,17 +22,25 @@ import android.provider.CallLog.Calls; import android.support.annotation.NonNull; import android.support.annotation.NonNull; import android.support.annotation.WorkerThread; import android.support.annotation.WorkerThread; import android.telecom.PhoneAccountHandle; import android.telecom.PhoneAccountHandle; import android.text.TextUtils; import com.android.dialer.CoalescedIds; import com.android.dialer.CoalescedIds; import com.android.dialer.DialerPhoneNumber; 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.AnnotatedCallLog; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog; import com.android.dialer.calllog.datasources.CallLogDataSource; import com.android.dialer.calllog.datasources.CallLogDataSource; import com.android.dialer.calllog.datasources.DataSources; 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.Assert; import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor; import com.android.dialer.compat.telephony.TelephonyManagerCompat; 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.phonenumberproto.DialerPhoneNumberUtil; import com.android.dialer.telecom.TelecomUtil; import com.android.dialer.telecom.TelecomUtil; import com.google.common.base.Preconditions; 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 com.google.protobuf.InvalidProtocolBufferException; import java.util.ArrayList; import java.util.ArrayList; import java.util.List; import java.util.List; Loading @@ -41,32 +49,76 @@ import java.util.Objects; import javax.inject.Inject; 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 * <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. * to each data source to determine how individual columns should be aggregated. */ */ public class Coalescer { 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 DataSources dataSources; private final FutureTimer futureTimer; private final ListeningExecutorService backgroundExecutorService; @Inject @Inject Coalescer(DataSources dataSources) { Coalescer( @BackgroundExecutor ListeningExecutorService backgroundExecutorService, DataSources dataSources, FutureTimer futureTimer) { this.backgroundExecutorService = backgroundExecutorService; this.dataSources = dataSources; 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 * Reads the entire {@link AnnotatedCallLog} into memory from the provided cursor and then builds * allAnnotatedCallLog} parameter and then builds and returns a new {@link MatrixCursor} which is * and returns a new {@link MatrixCursor} of {@link CoalescedAnnotatedCallLog}, which is the * the result of combining adjacent rows which should be collapsed for display purposes. * result of combining adjacent rows which should be collapsed for display purposes. * * * @param allAnnotatedCallLogRowsSortedByTimestampDesc all {@link AnnotatedCallLog} rows, sorted * @param allAnnotatedCallLogRowsSortedByTimestampDesc {@link AnnotatedCallLog} rows sorted in * by timestamp descending * descending order of timestamp. * @return a new {@link MatrixCursor} containing the {@link CoalescedAnnotatedCallLog} rows to * @return a new {@link MatrixCursor} containing the {@link CoalescedAnnotatedCallLog} rows to * display * display */ */ @WorkerThread @WorkerThread @NonNull @NonNull Cursor coalesce(@NonNull Cursor allAnnotatedCallLogRowsSortedByTimestampDesc) { private Cursor coalesceInternal(Cursor allAnnotatedCallLogRowsSortedByTimestampDesc) { Assert.isWorkerThread(); Assert.isWorkerThread(); // Note: This method relies on rowsShouldBeCombined to determine which rows should be combined, // Note: This method relies on rowsShouldBeCombined to determine which rows should be combined, Loading @@ -77,7 +129,7 @@ public class Coalescer { MatrixCursor allCoalescedRowsMatrixCursor = MatrixCursor allCoalescedRowsMatrixCursor = new MatrixCursor( new MatrixCursor( CoalescedAnnotatedCallLog.ALL_COLUMNS, CoalescedAnnotatedCallLog.ALL_COLUMNS, Assert.isNotNull(allAnnotatedCallLogRowsSortedByTimestampDesc).getCount()); allAnnotatedCallLogRowsSortedByTimestampDesc.getCount()); if (!allAnnotatedCallLogRowsSortedByTimestampDesc.moveToFirst()) { if (!allAnnotatedCallLogRowsSortedByTimestampDesc.moveToFirst()) { return allCoalescedRowsMatrixCursor; return allCoalescedRowsMatrixCursor; Loading Loading @@ -252,4 +304,85 @@ public class Coalescer { rowBuilder.add(entry.getKey(), entry.getValue()); 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); } } } java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java +1 −11 Original line number Original line Diff line number Diff line Loading @@ -225,7 +225,7 @@ public class AnnotatedCallLogContract { /** /** * An unique id to associate this call log row to a {@link android.telecom.Call}. * 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}. * <p>For Q+ device, this will be copied from {@link android.provider.CallLog.Calls}. * * Loading @@ -244,16 +244,6 @@ public class AnnotatedCallLogContract { */ */ public static final class CoalescedAnnotatedCallLog implements CommonColumns { 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 * IDs of rows in {@link AnnotatedCallLog} that are coalesced into one row in {@link * CoalescedAnnotatedCallLog}, encoded as a {@link com.android.dialer.CoalescedIds} proto. * CoalescedAnnotatedCallLog}, encoded as a {@link com.android.dialer.CoalescedIds} proto. Loading java/com/android/dialer/calllog/ui/AnnotatedCallLogCursorLoader.java 0 → 100644 +36 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.dialer.calllog.ui; import android.content.Context; import android.provider.CallLog.Calls; import android.support.v4.content.CursorLoader; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.AnnotatedCallLog; /** Cursor loader for {@link AnnotatedCallLog}. */ final class AnnotatedCallLogCursorLoader extends CursorLoader { AnnotatedCallLogCursorLoader(Context context) { super( context, AnnotatedCallLog.CONTENT_URI, /* projection = */ null, /* selection = */ AnnotatedCallLog.CALL_TYPE + " != ?", /* selectionArgs = */ new String[] {Integer.toString(Calls.VOICEMAIL_TYPE)}, /* sortOrder = */ AnnotatedCallLog.TIMESTAMP + " DESC"); } } java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.javadeleted 100644 → 0 +0 −132 Original line number Original line Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.dialer.calllog.ui; import android.content.Context; import android.database.Cursor; import android.support.v4.content.CursorLoader; 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.CoalescedAnnotatedCallLog; import com.android.dialer.calllog.model.CoalescedRow; import com.google.protobuf.InvalidProtocolBufferException; /** CursorLoader for the coalesced annotated call log. */ final class CoalescedAnnotatedCallLogCursorLoader extends CursorLoader { // 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; CoalescedAnnotatedCallLogCursorLoader(Context context) { // CoalescedAnnotatedCallLog requires that PROJECTION be ALL_COLUMNS and the following params be // null. super( context, CoalescedAnnotatedCallLog.CONTENT_URI, CoalescedAnnotatedCallLog.ALL_COLUMNS, null, null, null); } /** Creates a new {@link CoalescedRow} from the provided cursor using the current position. */ static CoalescedRow toRow(Cursor cursor) { DialerPhoneNumber number; try { number = DialerPhoneNumber.parseFrom(cursor.getBlob(NUMBER)); } catch (InvalidProtocolBufferException e) { throw new IllegalStateException("Couldn't parse DialerPhoneNumber bytes"); } CoalescedIds coalescedIds; try { coalescedIds = CoalescedIds.parseFrom(cursor.getBlob(COALESCED_IDS)); } catch (InvalidProtocolBufferException e) { throw new IllegalStateException("Couldn't parse CoalescedIds bytes"); } NumberAttributes numberAttributes; try { numberAttributes = NumberAttributes.parseFrom(cursor.getBlob(NUMBER_ATTRIBUTES)); } catch (InvalidProtocolBufferException e) { throw new IllegalStateException("Couldn't parse NumberAttributes bytes"); } CoalescedRow.Builder coalescedRowBuilder = CoalescedRow.newBuilder() .setId(cursor.getLong(ID)) .setTimestamp(cursor.getLong(TIMESTAMP)) .setNumber(number) .setNumberPresentation(cursor.getInt(NUMBER_PRESENTATION)) .setIsRead(cursor.getInt(IS_READ) == 1) .setIsNew(cursor.getInt(NEW) == 1) .setFeatures(cursor.getInt(FEATURES)) .setCallType(cursor.getInt(CALL_TYPE)) .setNumberAttributes(numberAttributes) .setIsVoicemailCall(cursor.getInt(IS_VOICEMAIL_CALL) == 1) .setCoalescedIds(coalescedIds); String formattedNumber = cursor.getString(FORMATTED_NUMBER); if (!TextUtils.isEmpty(formattedNumber)) { coalescedRowBuilder.setFormattedNumber(formattedNumber); } String geocodedLocation = cursor.getString(GEOCODED_LOCATION); if (!TextUtils.isEmpty(geocodedLocation)) { coalescedRowBuilder.setGeocodedLocation(geocodedLocation); } String phoneAccountComponentName = cursor.getString(PHONE_ACCOUNT_COMPONENT_NAME); if (!TextUtils.isEmpty(phoneAccountComponentName)) { coalescedRowBuilder.setPhoneAccountComponentName( cursor.getString(PHONE_ACCOUNT_COMPONENT_NAME)); } String phoneAccountId = cursor.getString(PHONE_ACCOUNT_ID); if (!TextUtils.isEmpty(phoneAccountId)) { coalescedRowBuilder.setPhoneAccountId(phoneAccountId); } String voicemailCallTag = cursor.getString(VOICEMAIL_CALL_TAG); if (!TextUtils.isEmpty(voicemailCallTag)) { coalescedRowBuilder.setVoicemailCallTag(voicemailCallTag); } return coalescedRowBuilder.build(); } static long getTimestamp(Cursor cursor) { return cursor.getLong(TIMESTAMP); } } Loading
java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java +1 −49 Original line number Original line Diff line number Diff line Loading @@ -29,16 +29,12 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.net.Uri; import android.os.Build; import android.os.Build; import android.provider.CallLog.Calls; import android.support.annotation.NonNull; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.Nullable; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract; 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.AnnotatedCallLog; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog; import com.android.dialer.common.Assert; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; 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.ArrayList; import java.util.Arrays; import java.util.Arrays; Loading @@ -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_CODE = 1; private static final int ANNOTATED_CALL_LOG_TABLE_ID_CODE = 2; 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 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); private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); Loading @@ -65,10 +60,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { AnnotatedCallLogContract.AUTHORITY, AnnotatedCallLogContract.AUTHORITY, AnnotatedCallLog.DISTINCT_PHONE_NUMBERS, AnnotatedCallLog.DISTINCT_PHONE_NUMBERS, ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE); ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE); uriMatcher.addURI( AnnotatedCallLogContract.AUTHORITY, CoalescedAnnotatedCallLog.TABLE, COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE); } } private AnnotatedCallLogDatabaseHelper databaseHelper; private AnnotatedCallLogDatabaseHelper databaseHelper; Loading Loading @@ -142,33 +133,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { LogUtil.w("AnnotatedCallLogContentProvider.query", "cursor was null"); LogUtil.w("AnnotatedCallLogContentProvider.query", "cursor was null"); } } return cursor; 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: default: throw new IllegalArgumentException("Unknown uri: " + uri); throw new IllegalArgumentException("Unknown uri: " + uri); } } Loading Loading @@ -207,8 +171,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { break; break; case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: throw new UnsupportedOperationException(); throw new UnsupportedOperationException(); case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE: throw new UnsupportedOperationException("coalesced call log does not support inserting"); default: default: throw new IllegalArgumentException("Unknown uri: " + uri); throw new IllegalArgumentException("Unknown uri: " + uri); } } Loading Loading @@ -245,8 +207,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { break; break; case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: throw new UnsupportedOperationException(); throw new UnsupportedOperationException(); case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE: throw new UnsupportedOperationException("coalesced call log does not support deleting"); default: default: throw new IllegalArgumentException("Unknown uri: " + uri); throw new IllegalArgumentException("Unknown uri: " + uri); } } Loading Loading @@ -300,7 +260,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { } } return rows; return rows; case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE: throw new UnsupportedOperationException(); throw new UnsupportedOperationException(); default: default: throw new IllegalArgumentException("Unknown uri: " + uri); throw new IllegalArgumentException("Unknown uri: " + uri); Loading Loading @@ -336,9 +295,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { break; break; case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE: throw new UnsupportedOperationException(); throw new UnsupportedOperationException(); case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE: throw new UnsupportedOperationException( "coalesced call log does not support applyBatch"); default: default: throw new IllegalArgumentException("Unknown uri: " + operation.getUri()); throw new IllegalArgumentException("Unknown uri: " + operation.getUri()); } } Loading Loading @@ -380,10 +336,6 @@ public class AnnotatedCallLogContentProvider extends ContentProvider { } } private void notifyChange(Uri uri) { private void notifyChange(Uri uri) { getContext().getContentResolver().notifyChange(uri, null); getContext().getContentResolver().notifyChange(uri, /* observer = */ 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); } } } }
java/com/android/dialer/calllog/database/Coalescer.java +142 −9 Original line number Original line Diff line number Diff line Loading @@ -22,17 +22,25 @@ import android.provider.CallLog.Calls; import android.support.annotation.NonNull; import android.support.annotation.NonNull; import android.support.annotation.WorkerThread; import android.support.annotation.WorkerThread; import android.telecom.PhoneAccountHandle; import android.telecom.PhoneAccountHandle; import android.text.TextUtils; import com.android.dialer.CoalescedIds; import com.android.dialer.CoalescedIds; import com.android.dialer.DialerPhoneNumber; 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.AnnotatedCallLog; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog; import com.android.dialer.calllog.datasources.CallLogDataSource; import com.android.dialer.calllog.datasources.CallLogDataSource; import com.android.dialer.calllog.datasources.DataSources; 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.Assert; import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor; import com.android.dialer.compat.telephony.TelephonyManagerCompat; 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.phonenumberproto.DialerPhoneNumberUtil; import com.android.dialer.telecom.TelecomUtil; import com.android.dialer.telecom.TelecomUtil; import com.google.common.base.Preconditions; 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 com.google.protobuf.InvalidProtocolBufferException; import java.util.ArrayList; import java.util.ArrayList; import java.util.List; import java.util.List; Loading @@ -41,32 +49,76 @@ import java.util.Objects; import javax.inject.Inject; 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 * <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. * to each data source to determine how individual columns should be aggregated. */ */ public class Coalescer { 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 DataSources dataSources; private final FutureTimer futureTimer; private final ListeningExecutorService backgroundExecutorService; @Inject @Inject Coalescer(DataSources dataSources) { Coalescer( @BackgroundExecutor ListeningExecutorService backgroundExecutorService, DataSources dataSources, FutureTimer futureTimer) { this.backgroundExecutorService = backgroundExecutorService; this.dataSources = dataSources; 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 * Reads the entire {@link AnnotatedCallLog} into memory from the provided cursor and then builds * allAnnotatedCallLog} parameter and then builds and returns a new {@link MatrixCursor} which is * and returns a new {@link MatrixCursor} of {@link CoalescedAnnotatedCallLog}, which is the * the result of combining adjacent rows which should be collapsed for display purposes. * result of combining adjacent rows which should be collapsed for display purposes. * * * @param allAnnotatedCallLogRowsSortedByTimestampDesc all {@link AnnotatedCallLog} rows, sorted * @param allAnnotatedCallLogRowsSortedByTimestampDesc {@link AnnotatedCallLog} rows sorted in * by timestamp descending * descending order of timestamp. * @return a new {@link MatrixCursor} containing the {@link CoalescedAnnotatedCallLog} rows to * @return a new {@link MatrixCursor} containing the {@link CoalescedAnnotatedCallLog} rows to * display * display */ */ @WorkerThread @WorkerThread @NonNull @NonNull Cursor coalesce(@NonNull Cursor allAnnotatedCallLogRowsSortedByTimestampDesc) { private Cursor coalesceInternal(Cursor allAnnotatedCallLogRowsSortedByTimestampDesc) { Assert.isWorkerThread(); Assert.isWorkerThread(); // Note: This method relies on rowsShouldBeCombined to determine which rows should be combined, // Note: This method relies on rowsShouldBeCombined to determine which rows should be combined, Loading @@ -77,7 +129,7 @@ public class Coalescer { MatrixCursor allCoalescedRowsMatrixCursor = MatrixCursor allCoalescedRowsMatrixCursor = new MatrixCursor( new MatrixCursor( CoalescedAnnotatedCallLog.ALL_COLUMNS, CoalescedAnnotatedCallLog.ALL_COLUMNS, Assert.isNotNull(allAnnotatedCallLogRowsSortedByTimestampDesc).getCount()); allAnnotatedCallLogRowsSortedByTimestampDesc.getCount()); if (!allAnnotatedCallLogRowsSortedByTimestampDesc.moveToFirst()) { if (!allAnnotatedCallLogRowsSortedByTimestampDesc.moveToFirst()) { return allCoalescedRowsMatrixCursor; return allCoalescedRowsMatrixCursor; Loading Loading @@ -252,4 +304,85 @@ public class Coalescer { rowBuilder.add(entry.getKey(), entry.getValue()); 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); } } }
java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java +1 −11 Original line number Original line Diff line number Diff line Loading @@ -225,7 +225,7 @@ public class AnnotatedCallLogContract { /** /** * An unique id to associate this call log row to a {@link android.telecom.Call}. * 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}. * <p>For Q+ device, this will be copied from {@link android.provider.CallLog.Calls}. * * Loading @@ -244,16 +244,6 @@ public class AnnotatedCallLogContract { */ */ public static final class CoalescedAnnotatedCallLog implements CommonColumns { 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 * IDs of rows in {@link AnnotatedCallLog} that are coalesced into one row in {@link * CoalescedAnnotatedCallLog}, encoded as a {@link com.android.dialer.CoalescedIds} proto. * CoalescedAnnotatedCallLog}, encoded as a {@link com.android.dialer.CoalescedIds} proto. Loading
java/com/android/dialer/calllog/ui/AnnotatedCallLogCursorLoader.java 0 → 100644 +36 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.dialer.calllog.ui; import android.content.Context; import android.provider.CallLog.Calls; import android.support.v4.content.CursorLoader; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.AnnotatedCallLog; /** Cursor loader for {@link AnnotatedCallLog}. */ final class AnnotatedCallLogCursorLoader extends CursorLoader { AnnotatedCallLogCursorLoader(Context context) { super( context, AnnotatedCallLog.CONTENT_URI, /* projection = */ null, /* selection = */ AnnotatedCallLog.CALL_TYPE + " != ?", /* selectionArgs = */ new String[] {Integer.toString(Calls.VOICEMAIL_TYPE)}, /* sortOrder = */ AnnotatedCallLog.TIMESTAMP + " DESC"); } }
java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.javadeleted 100644 → 0 +0 −132 Original line number Original line Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.dialer.calllog.ui; import android.content.Context; import android.database.Cursor; import android.support.v4.content.CursorLoader; 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.CoalescedAnnotatedCallLog; import com.android.dialer.calllog.model.CoalescedRow; import com.google.protobuf.InvalidProtocolBufferException; /** CursorLoader for the coalesced annotated call log. */ final class CoalescedAnnotatedCallLogCursorLoader extends CursorLoader { // 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; CoalescedAnnotatedCallLogCursorLoader(Context context) { // CoalescedAnnotatedCallLog requires that PROJECTION be ALL_COLUMNS and the following params be // null. super( context, CoalescedAnnotatedCallLog.CONTENT_URI, CoalescedAnnotatedCallLog.ALL_COLUMNS, null, null, null); } /** Creates a new {@link CoalescedRow} from the provided cursor using the current position. */ static CoalescedRow toRow(Cursor cursor) { DialerPhoneNumber number; try { number = DialerPhoneNumber.parseFrom(cursor.getBlob(NUMBER)); } catch (InvalidProtocolBufferException e) { throw new IllegalStateException("Couldn't parse DialerPhoneNumber bytes"); } CoalescedIds coalescedIds; try { coalescedIds = CoalescedIds.parseFrom(cursor.getBlob(COALESCED_IDS)); } catch (InvalidProtocolBufferException e) { throw new IllegalStateException("Couldn't parse CoalescedIds bytes"); } NumberAttributes numberAttributes; try { numberAttributes = NumberAttributes.parseFrom(cursor.getBlob(NUMBER_ATTRIBUTES)); } catch (InvalidProtocolBufferException e) { throw new IllegalStateException("Couldn't parse NumberAttributes bytes"); } CoalescedRow.Builder coalescedRowBuilder = CoalescedRow.newBuilder() .setId(cursor.getLong(ID)) .setTimestamp(cursor.getLong(TIMESTAMP)) .setNumber(number) .setNumberPresentation(cursor.getInt(NUMBER_PRESENTATION)) .setIsRead(cursor.getInt(IS_READ) == 1) .setIsNew(cursor.getInt(NEW) == 1) .setFeatures(cursor.getInt(FEATURES)) .setCallType(cursor.getInt(CALL_TYPE)) .setNumberAttributes(numberAttributes) .setIsVoicemailCall(cursor.getInt(IS_VOICEMAIL_CALL) == 1) .setCoalescedIds(coalescedIds); String formattedNumber = cursor.getString(FORMATTED_NUMBER); if (!TextUtils.isEmpty(formattedNumber)) { coalescedRowBuilder.setFormattedNumber(formattedNumber); } String geocodedLocation = cursor.getString(GEOCODED_LOCATION); if (!TextUtils.isEmpty(geocodedLocation)) { coalescedRowBuilder.setGeocodedLocation(geocodedLocation); } String phoneAccountComponentName = cursor.getString(PHONE_ACCOUNT_COMPONENT_NAME); if (!TextUtils.isEmpty(phoneAccountComponentName)) { coalescedRowBuilder.setPhoneAccountComponentName( cursor.getString(PHONE_ACCOUNT_COMPONENT_NAME)); } String phoneAccountId = cursor.getString(PHONE_ACCOUNT_ID); if (!TextUtils.isEmpty(phoneAccountId)) { coalescedRowBuilder.setPhoneAccountId(phoneAccountId); } String voicemailCallTag = cursor.getString(VOICEMAIL_CALL_TAG); if (!TextUtils.isEmpty(voicemailCallTag)) { coalescedRowBuilder.setVoicemailCallTag(voicemailCallTag); } return coalescedRowBuilder.build(); } static long getTimestamp(Cursor cursor) { return cursor.getLong(TIMESTAMP); } }