Remove package certificate from ContactsIndexerTests

- Refactor ContactsIndexerConfig into an interface and add a test
  implementation that returns only default values which can be used for
  tests that don't need the READ_DEVICE_CONFIG permission.
- Remove INTERACT_ACROSS_USERS_FULL and READ_DEVICE_CONFIG permissions
  since they are privileged.
- Remove the platform certificate since this is not allowed in MTS.
- Move the tests to the general-tests suite now that the issues making
  it device-specific are resolved.

Bug: 203690505
Bug: 229203989
Test: ContactsIndexerTests
Change-Id: Idd171751580a21128b9c2986e8784ca340af06d3
diff --git a/service/java/com/android/server/appsearch/AppSearchModule.java b/service/java/com/android/server/appsearch/AppSearchModule.java
index 41ec91b..9e7fe95 100644
--- a/service/java/com/android/server/appsearch/AppSearchModule.java
+++ b/service/java/com/android/server/appsearch/AppSearchModule.java
@@ -25,6 +25,7 @@
 
 import com.android.server.SystemService;
 import com.android.server.appsearch.contactsindexer.ContactsIndexerConfig;
+import com.android.server.appsearch.contactsindexer.FrameworkContactsIndexerConfig;
 import com.android.server.appsearch.contactsindexer.ContactsIndexerManagerService;
 
 import java.io.File;
@@ -69,8 +70,10 @@
 
             // It is safe to check DeviceConfig here, since SettingsProvider, which DeviceConfig
             // uses, starts before AppSearch.
