Merge "Added "clearData" to CallLogDataSource and PhoneLookup interfaces."
diff --git a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java
index 0495ba6..2cafb26 100644
--- a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java
+++ b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java
@@ -30,6 +30,7 @@
 import com.android.dialer.main.MainComponent;
 import com.android.dialer.metrics.MetricsComponent;
 import com.android.dialer.phonelookup.PhoneLookupComponent;
+import com.android.dialer.phonelookup.database.PhoneLookupDatabaseComponent;
 import com.android.dialer.phonenumbergeoutil.PhoneNumberGeoUtilComponent;
 import com.android.dialer.precall.PreCallComponent;
 import com.android.dialer.preferredsim.suggestion.SimSuggestionComponent;
@@ -47,7 +48,8 @@
  * from this component.
  */
 public interface BaseDialerRootComponent
-    extends CallLocationComponent.HasComponent,
+    extends BubbleComponent.HasComponent,
+        CallLocationComponent.HasComponent,
         CallLogComponent.HasComponent,
         CallLogDatabaseComponent.HasComponent,
         CallLogUiComponent.HasComponent,
@@ -61,8 +63,8 @@
         MainComponent.HasComponent,
         MapsComponent.HasComponent,
         MetricsComponent.HasComponent,
-        BubbleComponent.HasComponent,
         PhoneLookupComponent.HasComponent,
+        PhoneLookupDatabaseComponent.HasComponent,
         PhoneNumberGeoUtilComponent.HasComponent,
         PreCallComponent.HasComponent,
         SimSuggestionComponent.HasComponent,
diff --git a/java/com/android/dialer/calllog/CallLogModule.java b/java/com/android/dialer/calllog/CallLogModule.java
index 9dd9a79..5657270 100644
--- a/java/com/android/dialer/calllog/CallLogModule.java
+++ b/java/com/android/dialer/calllog/CallLogModule.java
@@ -16,6 +16,7 @@
 
 package com.android.dialer.calllog;
 
+import com.android.dialer.calllog.database.CallLogDatabaseModule;
 import com.android.dialer.calllog.datasources.CallLogDataSource;
 import com.android.dialer.calllog.datasources.DataSources;
 import com.android.dialer.calllog.datasources.phonelookup.PhoneLookupDataSource;
@@ -26,7 +27,7 @@
 import dagger.Provides;
 
 /** Dagger module which satisfies call log dependencies. */
