summaryrefslogtreecommitdiff
path: root/java/com/android
diff options
context:
space:
mode:
authorzachh <zachh@google.com>2017-12-07 17:59:20 -0800
committerCopybara-Service <copybara-piper@google.com>2017-12-07 18:35:07 -0800
commit81a7b490ebbf2d9a4213a79b52e7b999aa076b7f (patch)
tree8cc90871e7cef664d498d359b57a95ff7a1b6a79 /java/com/android
parent36a384e04fd9b8ba1d53500afb7e0055e4e4bb99 (diff)
Implemented PhoneLookupDataSource#onSuccesfulFill.
Required adding applyBatch functionality to PhoneLookupHistoryContentProvider so that the updates can be performed in a transaction. This code was just copied and modified from AnnotatedCallLogContentProvider. Also removed the trigger which limited the size of the PhoneLookupHistory, since we now delete rows from PhoneLookupHistory when the last occurrence of a number is deleted from AnnotatedCallLog. Since AnnotatedCallLog is bounded to 1000 rows PhoneLookupHistory is now indirectly bounded by that as well. Bug: 34672501 Test: unit PiperOrigin-RevId: 178323464 Change-Id: I233163fe70641b0e4b1d4c5c0e8970ad0b4b167d
Diffstat (limited to 'java/com/android')
-rw-r--r--java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java40
-rw-r--r--java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java117
-rw-r--r--java/com/android/dialer/phonelookup/database/PhoneLookupHistoryContentProvider.java90
-rw-r--r--java/com/android/dialer/phonelookup/database/PhoneLookupHistoryDatabaseHelper.java29
4 files changed, 214 insertions, 62 deletions
diff --git a/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java b/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
index 825e84f91..2427624a4 100644
--- a/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
+++ b/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
@@ -245,12 +245,12 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
throw new IllegalArgumentException("Unknown uri: " + uri);
}
int rows = database.delete(AnnotatedCallLog.TABLE, selection, selectionArgs);
- if (rows > 0) {
- if (!isApplyingBatch()) {
- notifyChange(uri);
- }
- } else {
+ if (rows == 0) {
LogUtil.w("AnnotatedCallLogContentProvider.delete", "no rows deleted");
+ return rows;
+ }
+ if (!isApplyingBatch()) {
+ notifyChange(uri);
}
return rows;
}
@@ -268,7 +268,15 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
int match = uriMatcher.match(uri);
switch (match) {
case ANNOTATED_CALL_LOG_TABLE_CODE:
- break;
+ int rows = database.update(AnnotatedCallLog.TABLE, values, selection, selectionArgs);
+ if (rows == 0) {
+ LogUtil.w("AnnotatedCallLogContentProvider.update", "no rows updated");
+ return rows;
+ }
+ if (!isApplyingBatch()) {
+ notifyChange(uri);
+ }
+ return rows;
case ANNOTATED_CALL_LOG_TABLE_ID_CODE:
Assert.checkArgument(
!values.containsKey(AnnotatedCallLog._ID), "Do not specify _ID when updating by ID");
@@ -276,23 +284,21 @@ public class AnnotatedCallLogContentProvider extends ContentProvider {
Assert.checkArgument(
selectionArgs == null, "Do not specify selection args when updating by ID");
selection = getSelectionWithId(ContentUris.parseId(uri));
- break;
+ rows = database.update(AnnotatedCallLog.TABLE, values, selection, selectionArgs);
+ if (rows == 0) {
+ LogUtil.w("AnnotatedCallLogContentProvider.update", "no rows updated");
+ return rows;
+ }
+ if (!isApplyingBatch()) {
+ notifyChange(uri);
+ }
+ return rows;
case ANNOTATED_CALL_LOG_TABLE_DISTINCT_NUMBER_CODE:
- throw new UnsupportedOperationException();
case COALESCED_ANNOTATED_CALL_LOG_TABLE_CODE:
throw new UnsupportedOperationException();
default:
throw new IllegalArgumentException("Unknown uri: " + uri);
}
- int rows = database.update(AnnotatedCallLog.TABLE, values, selection, selectionArgs);
- if (rows > 0) {
- if (!isApplyingBatch()) {
- notifyChange(uri);
- }
- } else {
- LogUtil.w("AnnotatedCallLogContentProvider.update", "no rows updated");
- }
- return rows;
}
/**
diff --git a/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java b/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
index 17a09ce47..fa7d3be16 100644
--- a/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
+++ b/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
@@ -16,9 +16,13 @@
package com.android.dialer.calllog.datasources.phonelookup;
+import android.content.ContentProviderOperation;
import android.content.ContentValues;
import android.content.Context;
+import android.content.OperationApplicationException;
import android.database.Cursor;
+import android.net.Uri;
+import android.os.RemoteException;
import android.support.annotation.MainThread;
import android.support.annotation.WorkerThread;
import android.text.TextUtils;
@@ -34,6 +38,7 @@ import com.android.dialer.common.concurrent.Annotations.LightweightExecutor;
import com.android.dialer.phonelookup.PhoneLookup;
import com.android.dialer.phonelookup.PhoneLookupInfo;
import com.android.dialer.phonelookup.PhoneLookupSelector;
+import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract;
import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory;
import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil;
import com.google.common.collect.ImmutableMap;
@@ -44,6 +49,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.protobuf.InvalidProtocolBufferException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -62,6 +68,23 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
private final ListeningExecutorService backgroundExecutorService;
private final ListeningExecutorService lightweightExecutorService;
+ /**
+ * Keyed by normalized number (the primary key for PhoneLookupHistory).
+ *
+ * <p>This is state saved between the {@link #fill(Context, CallLogMutations)} and {@link
+ * #onSuccessfulFill(Context)} operations.
+ */
+ private final Map<String, PhoneLookupInfo> phoneLookupHistoryRowsToUpdate = new ArrayMap<>();
+
+ /**
+ * Normalized numbers (the primary key for PhoneLookupHistory) which should be deleted from
+ * PhoneLookupHistory.
+ *
+ * <p>This is state saved between the {@link #fill(Context, CallLogMutations)} and {@link
+ * #onSuccessfulFill(Context)} operations.
+ */
+ private final Set<String> phoneLookupHistoryRowsToDelete = new ArraySet<>();
+
@Inject
PhoneLookupDataSource(
PhoneLookup phoneLookup,
@@ -108,6 +131,11 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
*/
@Override
public ListenableFuture<Void> fill(Context appContext, CallLogMutations mutations) {
+ // Clear state saved since the last call to fill. This is necessary in case fill is called but
+ // onSuccessfulFill is not called during a previous flow.
+ phoneLookupHistoryRowsToUpdate.clear();
+ phoneLookupHistoryRowsToDelete.clear();
+
// First query information from annotated call log.
ListenableFuture<Map<DialerPhoneNumber, Set<Long>>> annotatedCallLogIdsByNumberFuture =
backgroundExecutorService.submit(() -> queryIdAndNumberFromAnnotatedCallLog(appContext));
@@ -150,6 +178,13 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
}
populateInserts(originalPhoneLookupHistoryDataByAnnotatedCallLogId.build(), mutations);
+ // Compute and save the PhoneLookupHistory rows which can be deleted in onSuccessfulFill.
+ DialerPhoneNumberUtil dialerPhoneNumberUtil =
+ new DialerPhoneNumberUtil(PhoneNumberUtil.getInstance());
+ phoneLookupHistoryRowsToDelete.addAll(
+ computePhoneLookupHistoryRowsToDelete(
+ annotatedCallLogIdsByNumber, mutations, dialerPhoneNumberUtil));
+
// Now compute the rows to update.
ImmutableMap.Builder<Long, PhoneLookupInfo> rowsToUpdate = ImmutableMap.builder();
for (Entry<DialerPhoneNumber, PhoneLookupInfo> entry : updatedInfoMap.entrySet()) {
@@ -159,6 +194,10 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
for (Long id : annotatedCallLogIdsByNumber.get(dialerPhoneNumber)) {
rowsToUpdate.put(id, upToDateInfo);
}
+ // Also save the updated information so that it can be written to PhoneLookupHistory
+ // in onSuccessfulFill.
+ String normalizedNumber = dialerPhoneNumberUtil.formatToE164(dialerPhoneNumber);
+ phoneLookupHistoryRowsToUpdate.put(normalizedNumber, upToDateInfo);
}
}
return rowsToUpdate.build();
@@ -167,9 +206,11 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
ListenableFuture<ImmutableMap<Long, PhoneLookupInfo>> rowsToUpdateFuture =
Futures.whenAllSucceed(
annotatedCallLogIdsByNumberFuture, updatedInfoMapFuture, originalInfoMapFuture)
- .call(computeRowsToUpdate, lightweightExecutorService);
+ .call(
+ computeRowsToUpdate,
+ backgroundExecutorService /* PhoneNumberUtil may do disk IO */);
- // Finally apply the computed rows to update to mutations.
+ // Finally update the mutations with the computed rows.
return Futures.transform(
rowsToUpdateFuture,
rowsToUpdate -> {
@@ -181,12 +222,38 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
@Override
public ListenableFuture<Void> onSuccessfulFill(Context appContext) {
- return backgroundExecutorService.submit(this::onSuccessfulFillInternal);
+ // First update and/or delete the appropriate rows in PhoneLookupHistory.
+ ListenableFuture<Void> writePhoneLookupHistory =
+ backgroundExecutorService.submit(() -> writePhoneLookupHistory(appContext));
+
+ // If that succeeds, delegate to the composite PhoneLookup to notify all PhoneLookups that both
+ // the AnnotatedCallLog and PhoneLookupHistory have been successfully updated.
+ return Futures.transformAsync(
+ writePhoneLookupHistory,
+ unused -> phoneLookup.onSuccessfulBulkUpdate(),
+ lightweightExecutorService);
}
@WorkerThread
- private Void onSuccessfulFillInternal() {
- // TODO(zachh): Update PhoneLookupHistory.
+ private Void writePhoneLookupHistory(Context appContext)
+ throws RemoteException, OperationApplicationException {
+ ArrayList<ContentProviderOperation> operations = new ArrayList<>();
+ long currentTimestamp = System.currentTimeMillis();
+ for (Entry<String, PhoneLookupInfo> entry : phoneLookupHistoryRowsToUpdate.entrySet()) {
+ String normalizedNumber = entry.getKey();
+ PhoneLookupInfo phoneLookupInfo = entry.getValue();
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(PhoneLookupHistory.PHONE_LOOKUP_INFO, phoneLookupInfo.toByteArray());
+ contentValues.put(PhoneLookupHistory.LAST_MODIFIED, currentTimestamp);
+ operations.add(
+ ContentProviderOperation.newUpdate(numberUri(normalizedNumber))
+ .withValues(contentValues)
+ .build());
+ }
+ for (String normalizedNumber : phoneLookupHistoryRowsToDelete) {
+ operations.add(ContentProviderOperation.newDelete(numberUri(normalizedNumber)).build());
+ }
+ appContext.getContentResolver().applyBatch(PhoneLookupHistoryContract.AUTHORITY, operations);
return null;
}
@@ -422,7 +489,47 @@ public final class PhoneLookupDataSource implements CallLogDataSource {
}
}
+ private Set<String> computePhoneLookupHistoryRowsToDelete(
+ Map<DialerPhoneNumber, Set<Long>> annotatedCallLogIdsByNumber,
+ CallLogMutations mutations,
+ DialerPhoneNumberUtil dialerPhoneNumberUtil) {
+ if (mutations.getDeletes().isEmpty()) {
+ return ImmutableSet.of();
+ }
+ // First convert the dialer phone numbers to normalized numbers; we need to combine entries
+ // because different DialerPhoneNumbers can map to the same normalized number.
+ Map<String, Set<Long>> idsByNormalizedNumber = new ArrayMap<>();
+ for (Entry<DialerPhoneNumber, Set<Long>> entry : annotatedCallLogIdsByNumber.entrySet()) {
+ DialerPhoneNumber dialerPhoneNumber = entry.getKey();
+ Set<Long> idsForDialerPhoneNumber = entry.getValue();
+ String normalizedNumber = dialerPhoneNumberUtil.formatToE164(dialerPhoneNumber);
+ Set<Long> idsForNormalizedNumber = idsByNormalizedNumber.get(normalizedNumber);
+ if (idsForNormalizedNumber == null) {
+ idsForNormalizedNumber = new ArraySet<>();
+ idsByNormalizedNumber.put(normalizedNumber, idsForNormalizedNumber);
+ }
+ idsForNormalizedNumber.addAll(idsForDialerPhoneNumber);
+ }
+ // Now look through and remove all IDs that were scheduled for delete; after doing that, if
+ // there are no remaining IDs left for a normalized number, the number can be deleted from
+ // PhoneLookupHistory.
+ Set<String> normalizedNumbersToDelete = new ArraySet<>();
+ for (Entry<String, Set<Long>> entry : idsByNormalizedNumber.entrySet()) {
+ String normalizedNumber = entry.getKey();
+ Set<Long> idsForNormalizedNumber = entry.getValue();
+ idsForNormalizedNumber.removeAll(mutations.getDeletes());
+ if (idsForNormalizedNumber.isEmpty()) {
+ normalizedNumbersToDelete.add(normalizedNumber);
+ }
+ }
+ return normalizedNumbersToDelete;
+ }
+
private static String selectName(PhoneLookupInfo phoneLookupInfo) {
return PhoneLookupSelector.selectName(phoneLookupInfo);
}
+
+ private static Uri numberUri(String number) {
+ return PhoneLookupHistory.CONTENT_URI.buildUpon().appendEncodedPath(number).build();
+ }
}
diff --git a/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryContentProvider.java b/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryContentProvider.java
index e85654e99..5c0c00f81 100644
--- a/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryContentProvider.java
+++ b/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryContentProvider.java
@@ -17,7 +17,10 @@
package com.android.dialer.phonelookup.database;
import android.content.ContentProvider;
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
import android.content.ContentValues;
+import android.content.OperationApplicationException;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.DatabaseUtils;
@@ -31,6 +34,7 @@ import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract;
import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory;
+import java.util.ArrayList;
/**
* {@link ContentProvider} for the PhoneLookupHistory.
@@ -50,13 +54,6 @@ import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContra
*/
public class PhoneLookupHistoryContentProvider extends ContentProvider {
- /**
- * We sometimes run queries where we potentially pass numbers into a where clause using the
- * (?,?,?,...) syntax. The maximum number of host parameters is 999, so that's the maximum size
- * this table can be. See https://www.sqlite.org/limits.html for more details.
- */
- private static final int MAX_ROWS = 999;
-
// For operations against: content://com.android.dialer.phonelookuphistory/PhoneLookupHistory
private static final int PHONE_LOOKUP_HISTORY_TABLE_CODE = 1;
// For operations against: content://com.android.dialer.phonelookuphistory/PhoneLookupHistory/+123
@@ -77,9 +74,16 @@ public class PhoneLookupHistoryContentProvider extends ContentProvider {
private PhoneLookupHistoryDatabaseHelper databaseHelper;
+ private final ThreadLocal<Boolean> applyingBatch = new ThreadLocal<>();
+
+ /** Ensures that only a single notification is generated from {@link #applyBatch(ArrayList)}. */
+ private boolean isApplyingBatch() {
+ return applyingBatch.get() != null && applyingBatch.get();
+ }
+
@Override
public boolean onCreate() {
- databaseHelper = new PhoneLookupHistoryDatabaseHelper(getContext(), MAX_ROWS);
+ databaseHelper = new PhoneLookupHistoryDatabaseHelper(getContext());
return true;
}
@@ -168,7 +172,9 @@ public class PhoneLookupHistoryContentProvider extends ContentProvider {
.buildUpon()
.appendEncodedPath(values.getAsString(PhoneLookupHistory.NORMALIZED_NUMBER))
.build();
- notifyChange(insertedUri);
+ if (!isApplyingBatch()) {
+ notifyChange(insertedUri);
+ }
return insertedUri;
}
@@ -197,7 +203,9 @@ public class PhoneLookupHistoryContentProvider extends ContentProvider {
LogUtil.w("PhoneLookupHistoryContentProvider.delete", "no rows deleted");
return rows;
}
- notifyChange(uri);
+ if (!isApplyingBatch()) {
+ notifyChange(uri);
+ }
return rows;
}
@@ -206,6 +214,9 @@ public class PhoneLookupHistoryContentProvider extends ContentProvider {
* "content://com.android.dialer.phonelookuphistory/PhoneLookupHistory/+123") then the update
* operation will actually be a "replace" operation, inserting a new row if one does not already
* exist.
+ *
+ * <p>All columns in an existing row will be replaced which means you must specify all required
+ * columns in {@code values} when using this method.
*/
@Override
public int update(
@@ -225,7 +236,9 @@ public class PhoneLookupHistoryContentProvider extends ContentProvider {
LogUtil.w("PhoneLookupHistoryContentProvider.update", "no rows updated");
return rows;
}
- notifyChange(uri);
+ if (!isApplyingBatch()) {
+ notifyChange(uri);
+ }
return rows;
case PHONE_LOOKUP_HISTORY_TABLE_ID_CODE:
Assert.checkArgument(
@@ -237,14 +250,65 @@ public class PhoneLookupHistoryContentProvider extends ContentProvider {
String normalizedNumber = uri.getLastPathSegment();
values.put(PhoneLookupHistory.NORMALIZED_NUMBER, normalizedNumber);
- database.replace(PhoneLookupHistory.TABLE, null, values);
- notifyChange(uri);
+ long result = database.replace(PhoneLookupHistory.TABLE, null, values);
+ Assert.checkArgument(result != -1, "replacing PhoneLookupHistory row failed");
+ if (!isApplyingBatch()) {
+ notifyChange(uri);
+ }
return 1;
default:
throw new IllegalArgumentException("Unknown uri: " + uri);
}
}
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Note: When applyBatch is used with the PhoneLookupHistory, only a single notification for
+ * the content URI is generated, not individual notifications for each affected URI.
+ */
+ @NonNull
+ @Override
+ public ContentProviderResult[] applyBatch(@NonNull ArrayList<ContentProviderOperation> operations)
+ throws OperationApplicationException {
+ ContentProviderResult[] results = new ContentProviderResult[operations.size()];
+ if (operations.isEmpty()) {
+ return results;
+ }
+
+ SQLiteDatabase database = databaseHelper.getWritableDatabase();
+ try {
+ applyingBatch.set(true);
+ database.beginTransaction();
+ for (int i = 0; i < operations.size(); i++) {
+ ContentProviderOperation operation = operations.get(i);
+ int match = uriMatcher.match(operation.getUri());
+ switch (match) {
+ case PHONE_LOOKUP_HISTORY_TABLE_CODE:
+ case PHONE_LOOKUP_HISTORY_TABLE_ID_CODE:
+ ContentProviderResult result = operation.apply(this, results, i);
+ if (operation.isInsert()) {
+ if (result.uri == null) {
+ throw new OperationApplicationException("error inserting row");
+ }
+ } else if (result.count == 0) {
+ throw new OperationApplicationException("error applying operation");
+ }
+ results[i] = result;
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown uri: " + operation.getUri());
+ }
+ }
+ database.setTransactionSuccessful();
+ } finally {
+ applyingBatch.set(false);
+ database.endTransaction();
+ }
+ notifyChange(PhoneLookupHistory.CONTENT_URI);
+ return results;
+ }
+
private void notifyChange(Uri uri) {
getContext().getContentResolver().notifyChange(uri, null);
}
diff --git a/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryDatabaseHelper.java b/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryDatabaseHelper.java
index 70d88cee4..43b6f102c 100644
--- a/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryDatabaseHelper.java
+++ b/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryDatabaseHelper.java
@@ -22,17 +22,15 @@ import android.database.sqlite.SQLiteOpenHelper;
import android.os.SystemClock;
import com.android.dialer.common.LogUtil;
import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory;
-import java.util.Locale;
/** {@link SQLiteOpenHelper} for the PhoneLookupHistory database. */
class PhoneLookupHistoryDatabaseHelper extends SQLiteOpenHelper {
- private final int maxRows;
- PhoneLookupHistoryDatabaseHelper(Context appContext, int maxRows) {
+ PhoneLookupHistoryDatabaseHelper(Context appContext) {
super(appContext, "phone_lookup_history.db", null, 1);
- this.maxRows = maxRows;
}
+ // TODO(zachh): LAST_MODIFIED is no longer read and can be deleted.
private static final String CREATE_TABLE_SQL =
"create table if not exists "
+ PhoneLookupHistory.TABLE
@@ -42,28 +40,6 @@ class PhoneLookupHistoryDatabaseHelper extends SQLiteOpenHelper {
+ (PhoneLookupHistory.LAST_MODIFIED + " long not null")
+ ");";
- /** Deletes all but the first maxRows rows (by timestamp) to keep the table a manageable size. */
- private static final String CREATE_TRIGGER_SQL =
- "create trigger delete_old_rows after insert on "
- + PhoneLookupHistory.TABLE
- + " when (select count(*) from "
- + PhoneLookupHistory.TABLE
- + ") > %d"
- + " begin delete from "
- + PhoneLookupHistory.TABLE
- + " where "
- + PhoneLookupHistory.NORMALIZED_NUMBER
- + " in (select "
- + PhoneLookupHistory.NORMALIZED_NUMBER
- + " from "
- + PhoneLookupHistory.TABLE
- + " order by "
- + PhoneLookupHistory.LAST_MODIFIED
- + " limit (select count(*)-%d"
- + " from "
- + PhoneLookupHistory.TABLE
- + " )); end;";
-
private static final String CREATE_INDEX_ON_LAST_MODIFIED_SQL =
"create index last_modified_index on "
+ PhoneLookupHistory.TABLE
@@ -76,7 +52,6 @@ class PhoneLookupHistoryDatabaseHelper extends SQLiteOpenHelper {
LogUtil.enterBlock("PhoneLookupHistoryDatabaseHelper.onCreate");
long startTime = SystemClock.uptimeMillis();
db.execSQL(CREATE_TABLE_SQL);
- db.execSQL(String.format(Locale.US, CREATE_TRIGGER_SQL, maxRows, maxRows));
db.execSQL(CREATE_INDEX_ON_LAST_MODIFIED_SQL);
// TODO(zachh): Consider logging impression.
LogUtil.i(