-            if (ContactsIndexerConfig.isContactsIndexerEnabled()) {
-                mContactsIndexerManagerService = new ContactsIndexerManagerService(getContext());
+            ContactsIndexerConfig contactsIndexerConfig = new FrameworkContactsIndexerConfig();
+            if (contactsIndexerConfig.isContactsIndexerEnabled()) {
+                mContactsIndexerManagerService = new ContactsIndexerManagerService(getContext(),
+                        contactsIndexerConfig);
                 try {
                     mContactsIndexerManagerService.onStart();
                 } catch (Throwable t) {
diff --git a/service/java/com/android/server/appsearch/contactsindexer/ContactsIndexerConfig.java b/service/java/com/android/server/appsearch/contactsindexer/ContactsIndexerConfig.java
index 8089c7d..9544557 100644
--- a/service/java/com/android/server/appsearch/contactsindexer/ContactsIndexerConfig.java
+++ b/service/java/com/android/server/appsearch/contactsindexer/ContactsIndexerConfig.java
@@ -16,67 +16,50 @@
 
 package com.android.server.appsearch.contactsindexer;
 
-import android.provider.DeviceConfig;
-
 import java.util.concurrent.TimeUnit;
 
 /**
- * Contains all the keys for flags related to Contacts Indexer.
+ * An interface which exposes config flags to Contacts Indexer.
+ *
+ * <p>Implementations of this interface must be thread-safe.
  *
  * @hide
  */
-public class ContactsIndexerConfig {
-    // LIMIT of -1 means no upper bound (see https://www.sqlite.org/lang_select.html)
-    public static final int UPDATE_LIMIT_NONE = -1;
+public interface ContactsIndexerConfig {
+    boolean DEFAULT_CONTACTS_INDEXER_ENABLED = true;
+    int DEFAULT_CONTACTS_FIRST_RUN_INDEXING_LIMIT = 1000;
+    long DEFAULT_CONTACTS_FULL_UPDATE_INTERVAL_MILLIS = TimeUnit.DAYS.toMillis(30); // 30 days.
+    int DEFAULT_CONTACTS_FULL_UPDATE_INDEXING_LIMIT = 10_000;
+    int DEFAULT_CONTACTS_DELTA_UPDATE_INDEXING_LIMIT = 1000;
 
-    private static final String KEY_CONTACTS_INSTANT_INDEXING_LIMIT =
-            "contacts_instant_indexing_limit";
-    public static final String KEY_CONTACTS_INDEXER_ENABLED = "contacts_indexer_enabled";
-    public static final String KEY_CONTACTS_FULL_UPDATE_INTERVAL_MILLIS
-            = "contacts_full_update_interval_millis";
-    public static final String KEY_CONTACTS_FULL_UPDATE_LIMIT =
-            "contacts_indexer_full_update_limit";
-    public static final String KEY_CONTACTS_DELTA_UPDATE_LIMIT =
-            "contacts_indexer_delta_update_limit";
+    /** Returns whether Contacts Indexer is enabled. */
+    boolean isContactsIndexerEnabled();
 
-    public static boolean isContactsIndexerEnabled() {
-        return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_APPSEARCH,
-                KEY_CONTACTS_INDEXER_ENABLED,
-                /*defaultValue=*/ true);
-    }
+    /**
+     * Returns the maximum number of CP2 contacts indexed during first run.
+     *
+     * <p>This value will limit the amount of processing performed when the device upgrades from
+     * Android S to T with Contacts Indexer enabled.
+     */
+    int getContactsFirstRunIndexingLimit();
 
-    public static int getContactsInstantIndexingLimit() {
-        return DeviceConfig.getInt(DeviceConfig.NAMESPACE_APPSEARCH,
-                KEY_CONTACTS_INSTANT_INDEXING_LIMIT, /*defaultValue=*/ 1000);
-    }
-
-    public static long getContactsFullUpdateIntervalMillis() {
-        return DeviceConfig.getLong(DeviceConfig.NAMESPACE_APPSEARCH,
-                KEY_CONTACTS_FULL_UPDATE_INTERVAL_MILLIS,
-                /*defaultValue=*/ TimeUnit.DAYS.toMillis(30));
-    }
+    /**
+     * Returns the minimum internal in millis for two consecutive full update. This is only checked
+     * once after reach boot.
+     */
+    long getContactsFullUpdateIntervalMillis();
 
     /**
      * Returns the maximum number of CP2 contacts indexed during a full update.
      *
      * <p>The value will be used as a LIMIT for querying CP2 during full update.
      */
-    public static int getContactsFullUpdateLimit() {
-        return DeviceConfig.getInt(DeviceConfig.NAMESPACE_APPSEARCH,
-                KEY_CONTACTS_FULL_UPDATE_LIMIT,
-                /*defaultValue=*/ 10_000);
-    }
+    int getContactsFullUpdateLimit();
 
     /**
      * Returns the maximum number of CP2 contacts indexed during a delta update.
      *
      * <p>The value will be used as a LIMIT for querying CP2 during the delta update.
      */
-    public static int getContactsDeltaUpdateLimit() {
-        // TODO(b/227419499) Based on the metrics, we can tweak this number. Right now it is same
-        //  as the instant indexing limit, which is 1,000. From our stats in GMSCore, 95th
-        //  percentile for number of contacts on the device is around 2000 contacts.
-        return DeviceConfig.getInt(DeviceConfig.NAMESPACE_APPSEARCH,
-                KEY_CONTACTS_DELTA_UPDATE_LIMIT, /*defaultValue=*/ 1000);
-    }
+    int getContactsDeltaUpdateLimit();
 }
diff --git a/service/java/com/android/server/appsearch/contactsindexer/ContactsIndexerManagerService.java b/service/java/com/android/server/appsearch/contactsindexer/ContactsIndexerManagerService.java
index f83133a..f9bff4f 100644
--- a/service/java/com/android/server/appsearch/contactsindexer/ContactsIndexerManagerService.java
+++ b/service/java/com/android/server/appsearch/contactsindexer/ContactsIndexerManagerService.java
@@ -56,6 +56,7 @@
             "com.android.providers.contacts";
 
     private final Context mContext;
+    private final ContactsIndexerConfig mContactsIndexerConfig;
     private final LocalService mLocalService;
     // Sparse array of ContactsIndexerUserInstance indexed by the device-user ID.
     private final SparseArray<ContactsIndexerUserInstance> mContactsIndexersLocked =
@@ -64,9 +65,11 @@
     private String mContactsProviderPackageName;
 
     /** Constructs a {@link ContactsIndexerManagerService}. */
-    public ContactsIndexerManagerService(@NonNull Context context) {
+    public ContactsIndexerManagerService(@NonNull Context context,
+            @NonNull ContactsIndexerConfig contactsIndexerConfig) {
         super(context);
         mContext = Objects.requireNonNull(context);
+        mContactsIndexerConfig = Objects.requireNonNull(contactsIndexerConfig);
         mLocalService = new LocalService();
     }
 
@@ -89,7 +92,8 @@
                 File appSearchDir = AppSearchModule.getAppSearchDir(userHandle);
                 File contactsDir = new File(appSearchDir, "contacts");
                 try {
-                    instance = ContactsIndexerUserInstance.createInstance(userContext, contactsDir);
+                    instance = ContactsIndexerUserInstance.createInstance(userContext, contactsDir,
+                            mContactsIndexerConfig);
                     Log.d(TAG, "Created Contacts Indexer instance for user " + userHandle);
                 } catch (Throwable t) {
                     Log.e(TAG, "Failed to create Contacts Indexer instance for user "
diff --git a/service/java/com/android/server/appsearch/contactsindexer/ContactsIndexerUserInstance.java b/service/java/com/android/server/appsearch/contactsindexer/ContactsIndexerUserInstance.java
index 29fb34d..7acb633 100644
--- a/service/java/com/android/server/appsearch/contactsindexer/ContactsIndexerUserInstance.java
+++ b/service/java/com/android/server/appsearch/contactsindexer/ContactsIndexerUserInstance.java
@@ -67,6 +67,7 @@
 
     private final AppSearchHelper mAppSearchHelper;
     private final ContactsIndexerImpl mContactsIndexerImpl;
+    private final ContactsIndexerConfig mContactsIndexerConfig;
 
     /**
      * Single threaded executor to make sure there is only one active sync for this {@link
@@ -83,27 +84,30 @@
      */
     @NonNull
     public static ContactsIndexerUserInstance createInstance(@NonNull Context userContext,
-            @NonNull File contactsDir) {
+            @NonNull File contactsDir, @NonNull ContactsIndexerConfig contactsIndexerConfig) {
         Objects.requireNonNull(userContext);
         Objects.requireNonNull(contactsDir);
+        Objects.requireNonNull(contactsIndexerConfig);
 
         ExecutorService singleThreadedExecutor = Executors.newSingleThreadExecutor();
-        return createInstance(userContext, contactsDir, singleThreadedExecutor);
+        return createInstance(userContext, contactsDir, contactsIndexerConfig,
+                singleThreadedExecutor);
     }
 
     @VisibleForTesting
     @NonNull
     /*package*/ static ContactsIndexerUserInstance createInstance(@NonNull Context context,
-            @NonNull File contactsDir,
+            @NonNull File contactsDir, @NonNull ContactsIndexerConfig contactsIndexerConfig,
             @NonNull ExecutorService executorService) {
         Objects.requireNonNull(context);
         Objects.requireNonNull(contactsDir);
+        Objects.requireNonNull(contactsIndexerConfig);
         Objects.requireNonNull(executorService);
 
         AppSearchHelper appSearchHelper = AppSearchHelper.createAppSearchHelper(context,
                 executorService);
         ContactsIndexerUserInstance indexer = new ContactsIndexerUserInstance(context,
-                contactsDir, appSearchHelper, executorService);
+                contactsDir, appSearchHelper, contactsIndexerConfig, executorService);
         indexer.loadSettingsAsync();
 
         return indexer;
@@ -112,17 +116,20 @@
     /**
      * Constructs a {@link ContactsIndexerUserInstance}.
      *
-     * @param context                Context object passed from
-     *                               {@link ContactsIndexerManagerService}
-     * @param dataDir                data directory for storing contacts indexer state.
-     * @param singleThreadedExecutor an {@link ExecutorService} with at most one thread to ensure
-     *                               the thread safety of this class.
+     * @param context                 Context object passed from
+     *                                {@link ContactsIndexerManagerService}
+     * @param dataDir                 data directory for storing contacts indexer state.
+     * @param contactsIndexerConfig   configuration for the Contacts Indexer.
+     * @param singleThreadedExecutor  an {@link ExecutorService} with at most one thread to ensure
+     *                                the thread safety of this class.
      */
     private ContactsIndexerUserInstance(@NonNull Context context, @NonNull File dataDir,
             @NonNull AppSearchHelper appSearchHelper,
+            @NonNull ContactsIndexerConfig contactsIndexerConfig,
             @NonNull ExecutorService singleThreadedExecutor) {
         mContext = Objects.requireNonNull(context);
         mDataDir = Objects.requireNonNull(dataDir);
+        mContactsIndexerConfig = Objects.requireNonNull(contactsIndexerConfig);
         mSettings = new ContactsIndexerSettings(mDataDir);
         mAppSearchHelper = Objects.requireNonNull(appSearchHelper);
         mSingleThreadedExecutor = Objects.requireNonNull(singleThreadedExecutor);
@@ -172,7 +179,7 @@
             // TODO(b/222126568): refactor doDeltaUpdateAsync() to return a future value of
             // ContactsUpdateStats so that it can be checked and logged here, instead of the
             // placeholder exceptionally() block that only logs to the console.
-            doDeltaUpdateAsync(ContactsIndexerConfig.getContactsInstantIndexingLimit(),
+            doDeltaUpdateAsync(mContactsIndexerConfig.getContactsFirstRunIndexingLimit(),
                     new ContactsUpdateStats()).exceptionally(t -> {
                 Log.d(TAG, "Failed to bootstrap Person corpus with CP2 contacts", t);
                 return null;
@@ -181,7 +188,8 @@
 
         // If a configurable amount of time has passed since the last full sync, schedule a job
         // to do a full update. That is, sync all CP2 contacts into AppSearch.
-        long fullUpdateIntervalMillis = ContactsIndexerConfig.getContactsFullUpdateIntervalMillis();
+        long fullUpdateIntervalMillis =
+                mContactsIndexerConfig.getContactsFullUpdateIntervalMillis();
         long lastFullUpdateTimestampMillis = mSettings.getLastFullUpdateTimestampMillis();
         if (lastFullUpdateTimestampMillis + fullUpdateIntervalMillis
                 <= System.currentTimeMillis()) {
@@ -216,7 +224,7 @@
         // TODO(b/203605504): reconsider whether the most recent
         //  updated and deleted timestamps are useful.
         ContactsProviderUtil.getUpdatedContactIds(mContext, /*sinceFilter=*/ 0,
-                ContactsIndexerConfig.getContactsFullUpdateLimit(), cp2ContactIds,
+                mContactsIndexerConfig.getContactsFullUpdateLimit(), cp2ContactIds,
                 updateStats);
         return mAppSearchHelper.getAllContactIdsAsync()
                 .thenCompose(appsearchContactIds -> {
@@ -288,7 +296,7 @@
                 // TODO(b/222126568): refactor doDeltaUpdateAsync() to return a future value of
                 //  ContactsUpdateStats so that it can be checked and logged here, instead of the
                 //  placeholder exceptionally() block that only logs to the console.
-                doDeltaUpdateAsync(ContactsIndexerConfig.getContactsDeltaUpdateLimit(),
+                doDeltaUpdateAsync(mContactsIndexerConfig.getContactsDeltaUpdateLimit(),
                         updateStats).exceptionally(t -> {
                     Log.d(TAG, "Failed to index CP2 change", t);
                     return null;
diff --git a/service/java/com/android/server/appsearch/contactsindexer/ContactsProviderUtil.java b/service/java/com/android/server/appsearch/contactsindexer/ContactsProviderUtil.java
index ff32bf1..c9886f7 100644
--- a/service/java/com/android/server/appsearch/contactsindexer/ContactsProviderUtil.java
+++ b/service/java/com/android/server/appsearch/contactsindexer/ContactsProviderUtil.java
@@ -40,6 +40,8 @@
 public final class ContactsProviderUtil {
     private static final String TAG = "ContactsProviderHelper";
 
+    public static final int UPDATE_LIMIT_NONE = -1;
+
     // static final string for querying CP2
     private static final String UPDATE_SINCE = Contacts.CONTACT_LAST_UPDATED_TIMESTAMP + ">?";
     private static final String UPDATE_ORDER_BY = Contacts.CONTACT_LAST_UPDATED_TIMESTAMP + " DESC";
diff --git a/service/java/com/android/server/appsearch/contactsindexer/FrameworkContactsIndexerConfig.java b/service/java/com/android/server/appsearch/contactsindexer/FrameworkContactsIndexerConfig.java
new file mode 100644
index 0000000..007be78
--- /dev/null
+++ b/service/java/com/android/server/appsearch/contactsindexer/FrameworkContactsIndexerConfig.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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.server.appsearch.contactsindexer;
+
+import android.provider.DeviceConfig;
+
+/**
+ * Implementation of {@link ContactsIndexerConfig} using {@link DeviceConfig}.
+ *
+ * <p>It contains all the keys for flags related to Contacts Indexer.
+ *
+ * <p>This class is thread-safe.
+ *
+ * @hide
+ */
+public class FrameworkContactsIndexerConfig implements ContactsIndexerConfig {
+    static final String KEY_CONTACTS_INDEXER_ENABLED = "contacts_indexer_enabled";
+    static final String KEY_CONTACTS_INSTANT_INDEXING_LIMIT = "contacts_instant_indexing_limit";
+    static final String KEY_CONTACTS_FULL_UPDATE_INTERVAL_MILLIS =
+            "contacts_full_update_interval_millis";
+    static final String KEY_CONTACTS_FULL_UPDATE_LIMIT = "contacts_indexer_full_update_limit";
+    static final String KEY_CONTACTS_DELTA_UPDATE_LIMIT = "contacts_indexer_delta_update_limit";
+
+    @Override
+    public boolean isContactsIndexerEnabled() {
+        return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_APPSEARCH,
+                KEY_CONTACTS_INDEXER_ENABLED,
+                DEFAULT_CONTACTS_INDEXER_ENABLED);
+    }
+
+    @Override
+    public int getContactsFirstRunIndexingLimit() {
+        return DeviceConfig.getInt(DeviceConfig.NAMESPACE_APPSEARCH,
+                KEY_CONTACTS_INSTANT_INDEXING_LIMIT, DEFAULT_CONTACTS_FIRST_RUN_INDEXING_LIMIT);
+    }
+
+    @Override
+    public long getContactsFullUpdateIntervalMillis() {
+        return DeviceConfig.getLong(DeviceConfig.NAMESPACE_APPSEARCH,
+                KEY_CONTACTS_FULL_UPDATE_INTERVAL_MILLIS,
+                DEFAULT_CONTACTS_FULL_UPDATE_INTERVAL_MILLIS);
+    }
+
+    @Override
+    public int getContactsFullUpdateLimit() {
+        return DeviceConfig.getInt(DeviceConfig.NAMESPACE_APPSEARCH,
+                KEY_CONTACTS_FULL_UPDATE_LIMIT,
+                DEFAULT_CONTACTS_FULL_UPDATE_INDEXING_LIMIT);
+    }
+
+    @Override
+    public int getContactsDeltaUpdateLimit() {
+        // TODO(b/227419499) Based on the metrics, we can tweak this number. Right now it is same
+        //  as the instant indexing limit, which is 1,000. From our stats in GMSCore, 95th
+        //  percentile for number of contacts on the device is around 2000 contacts.
+        return DeviceConfig.getInt(DeviceConfig.NAMESPACE_APPSEARCH,
+                KEY_CONTACTS_DELTA_UPDATE_LIMIT,
+                DEFAULT_CONTACTS_DELTA_UPDATE_INDEXING_LIMIT);
+    }
+}
diff --git a/testing/contactsindexertests/Android.bp b/testing/contactsindexertests/Android.bp
index 551c061..6464f40 100644
--- a/testing/contactsindexertests/Android.bp
+++ b/testing/contactsindexertests/Android.bp
@@ -34,14 +34,9 @@
         "android.test.mock",
         "android.test.base",
     ],
-    // TODO(b/203690505): Move to general-tests when tests no longer need
-    //  READ_DEVICE_CONFIG permission.
     test_suites: [
-        "device-tests",
+        "general-tests",
         "mts-appsearch",
     ],
     compile_multilib: "both",
-    // TODO(b/203690505): Remove the platform certificate when tests no longer
-    //  need READ_DEVICE_CONFIG permission.
-    certificate: "platform",
 }
diff --git a/testing/contactsindexertests/AndroidManifest.xml b/testing/contactsindexertests/AndroidManifest.xml
index dfb52ea..3f6bcfb 100644
--- a/testing/contactsindexertests/AndroidManifest.xml
+++ b/testing/contactsindexertests/AndroidManifest.xml
@@ -18,9 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.appsearch.contactsindexertests" >
     <uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" />
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
-    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.READ_SYNC_STATS" />
     <application android:label="ContactsIndexerTests"
                  android:debuggable="true">
diff --git a/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsIndexerImplTest.java b/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsIndexerImplTest.java
index 64dad40..42b9505 100644
--- a/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsIndexerImplTest.java
+++ b/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsIndexerImplTest.java
@@ -97,7 +97,7 @@
         List<String> unWantedContactIds = new ArrayList<>();
 
         lastUpdatedTimestamp = ContactsProviderUtil.getUpdatedContactIds(mContext,
-                lastUpdatedTimestamp, ContactsIndexerConfig.UPDATE_LIMIT_NONE,
+                lastUpdatedTimestamp, ContactsProviderUtil.UPDATE_LIMIT_NONE,
                 wantedContactIds, /*stats=*/ null);
         lastDeletedTimestamp = ContactsProviderUtil.getDeletedContactIds(mContext,
                 lastDeletedTimestamp, unWantedContactIds, /*stats=*/ null);
diff --git a/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsIndexerManagerServiceTest.java b/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsIndexerManagerServiceTest.java
index c09a5c7..b52c769 100644
--- a/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsIndexerManagerServiceTest.java
+++ b/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsIndexerManagerServiceTest.java
@@ -41,6 +41,8 @@
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
 
 import com.android.compatibility.common.util.SystemUtil;
 import com.android.server.SystemService;
@@ -93,7 +95,11 @@
                 return getMockContentResolver();
             }
         };
-        mContactsIndexerManagerService = new ContactsIndexerManagerService(mContext);
+        // INTERACT_ACROSS_USERS_FULL: needed when we do registerReceiverForAllUsers for getting
+        // package change notifications.
+        mUiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_FULL);
+        mContactsIndexerManagerService = new ContactsIndexerManagerService(mContext,
+                new TestContactsIndexerConfig());
         mContactsIndexerManagerService.onStart();
         UserInfo userInfo = new UserInfo(userHandle.getIdentifier(), /*name=*/ "default",
                 /*flags=*/ 0);
@@ -108,6 +114,7 @@
                 new AppSearchManager.SearchContext.Builder(AppSearchHelper.DATABASE_NAME).build(),
                 mSingleThreadedExecutor).get();
         db.setSchemaAsync(new SetSchemaRequest.Builder().setForceOverride(true).build()).get();
+        mUiAutomation.dropShellPermissionIdentity();
         super.tearDown();
     }
 
diff --git a/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsIndexerUserInstanceTest.java b/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsIndexerUserInstanceTest.java
index a8139b1..fef2f42 100644
--- a/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsIndexerUserInstanceTest.java
+++ b/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsIndexerUserInstanceTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.appsearch.contactsindexer;
 
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
 import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -49,6 +50,7 @@
 import android.provider.DeviceConfig;
 import android.test.ProviderTestCase2;
 
+import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -81,7 +83,6 @@
 //  stick to ProviderTestCase2 for now.
 @RunWith(AndroidJUnit4.class)
 public class ContactsIndexerUserInstanceTest extends ProviderTestCase2<FakeContactsProvider> {
-
     @Rule
     public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
 
@@ -92,6 +93,7 @@
     private SearchSpec mSpecForQueryAllContacts;
     private ContactsIndexerUserInstance mInstance;
     private ContactsUpdateStats mUpdateStats;
+    private ContactsIndexerConfig mConfigForTest = new TestContactsIndexerConfig();
 
     public ContactsIndexerUserInstanceTest() {
         super(FakeContactsProvider.class, FakeContactsProvider.AUTHORITY);
@@ -115,7 +117,7 @@
                 .build();
 
         mInstance = ContactsIndexerUserInstance.createInstance(mContext, mContactsDir,
-                mSingleThreadedExecutor);
+                mConfigForTest, mSingleThreadedExecutor);
         mUpdateStats = new ContactsUpdateStats();
     }
 
@@ -138,7 +140,7 @@
         File dataDir = new File(mTemporaryFolder.newFolder(), "contacts");
         boolean isDataDirectoryCreatedSynchronously = mSingleThreadedExecutor.submit(() -> {
             ContactsIndexerUserInstance unused =
-                    ContactsIndexerUserInstance.createInstance(mContext, dataDir,
+                    ContactsIndexerUserInstance.createInstance(mContext, dataDir, mConfigForTest,
                             mSingleThreadedExecutor);
             // Data directory shouldn't have been created synchronously in createInstance()
             return dataDir.exists();
@@ -153,13 +155,15 @@
     public void testStart_initialRun_schedulesFullUpdateJob() throws Exception {
         JobScheduler mockJobScheduler = mock(JobScheduler.class);
         mContextWrapper.setJobScheduler(mockJobScheduler);
-        ContactsIndexerUserInstance instance = ContactsIndexerUserInstance.createInstance(mContext,
-                mContactsDir, mSingleThreadedExecutor);
+        ContactsIndexerUserInstance instance = ContactsIndexerUserInstance.createInstance(
+                mContext,
+                mContactsDir, mConfigForTest, mSingleThreadedExecutor);
 
         instance.startAsync();
 
         // Wait for all async tasks to complete
-        mSingleThreadedExecutor.submit(() -> {}).get();
+        mSingleThreadedExecutor.submit(() -> {
+        }).get();
 
         verify(mockJobScheduler).schedule(any());
     }
@@ -172,15 +176,16 @@
 
         JobScheduler mockJobScheduler = mock(JobScheduler.class);
         mContextWrapper.setJobScheduler(mockJobScheduler);
-        ContactsIndexerUserInstance instance = ContactsIndexerUserInstance.createInstance(mContext,
-                mContactsDir, mSingleThreadedExecutor);
+        ContactsIndexerUserInstance instance = ContactsIndexerUserInstance.createInstance(
+                mContext, mContactsDir, mConfigForTest, mSingleThreadedExecutor);
 
         instance.startAsync();
 
         // Wait for all async tasks to complete
-        mSingleThreadedExecutor.submit(() -> {}).get();
+        mSingleThreadedExecutor.submit(() -> {
+            }).get();
 
-        verifyZeroInteractions(mockJobScheduler);
+            verifyZeroInteractions(mockJobScheduler);
     }
 
     @Test
@@ -429,10 +434,11 @@
     @Test
     public void testDeltaUpdate_outOfSpaceError_fullUpdateScheduled() throws Exception {
         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
-        int maxDocumentCountBeforeTest = FrameworkAppSearchConfig.getInstance(
-                mSingleThreadedExecutor).getCachedLimitConfigMaxDocumentCount();
+        int maxDocumentCountBeforeTest = -1;
         try {
-            uiAutomation.adoptShellPermissionIdentity(WRITE_DEVICE_CONFIG);
+            uiAutomation.adoptShellPermissionIdentity(READ_DEVICE_CONFIG, WRITE_DEVICE_CONFIG);
+            maxDocumentCountBeforeTest = FrameworkAppSearchConfig.getInstance(
+                    mSingleThreadedExecutor).getCachedLimitConfigMaxDocumentCount();
             int totalContactCount = 250;
             int maxDocumentCount = 100;
             // Override the configs in AppSearch. This is hard to be mocked since we are not testing
@@ -478,7 +484,7 @@
             }
 
             executeAndWaitForCompletion(
-                    mInstance.doDeltaUpdateAsync(ContactsIndexerConfig.UPDATE_LIMIT_NONE,
+                    mInstance.doDeltaUpdateAsync(ContactsProviderUtil.UPDATE_LIMIT_NONE,
                             mUpdateStats),
                     mSingleThreadedExecutor);
             latch.await(30L, TimeUnit.SECONDS);
@@ -490,9 +496,11 @@
                     settingsBundle.getLong(ContactsIndexerSettings.LAST_DELTA_UPDATE_TIMESTAMP_KEY))
                     .isAtLeast(timeBeforeDeltaChangeNotification);
         } finally {
-            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
-                    FrameworkAppSearchConfig.KEY_LIMIT_CONFIG_MAX_DOCUMENT_COUNT,
-                    String.valueOf(maxDocumentCountBeforeTest), false);
+            if (maxDocumentCountBeforeTest > 0) {
+                DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+                        FrameworkAppSearchConfig.KEY_LIMIT_CONFIG_MAX_DOCUMENT_COUNT,
+                        String.valueOf(maxDocumentCountBeforeTest), false);
+            }
             uiAutomation.dropShellPermissionIdentity();
         }
     }
diff --git a/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsProviderUtilTest.java b/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsProviderUtilTest.java
index 93b1c07..5c25b1b 100644
--- a/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsProviderUtilTest.java
+++ b/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/ContactsProviderUtilTest.java
@@ -68,7 +68,7 @@
 
         List<String> ids = new ArrayList<>();
         long lastUpdatedTime = ContactsProviderUtil.getUpdatedContactIds(mContext,
-                /*sinceFilter=*/ 0, ContactsIndexerConfig.UPDATE_LIMIT_NONE, ids, /*stats=*/ null);
+                /*sinceFilter=*/ 0, ContactsProviderUtil.UPDATE_LIMIT_NONE, ids, /*stats=*/ null);
 
         assertThat(lastUpdatedTime).isEqualTo(
                 getProvider().getMostRecentContactUpdateTimestampMillis());
@@ -86,7 +86,7 @@
         List<String> ids = new ArrayList<>();
         long lastUpdatedTime = ContactsProviderUtil.getUpdatedContactIds(mContext,
                 /*sinceFilter=*/ getProvider().getMostRecentContactUpdateTimestampMillis(),
-                ContactsIndexerConfig.UPDATE_LIMIT_NONE, ids, /*stats=*/ null);
+                ContactsProviderUtil.UPDATE_LIMIT_NONE, ids, /*stats=*/ null);
 
         assertThat(lastUpdatedTime).isEqualTo(
                 getProvider().getMostRecentContactUpdateTimestampMillis());
@@ -108,7 +108,7 @@
 
         List<String> ids = new ArrayList<>();
         long lastUpdatedTime = ContactsProviderUtil.getUpdatedContactIds(mContext,
-                /*sinceFilter=*/ firstUpdateTimestamp, ContactsIndexerConfig.UPDATE_LIMIT_NONE,
+                /*sinceFilter=*/ firstUpdateTimestamp, ContactsProviderUtil.UPDATE_LIMIT_NONE,
                 ids, /*stats=*/ null);
 
         assertThat(lastUpdatedTime).isEqualTo(
diff --git a/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/PersonBuilderHelperTest.java b/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/PersonBuilderHelperTest.java
index e004175..b52aacf 100644
--- a/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/PersonBuilderHelperTest.java
+++ b/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/PersonBuilderHelperTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package contactsindexertests.src.com.android.server.appsearch.contactsindexer;
+package com.android.server.appsearch.contactsindexer;
 
 import android.net.Uri;
 
diff --git a/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/TestContactsIndexerConfig.java b/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/TestContactsIndexerConfig.java
new file mode 100644
index 0000000..7aa31cb
--- /dev/null
+++ b/testing/contactsindexertests/src/com/android/server/appsearch/contactsindexer/TestContactsIndexerConfig.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.server.appsearch.contactsindexer;
+
+/**
+ * Contacts Indexer configuration for testing.
+ *
+ * <p>It simply returns default values.
+ */
+public class TestContactsIndexerConfig implements ContactsIndexerConfig {
+    @Override
+    public boolean isContactsIndexerEnabled() {
+        return DEFAULT_CONTACTS_INDEXER_ENABLED;
+    }
+
+    @Override
+    public int getContactsFirstRunIndexingLimit() {
+        return DEFAULT_CONTACTS_FIRST_RUN_INDEXING_LIMIT;
+    }
+
+    @Override
+    public long getContactsFullUpdateIntervalMillis() {
+        return DEFAULT_CONTACTS_FULL_UPDATE_INTERVAL_MILLIS;
+    }
+
+    @Override
+    public int getContactsFullUpdateLimit() {
+        return DEFAULT_CONTACTS_FULL_UPDATE_INDEXING_LIMIT;
+    }
+
+    @Override
+    public int getContactsDeltaUpdateLimit() {
+        return DEFAULT_CONTACTS_DELTA_UPDATE_INDEXING_LIMIT;
+    }
+}
diff --git a/testing/mockingservicestests/src/com/android/server/appsearch/ContactsIndexer/FrameworkContactsIndexerConfigTest.java b/testing/mockingservicestests/src/com/android/server/appsearch/ContactsIndexer/FrameworkContactsIndexerConfigTest.java
new file mode 100644
index 0000000..a767510
--- /dev/null
+++ b/testing/mockingservicestests/src/com/android/server/appsearch/ContactsIndexer/FrameworkContactsIndexerConfigTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 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.server.appsearch.contactsindexer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.provider.DeviceConfig;
+
+import com.android.modules.utils.testing.TestableDeviceConfig;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+public class FrameworkContactsIndexerConfigTest {
+    @Rule
+    public final TestableDeviceConfig.TestableDeviceConfigRule
+            mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule();
+
+    @Test
+    public void testDefaultValues() {
+        ContactsIndexerConfig contactsIndexerConfig = new FrameworkContactsIndexerConfig();
+
+        assertThat(contactsIndexerConfig.isContactsIndexerEnabled()).isTrue();
+        assertThat(contactsIndexerConfig.getContactsFirstRunIndexingLimit()).isEqualTo(
+                ContactsIndexerConfig.DEFAULT_CONTACTS_FIRST_RUN_INDEXING_LIMIT);
+        assertThat(contactsIndexerConfig.getContactsFullUpdateIntervalMillis()).isEqualTo(
+                ContactsIndexerConfig.DEFAULT_CONTACTS_FULL_UPDATE_INTERVAL_MILLIS);
+        assertThat(contactsIndexerConfig.getContactsFullUpdateLimit()).isEqualTo(
+                ContactsIndexerConfig.DEFAULT_CONTACTS_FULL_UPDATE_INDEXING_LIMIT);
+        assertThat(contactsIndexerConfig.getContactsDeltaUpdateLimit()).isEqualTo(
+                ContactsIndexerConfig.DEFAULT_CONTACTS_DELTA_UPDATE_INDEXING_LIMIT);
+    }
+
+    @Test
+    public void testCustomizedValues() {
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+                FrameworkContactsIndexerConfig.KEY_CONTACTS_INDEXER_ENABLED,
+                Boolean.toString(false),
+                false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+                FrameworkContactsIndexerConfig.KEY_CONTACTS_INSTANT_INDEXING_LIMIT,
+                Integer.toString(
+                        ContactsIndexerConfig.DEFAULT_CONTACTS_FIRST_RUN_INDEXING_LIMIT + 1),
+                false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+                FrameworkContactsIndexerConfig.KEY_CONTACTS_FULL_UPDATE_INTERVAL_MILLIS,
+                Long.toString(
+                        ContactsIndexerConfig.DEFAULT_CONTACTS_FULL_UPDATE_INTERVAL_MILLIS + 1),
+                false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+                FrameworkContactsIndexerConfig.KEY_CONTACTS_FULL_UPDATE_LIMIT,
+                Long.toString(
+                        ContactsIndexerConfig.DEFAULT_CONTACTS_FULL_UPDATE_INDEXING_LIMIT + 1),
+                false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
+                FrameworkContactsIndexerConfig.KEY_CONTACTS_DELTA_UPDATE_LIMIT,
+                Long.toString(
+                        ContactsIndexerConfig.DEFAULT_CONTACTS_DELTA_UPDATE_INDEXING_LIMIT + 1),
+                false);
+
+        ContactsIndexerConfig contactsIndexerConfig = new FrameworkContactsIndexerConfig();
+
+        assertThat(contactsIndexerConfig.isContactsIndexerEnabled()).isFalse();
+        assertThat(contactsIndexerConfig.getContactsFirstRunIndexingLimit()).isEqualTo(
+                ContactsIndexerConfig.DEFAULT_CONTACTS_FIRST_RUN_INDEXING_LIMIT + 1);
+        assertThat(contactsIndexerConfig.getContactsFullUpdateIntervalMillis()).isEqualTo(
+                ContactsIndexerConfig.DEFAULT_CONTACTS_FULL_UPDATE_INTERVAL_MILLIS + 1);
+        assertThat(contactsIndexerConfig.getContactsFullUpdateLimit()).isEqualTo(
+                ContactsIndexerConfig.DEFAULT_CONTACTS_FULL_UPDATE_INDEXING_LIMIT + 1);
+        assertThat(contactsIndexerConfig.getContactsDeltaUpdateLimit()).isEqualTo(
+                ContactsIndexerConfig.DEFAULT_CONTACTS_DELTA_UPDATE_INDEXING_LIMIT + 1);
+    }
+}