-@Module
+@Module(includes = CallLogDatabaseModule.class)
 public abstract class CallLogModule {
 
   @Provides
diff --git a/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java b/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
index 6972273..9a80af2 100644
--- a/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
+++ b/java/com/android/dialer/calllog/database/AnnotatedCallLogContentProvider.java
@@ -45,12 +45,7 @@
 /** {@link ContentProvider} for the annotated call log. */
 public class AnnotatedCallLogContentProvider extends ContentProvider {
 
-  /**
-   * We sometimes run queries where we potentially pass every ID 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;
+
 
   private static final int ANNOTATED_CALL_LOG_TABLE_CODE = 1;
   private static final int ANNOTATED_CALL_LOG_TABLE_ID_CODE = 2;
@@ -87,7 +82,7 @@
 
   @Override
   public boolean onCreate() {
-    databaseHelper = new AnnotatedCallLogDatabaseHelper(getContext(), MAX_ROWS);
+    databaseHelper = CallLogDatabaseComponent.get(getContext()).annotatedCallLogDatabaseHelper();
 
     // Note: As this method is called before Application#onCreate, we must *not* initialize objects
     // that require preparation work done in Application#onCreate.
diff --git a/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java b/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java
index 3b67ff2..7df83b3 100644
--- a/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java
+++ b/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java
@@ -22,15 +22,34 @@
 import android.provider.CallLog.Calls;
 import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.AnnotatedCallLog;
 import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor;
+import com.android.dialer.inject.ApplicationContext;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
 import java.util.Locale;
+import javax.inject.Inject;
+import javax.inject.Singleton;
 
 /** {@link SQLiteOpenHelper} for the AnnotatedCallLog database. */
-class AnnotatedCallLogDatabaseHelper extends SQLiteOpenHelper {
-  private final int maxRows;
+@Singleton
+public class AnnotatedCallLogDatabaseHelper extends SQLiteOpenHelper {
 
-  AnnotatedCallLogDatabaseHelper(Context appContext, int maxRows) {
-    super(appContext, "annotated_call_log.db", null, 1);
+  private static final String FILENAME = "annotated_call_log.db";
+
+  private final Context appContext;
+  private final int maxRows;
+  private final ListeningExecutorService backgroundExecutor;
+
+  @Inject
+  public AnnotatedCallLogDatabaseHelper(
+      @ApplicationContext Context appContext,
+      @AnnotatedCallLogMaxRows int maxRows,
+      @BackgroundExecutor ListeningExecutorService backgroundExecutor) {
+    super(appContext, FILENAME, null, 1);
+
+    this.appContext = appContext;
     this.maxRows = maxRows;
+    this.backgroundExecutor = backgroundExecutor;
   }
 
   private static final String CREATE_TABLE_SQL =
@@ -127,4 +146,14 @@
 
   @Override
   public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
+
+  /** Closes the database and deletes it. */
+  public ListenableFuture<Void> delete() {
+    return backgroundExecutor.submit(
+        () -> {
+          close();
+          appContext.deleteDatabase(FILENAME);
+          return null;
+        });
+  }
 }
diff --git a/java/com/android/dialer/calllog/database/AnnotatedCallLogMaxRows.java b/java/com/android/dialer/calllog/database/AnnotatedCallLogMaxRows.java
new file mode 100644
index 0000000..5542d66
--- /dev/null
+++ b/java/com/android/dialer/calllog/database/AnnotatedCallLogMaxRows.java
@@ -0,0 +1,22 @@
+/*
+ * 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.database;
+
+import javax.inject.Qualifier;
+
+/** Annotation for the max number of rows in the AnnotatedCallLog. */
+@Qualifier
+public @interface AnnotatedCallLogMaxRows {}
diff --git a/java/com/android/dialer/calllog/database/CallLogDatabaseComponent.java b/java/com/android/dialer/calllog/database/CallLogDatabaseComponent.java
index 9912374..09e291e 100644
--- a/java/com/android/dialer/calllog/database/CallLogDatabaseComponent.java
+++ b/java/com/android/dialer/calllog/database/CallLogDatabaseComponent.java
@@ -25,6 +25,8 @@
 
   public abstract Coalescer coalescer();
 
+  public abstract AnnotatedCallLogDatabaseHelper annotatedCallLogDatabaseHelper();
+
   public static CallLogDatabaseComponent get(Context context) {
     return ((CallLogDatabaseComponent.HasComponent)
             ((HasRootComponent) context.getApplicationContext()).component())
diff --git a/java/com/android/dialer/calllog/database/CallLogDatabaseModule.java b/java/com/android/dialer/calllog/database/CallLogDatabaseModule.java
new file mode 100644
index 0000000..eef3fb5
--- /dev/null
+++ b/java/com/android/dialer/calllog/database/CallLogDatabaseModule.java
@@ -0,0 +1,36 @@
+/*
+ * 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.database;
+
+import dagger.Module;
+import dagger.Provides;
+
+/** Binds database dependencies. */
+@Module
+public class CallLogDatabaseModule {
+
+  @Provides
+  @AnnotatedCallLogMaxRows
+  static int provideMaxRows() {
+    /*
+     * We sometimes run queries where we potentially pass every ID 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.
+     */
+    return 999;
+  }
+}
diff --git a/java/com/android/dialer/calllog/datasources/CallLogDataSource.java b/java/com/android/dialer/calllog/datasources/CallLogDataSource.java
index 03a5716..fa3b6a9 100644
--- a/java/com/android/dialer/calllog/datasources/CallLogDataSource.java
+++ b/java/com/android/dialer/calllog/datasources/CallLogDataSource.java
@@ -108,4 +108,11 @@
 
   @MainThread
   void unregisterContentObservers(Context appContext);
+
+  /**
+   * Clear any data written by this data source. This is called when the new call log framework has
+   * been disabled (because for example there was a problem with it).
+   */
+  @MainThread
+  ListenableFuture<Void> clearData();
 }
diff --git a/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java b/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
index 40b0090..615a457 100644
--- a/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
+++ b/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java
@@ -40,6 +40,7 @@
 import com.android.dialer.phonelookup.PhoneLookup;
 import com.android.dialer.phonelookup.PhoneLookupInfo;
 import com.android.dialer.phonelookup.composite.CompositePhoneLookup;
+import com.android.dialer.phonelookup.database.PhoneLookupHistoryDatabaseHelper;
 import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract;
 import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory;
 import com.google.common.collect.ImmutableMap;
@@ -48,6 +49,7 @@
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
 import com.google.protobuf.InvalidProtocolBufferException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -85,14 +87,18 @@
    */
   private final Set<String> phoneLookupHistoryRowsToDelete = new ArraySet<>();
 
+  private final PhoneLookupHistoryDatabaseHelper phoneLookupHistoryDatabaseHelper;
+
   @Inject
   PhoneLookupDataSource(
       CompositePhoneLookup compositePhoneLookup,
       @BackgroundExecutor ListeningExecutorService backgroundExecutorService,
-      @LightweightExecutor ListeningExecutorService lightweightExecutorService) {
+      @LightweightExecutor ListeningExecutorService lightweightExecutorService,
+      PhoneLookupHistoryDatabaseHelper phoneLookupHistoryDatabaseHelper) {
     this.compositePhoneLookup = compositePhoneLookup;
     this.backgroundExecutorService = backgroundExecutorService;
     this.lightweightExecutorService = lightweightExecutorService;
+    this.phoneLookupHistoryDatabaseHelper = phoneLookupHistoryDatabaseHelper;
   }
 
   @Override
@@ -299,6 +305,17 @@
     compositePhoneLookup.unregisterContentObservers(appContext);
   }
 
+  @Override
+  public ListenableFuture<Void> clearData() {
+    ListenableFuture<Void> clearDataFuture = compositePhoneLookup.clearData();
+    ListenableFuture<Void> deleteDatabaseFuture = phoneLookupHistoryDatabaseHelper.delete();
+
+    return Futures.transform(
+        Futures.allAsList(clearDataFuture, deleteDatabaseFuture),
+        unused -> null,
+        MoreExecutors.directExecutor());
+  }
+
   private static ImmutableSet<DialerPhoneNumber>
       queryDistinctDialerPhoneNumbersFromAnnotatedCallLog(Context appContext) {
     ImmutableSet.Builder<DialerPhoneNumber> numbers = ImmutableSet.builder();
diff --git a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
index 3c34fa6..e079961 100644
--- a/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
+++ b/java/com/android/dialer/calllog/datasources/systemcalllog/SystemCallLogDataSource.java
@@ -20,6 +20,7 @@
 import android.annotation.TargetApi;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.os.Build;
 import android.os.Build.VERSION;
@@ -40,6 +41,7 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import com.android.dialer.DialerPhoneNumber;
+import com.android.dialer.calllog.database.AnnotatedCallLogDatabaseHelper;
 import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.AnnotatedCallLog;
 import com.android.dialer.calllog.datasources.CallLogDataSource;
 import com.android.dialer.calllog.datasources.CallLogMutations;
@@ -51,13 +53,15 @@
 import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor;
 import com.android.dialer.compat.android.provider.VoicemailCompat;
 import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil;
-import com.android.dialer.storage.StorageComponent;
+import com.android.dialer.storage.Unencrypted;
 import com.android.dialer.telecom.TelecomUtil;
 import com.android.dialer.theme.R;
 import com.android.dialer.util.PermissionsUtil;
 import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
 import com.google.i18n.phonenumbers.PhoneNumberUtil;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -77,15 +81,21 @@
 
   private final ListeningExecutorService backgroundExecutorService;
   private final MarkDirtyObserver markDirtyObserver;
+  private final SharedPreferences sharedPreferences;
+  private final AnnotatedCallLogDatabaseHelper annotatedCallLogDatabaseHelper;
 
   @Nullable private Long lastTimestampProcessed;
 
   @Inject
   SystemCallLogDataSource(
       @BackgroundExecutor ListeningExecutorService backgroundExecutorService,
-      MarkDirtyObserver markDirtyObserver) {
+      MarkDirtyObserver markDirtyObserver,
+      @Unencrypted SharedPreferences sharedPreferences,
+      AnnotatedCallLogDatabaseHelper annotatedCallLogDatabaseHelper) {
     this.backgroundExecutorService = backgroundExecutorService;
     this.markDirtyObserver = markDirtyObserver;
+    this.sharedPreferences = sharedPreferences;
+    this.annotatedCallLogDatabaseHelper = annotatedCallLogDatabaseHelper;
   }
 
   @MainThread
@@ -125,8 +135,24 @@
   }
 
   @Override
+  public ListenableFuture<Void> clearData() {
+    ListenableFuture<Void> deleteSharedPref =
+        backgroundExecutorService.submit(
+            () -> {
+              sharedPreferences.edit().remove(PREF_LAST_TIMESTAMP_PROCESSED).apply();
+              return null;
+            });
+
+    // TODO(zachh): Test re-enabling after deleting database like this.
+    return Futures.transform(
+        Futures.allAsList(deleteSharedPref, annotatedCallLogDatabaseHelper.delete()),
+        unused -> null,
+        MoreExecutors.directExecutor());
+  }
+
+  @Override
   public ListenableFuture<Boolean> isDirty(Context appContext) {
-    return backgroundExecutorService.submit(() -> isDirtyInternal(appContext));
+    return backgroundExecutorService.submit(this::isDirtyInternal);
   }
 
   @Override
@@ -136,11 +162,11 @@
 
   @Override
   public ListenableFuture<Void> onSuccessfulFill(Context appContext) {
-    return backgroundExecutorService.submit(() -> onSuccessfulFillInternal(appContext));
+    return backgroundExecutorService.submit(this::onSuccessfulFillInternal);
   }
 
   @WorkerThread
-  private boolean isDirtyInternal(Context appContext) {
+  private boolean isDirtyInternal() {
     Assert.isWorkerThread();
 
     /*
@@ -151,9 +177,7 @@
      *
      * Just return false unless the table has never been written to.
      */
-    return !StorageComponent.get(appContext)
-        .unencryptedSharedPrefs()
-        .contains(PREF_LAST_TIMESTAMP_PROCESSED);
+    return !sharedPreferences.contains(PREF_LAST_TIMESTAMP_PROCESSED);
   }
 
   @WorkerThread
@@ -183,11 +207,10 @@
   }
 
   @WorkerThread
-  private Void onSuccessfulFillInternal(Context appContext) {
+  private Void onSuccessfulFillInternal() {
     // If a fill operation was a no-op, lastTimestampProcessed could still be null.
     if (lastTimestampProcessed != null) {
-      StorageComponent.get(appContext)
-          .unencryptedSharedPrefs()
+      sharedPreferences
           .edit()
           .putLong(PREF_LAST_TIMESTAMP_PROCESSED, lastTimestampProcessed)
           .apply();
@@ -232,10 +255,7 @@
   @TargetApi(Build.VERSION_CODES.M) // Uses try-with-resources
   private void handleInsertsAndUpdates(
       Context appContext, CallLogMutations mutations, Set<Long> existingAnnotatedCallLogIds) {
-    long previousTimestampProcessed =
-        StorageComponent.get(appContext)
-            .unencryptedSharedPrefs()
-            .getLong(PREF_LAST_TIMESTAMP_PROCESSED, 0L);
+    long previousTimestampProcessed = sharedPreferences.getLong(PREF_LAST_TIMESTAMP_PROCESSED, 0L);
 
     DialerPhoneNumberUtil dialerPhoneNumberUtil =
         new DialerPhoneNumberUtil(PhoneNumberUtil.getInstance());
diff --git a/java/com/android/dialer/calllog/datasources/voicemail/VoicemailDataSource.java b/java/com/android/dialer/calllog/datasources/voicemail/VoicemailDataSource.java
index 86f3d47..75c0513 100644
--- a/java/com/android/dialer/calllog/datasources/voicemail/VoicemailDataSource.java
+++ b/java/com/android/dialer/calllog/datasources/voicemail/VoicemailDataSource.java
@@ -111,4 +111,9 @@
 
   @Override
   public void unregisterContentObservers(Context appContext) {}
+
+  @Override
+  public ListenableFuture<Void> clearData() {
+    return Futures.immediateFuture(null);
+  }
 }
diff --git a/java/com/android/dialer/phonelookup/PhoneLookup.java b/java/com/android/dialer/phonelookup/PhoneLookup.java
index 016a8a8..d4a1ddf 100644
--- a/java/com/android/dialer/phonelookup/PhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/PhoneLookup.java
@@ -88,4 +88,10 @@
 
   @MainThread
   void unregisterContentObservers(Context appContext);
+
+  /**
+   * Clear any data written by this lookup. This is called when the new call log framework has been
+   * disabled (because for example there was a problem with it).
+   */
+  ListenableFuture<Void> clearData();
 }
diff --git a/java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java b/java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java
index 3491070..f5a249a 100644
--- a/java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/blockednumber/DialerBlockedNumberPhoneLookup.java
@@ -182,4 +182,9 @@
   public void unregisterContentObservers(Context appContext) {
     appContext.getContentResolver().unregisterContentObserver(markDirtyObserver);
   }
+
+  @Override
+  public ListenableFuture<Void> clearData() {
+    return Futures.immediateFuture(null);
+  }
 }
diff --git a/java/com/android/dialer/phonelookup/blockednumber/SystemBlockedNumberPhoneLookup.java b/java/com/android/dialer/phonelookup/blockednumber/SystemBlockedNumberPhoneLookup.java
index def1f01..e2a90c2 100644
--- a/java/com/android/dialer/phonelookup/blockednumber/SystemBlockedNumberPhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/blockednumber/SystemBlockedNumberPhoneLookup.java
@@ -186,4 +186,9 @@
   public void unregisterContentObservers(Context appContext) {
     appContext.getContentResolver().unregisterContentObserver(markDirtyObserver);
   }
+
+  @Override
+  public ListenableFuture<Void> clearData() {
+    return Futures.immediateFuture(null);
+  }
 }
diff --git a/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java b/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java
index 4be43da..365b218 100644
--- a/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/composite/CompositePhoneLookup.java
@@ -230,6 +230,17 @@
     }
   }
 
+  /** Delegates to sub-lookups' {@link PhoneLookup#clearData()}. */
+  public ListenableFuture<Void> clearData() {
+    List<ListenableFuture<Void>> futures = new ArrayList<>();
+    for (PhoneLookup<?> phoneLookup : phoneLookups) {
+      ListenableFuture<Void> phoneLookupFuture = phoneLookup.clearData();
+      futures.add(phoneLookupFuture);
+    }
+    return Futures.transform(
+        Futures.allAsList(futures), unused -> null, lightweightExecutorService);
+  }
+
   private static String getMostRecentInfoEventName(Object classNameSource, boolean isBuilt) {
     return String.format(
         !isBuilt
diff --git a/java/com/android/dialer/phonelookup/cp2/Cp2DefaultDirectoryPhoneLookup.java b/java/com/android/dialer/phonelookup/cp2/Cp2DefaultDirectoryPhoneLookup.java
index b023500..a5b3b72 100644
--- a/java/com/android/dialer/phonelookup/cp2/Cp2DefaultDirectoryPhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/cp2/Cp2DefaultDirectoryPhoneLookup.java
@@ -630,6 +630,15 @@
   @Override
   public void unregisterContentObservers(Context appContext) {}
 
+  @Override
+  public ListenableFuture<Void> clearData() {
+    return backgroundExecutorService.submit(
+        () -> {
+          sharedPreferences.edit().remove(PREF_LAST_TIMESTAMP_PROCESSED).apply();
+          return null;
+        });
+  }
+
   /**
    * 1. get all contact ids. if the id is unset, add the number to the list of contacts to look up.
    * 2. reduce our list of contact ids to those that were updated after lastModified. 3. Now we have
diff --git a/java/com/android/dialer/phonelookup/cp2/Cp2ExtendedDirectoryPhoneLookup.java b/java/com/android/dialer/phonelookup/cp2/Cp2ExtendedDirectoryPhoneLookup.java
index 873658b..9110aa7 100644
--- a/java/com/android/dialer/phonelookup/cp2/Cp2ExtendedDirectoryPhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/cp2/Cp2ExtendedDirectoryPhoneLookup.java
@@ -236,4 +236,9 @@
 
   @Override
   public void unregisterContentObservers(Context appContext) {}
+
+  @Override
+  public ListenableFuture<Void> clearData() {
+    return Futures.immediateFuture(null);
+  }
 }
diff --git a/java/com/android/dialer/phonelookup/database/PhoneLookupDatabaseComponent.java b/java/com/android/dialer/phonelookup/database/PhoneLookupDatabaseComponent.java
new file mode 100644
index 0000000..e3e4160
--- /dev/null
+++ b/java/com/android/dialer/phonelookup/database/PhoneLookupDatabaseComponent.java
@@ -0,0 +1,38 @@
+/*
+ * 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.phonelookup.database;
+
+import android.content.Context;
+import com.android.dialer.inject.HasRootComponent;
+import dagger.Subcomponent;
+
+/** Dagger component for database package. */
+@Subcomponent
+public abstract class PhoneLookupDatabaseComponent {
+
+  public abstract PhoneLookupHistoryDatabaseHelper phoneLookupHistoryDatabaseHelper();
+
+  public static PhoneLookupDatabaseComponent get(Context context) {
+    return ((PhoneLookupDatabaseComponent.HasComponent)
+            ((HasRootComponent) context.getApplicationContext()).component())
+        .phoneLookupDatabaseComponent();
+  }
+
+  /** Used to refer to the root application component. */
+  public interface HasComponent {
+    PhoneLookupDatabaseComponent phoneLookupDatabaseComponent();
+  }
+}
diff --git a/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryContentProvider.java b/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryContentProvider.java
index 1c20b10..35d2d4f 100644
--- a/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryContentProvider.java
+++ b/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryContentProvider.java
@@ -81,7 +81,8 @@
 
   @Override
   public boolean onCreate() {
-    databaseHelper = new PhoneLookupHistoryDatabaseHelper(getContext());
+    databaseHelper =
+        PhoneLookupDatabaseComponent.get(getContext()).phoneLookupHistoryDatabaseHelper();
     return true;
   }
 
diff --git a/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryDatabaseHelper.java b/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryDatabaseHelper.java
index 43b6f10..337e467 100644
--- a/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryDatabaseHelper.java
+++ b/java/com/android/dialer/phonelookup/database/PhoneLookupHistoryDatabaseHelper.java
@@ -21,13 +21,31 @@
 import android.database.sqlite.SQLiteOpenHelper;
 import android.os.SystemClock;
 import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor;
+import com.android.dialer.inject.ApplicationContext;
 import com.android.dialer.phonelookup.database.contract.PhoneLookupHistoryContract.PhoneLookupHistory;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import javax.inject.Inject;
+import javax.inject.Singleton;
 
 /** {@link SQLiteOpenHelper} for the PhoneLookupHistory database. */
-class PhoneLookupHistoryDatabaseHelper extends SQLiteOpenHelper {
+@Singleton
+public class PhoneLookupHistoryDatabaseHelper extends SQLiteOpenHelper {
 
-  PhoneLookupHistoryDatabaseHelper(Context appContext) {
-    super(appContext, "phone_lookup_history.db", null, 1);
+  private static final String FILENAME = "phone_lookup_history.db";
+
+  private final Context appContext;
+  private final ListeningExecutorService backgroundExecutor;
+
+  @Inject
+  PhoneLookupHistoryDatabaseHelper(
+      @ApplicationContext Context appContext,
+      @BackgroundExecutor ListeningExecutorService backgroundExecutor) {
+    super(appContext, FILENAME, null, 1);
+
+    this.appContext = appContext;
+    this.backgroundExecutor = backgroundExecutor;
   }
 
   // TODO(zachh): LAST_MODIFIED is no longer read and can be deleted.
@@ -62,4 +80,14 @@
 
   @Override
   public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
+
+  /** Closes the database and deletes it. */
+  public ListenableFuture<Void> delete() {
+    return backgroundExecutor.submit(
+        () -> {
+          close();
+          appContext.deleteDatabase(FILENAME);
+          return null;
+        });
+  }
 }
diff --git a/java/com/android/dialer/phonelookup/spam/SpamPhoneLookup.java b/java/com/android/dialer/phonelookup/spam/SpamPhoneLookup.java
index 2a85628..315f658 100644
--- a/java/com/android/dialer/phonelookup/spam/SpamPhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/spam/SpamPhoneLookup.java
@@ -159,4 +159,13 @@
 
   @Override
   public void unregisterContentObservers(Context appContext) {}
+
+  @Override
+  public ListenableFuture<Void> clearData() {
+    return backgroundExecutorService.submit(
+        () -> {
+          sharedPreferences.edit().remove(PREF_LAST_TIMESTAMP_PROCESSED).apply();
+          return null;
+        });
+  }
 }