[automerger skipped] Import translations. DO NOT MERGE
am: 0b588b0ac8 -s ours
am skip reason: subject contains skip directive

Change-Id: Ibdad27e280d18347641f82a9d28be8ec32718944
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..b6bddce
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,32 @@
+android_app {
+    name: "ContactsProvider",
+    // Only compile source java files in this apk.
+    srcs: [
+        "src/**/*.java",
+        "src/com/android/providers/contacts/EventLogTags.logtags",
+    ],
+    libs: [
+        "ext",
+        "telephony-common",
+    ],
+    static_libs: [
+        "android-common",
+        "com.android.vcard",
+        "guava",
+    ],
+
+    // The Jacoco tool analyzes code coverage when running unit tests on the
+    // application. This configuration line selects which packages will be analyzed,
+    // leaving out code which is tested by other means (e.g. static libraries) that
+    // would dilute the coverage results. These options do not affect regular
+    // production builds.
+    jacoco: {
+        include_filter: ["com.android.providers.contacts.*"],
+    },
+    platform_apis: true,
+    certificate: "shared",
+    privileged: true,
+    optimize: {
+        proguard_flags_files: ["proguard.flags"],
+    },
+}
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index d31ad73..0000000
--- a/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SRC_FILES += \
-        src/com/android/providers/contacts/EventLogTags.logtags
-
-LOCAL_JAVA_LIBRARIES := ext telephony-common
-
-LOCAL_STATIC_JAVA_LIBRARIES += android-common com.android.vcard guava
-
-# The Jacoco tool analyzes code coverage when running unit tests on the
-# application. This configuration line selects which packages will be analyzed,
-# leaving out code which is tested by other means (e.g. static libraries) that
-# would dilute the coverage results. These options do not affect regular
-# production builds.
-LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.providers.contacts.*
-
-LOCAL_PACKAGE_NAME := ContactsProvider
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := shared
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 559e60f..2da56fc 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -16,6 +16,7 @@
     <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
     <uses-permission android:name="android.permission.WRITE_CONTACTS" />
     <uses-permission android:name="android.permission.USE_RESERVED_DISK" />
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
 
     <permission
             android:name="android.permission.SEND_CALL_LOG_CHANGE"
diff --git a/README-tests.md b/README-tests.md
new file mode 100644
index 0000000..8351c6c
--- /dev/null
+++ b/README-tests.md
@@ -0,0 +1,7 @@
+# Running tests
+
+Use the following command to run the unit tests.
+
+```
+atest ContactsProviderTests ContactsProviderTests2
+```
\ No newline at end of file
diff --git a/run-all-tests.sh b/run-all-tests.sh
deleted file mode 100755
index 84a2ce3..0000000
--- a/run-all-tests.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2016 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.
-#
-
-set -e
-
-cd $ANDROID_BUILD_TOP
-
-. build/envsetup.sh
-
-mmm -j32 packages/providers/ContactsProvider
-adb install -t -r -g $ANDROID_PRODUCT_OUT/system/priv-app/ContactsProvider/ContactsProvider.apk
-adb install -t -r -g $ANDROID_PRODUCT_OUT/data/app/ContactsProviderTests/ContactsProviderTests.apk
-adb install -t -r -g $ANDROID_PRODUCT_OUT/data/app/ContactsProviderTests2/ContactsProviderTests2.apk
-
-runtest() {
-    log=/tmp/$$.log
-    adb shell am instrument -w "${@}" |& tee $log
-    if grep -q FAILURES $log || ! grep -P -q 'OK \([1-9]' $log ; then
-        return 1
-    else
-        return 0
-    fi
-
-}
-
-runtest com.android.providers.contacts.tests
-runtest com.android.providers.contacts.tests2
\ No newline at end of file
diff --git a/src/com/android/providers/contacts/CallLogDatabaseHelper.java b/src/com/android/providers/contacts/CallLogDatabaseHelper.java
index 736d665..39c3d5f 100644
--- a/src/com/android/providers/contacts/CallLogDatabaseHelper.java
+++ b/src/com/android/providers/contacts/CallLogDatabaseHelper.java
@@ -39,7 +39,7 @@
 public class CallLogDatabaseHelper {
     private static final String TAG = "CallLogDatabaseHelper";
 
-    private static final int DATABASE_VERSION = 5;
+    private static final int DATABASE_VERSION = 8;
 
     private static final boolean DEBUG = false; // DON'T SUBMIT WITH TRUE
 
@@ -149,6 +149,10 @@
                     Calls.CACHED_FORMATTED_NUMBER + " TEXT," +
                     Calls.ADD_FOR_ALL_USERS + " INTEGER NOT NULL DEFAULT 1," +
                     Calls.LAST_MODIFIED + " INTEGER DEFAULT 0," +
+                    Calls.CALL_SCREENING_COMPONENT_NAME + " TEXT," +
+                    Calls.CALL_SCREENING_APP_NAME + " TEXT," +
+                    Calls.BLOCK_REASON + " INTEGER NOT NULL DEFAULT 0," +
+
                     Voicemails._DATA + " TEXT," +
                     Voicemails.HAS_CONTENT + " INTEGER," +
                     Voicemails.MIME_TYPE + " TEXT," +
@@ -204,6 +208,18 @@
             if (oldVersion < 5) {
                 upgradeToVersion5(db);
             }
+
+            if (oldVersion < 6) {
+                upgradeToVersion6(db);
+            }
+
+            if (oldVersion < 7) {
+                upgradeToVersion7(db);
+            }
+
+            if (oldVersion < 8) {
+                upgradetoVersion8(db);
+            }
         }
     }
 
@@ -280,6 +296,161 @@
     }
 
     /**
+     * Add {@link CallLog.Calls#CALL_SCREENING_COMPONENT_NAME}
+     * {@link CallLog.Calls#CALL_SCREENING_APP_NAME}
+     * {@link CallLog.Calls#BLOCK_REASON} column to the CallLog database.
+     */
+    private void upgradeToVersion6(SQLiteDatabase db) {
+        db.execSQL("ALTER TABLE calls ADD call_screening_component_name TEXT");
+        db.execSQL("ALTER TABLE calls ADD call_screening_app_name TEXT");
+        db.execSQL("ALTER TABLE calls ADD block_reason INTEGER NOT NULL DEFAULT 0");
+    }
+
+    /**
+     * Add {@code android.telecom.CallIdentification} columns; these are destined to be removed
+     * in {@link #upgradetoVersion8(SQLiteDatabase)}.
+     * @param db DB to upgrade
+     */
+    private void upgradeToVersion7(SQLiteDatabase db) {
+        db.execSQL("ALTER TABLE calls ADD call_id_package_name TEXT NULL");
+        db.execSQL("ALTER TABLE calls ADD call_id_app_name TEXT NULL");
+        db.execSQL("ALTER TABLE calls ADD call_id_name TEXT NULL");
+        db.execSQL("ALTER TABLE calls ADD call_id_description TEXT NULL");
+        db.execSQL("ALTER TABLE calls ADD call_id_details TEXT NULL");
+        db.execSQL("ALTER TABLE calls ADD call_id_nuisance_confidence INTEGER NULL");
+    }
+
+    /**
+     * Remove the {@code android.telecom.CallIdentification} column.
+     * @param db DB to upgrade
+     */
+    private void upgradetoVersion8(SQLiteDatabase db) {
+        db.beginTransaction();
+        try {
+            String oldTable = Tables.CALLS + "_old";
+            // SQLite3 doesn't support altering a column name, so we'll rename the old calls table..
+            db.execSQL("ALTER TABLE calls RENAME TO " + oldTable);
+
+            // ... create a new one (yes, this seems similar to what is in onCreate, but we can't
+            // assume that one won't change in the future) ...
+            db.execSQL("CREATE TABLE " + Tables.CALLS + " (" +
+                    Calls._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+                    Calls.NUMBER + " TEXT," +
+                    Calls.NUMBER_PRESENTATION + " INTEGER NOT NULL DEFAULT " +
+                    Calls.PRESENTATION_ALLOWED + "," +
+                    Calls.POST_DIAL_DIGITS + " TEXT NOT NULL DEFAULT ''," +
+                    Calls.VIA_NUMBER + " TEXT NOT NULL DEFAULT ''," +
+                    Calls.DATE + " INTEGER," +
+                    Calls.DURATION + " INTEGER," +
+                    Calls.DATA_USAGE + " INTEGER," +
+                    Calls.TYPE + " INTEGER," +
+                    Calls.FEATURES + " INTEGER NOT NULL DEFAULT 0," +
+                    Calls.PHONE_ACCOUNT_COMPONENT_NAME + " TEXT," +
+                    Calls.PHONE_ACCOUNT_ID + " TEXT," +
+                    Calls.PHONE_ACCOUNT_ADDRESS + " TEXT," +
+                    Calls.PHONE_ACCOUNT_HIDDEN + " INTEGER NOT NULL DEFAULT 0," +
+                    Calls.SUB_ID + " INTEGER DEFAULT -1," +
+                    Calls.NEW + " INTEGER," +
+                    Calls.CACHED_NAME + " TEXT," +
+                    Calls.CACHED_NUMBER_TYPE + " INTEGER," +
+                    Calls.CACHED_NUMBER_LABEL + " TEXT," +
+                    Calls.COUNTRY_ISO + " TEXT," +
+                    Calls.VOICEMAIL_URI + " TEXT," +
+                    Calls.IS_READ + " INTEGER," +
+                    Calls.GEOCODED_LOCATION + " TEXT," +
+                    Calls.CACHED_LOOKUP_URI + " TEXT," +
+                    Calls.CACHED_MATCHED_NUMBER + " TEXT," +
+                    Calls.CACHED_NORMALIZED_NUMBER + " TEXT," +
+                    Calls.CACHED_PHOTO_ID + " INTEGER NOT NULL DEFAULT 0," +
+                    Calls.CACHED_PHOTO_URI + " TEXT," +
+                    Calls.CACHED_FORMATTED_NUMBER + " TEXT," +
+                    Calls.ADD_FOR_ALL_USERS + " INTEGER NOT NULL DEFAULT 1," +
+                    Calls.LAST_MODIFIED + " INTEGER DEFAULT 0," +
+                    Calls.CALL_SCREENING_COMPONENT_NAME + " TEXT," +
+                    Calls.CALL_SCREENING_APP_NAME + " TEXT," +
+                    Calls.BLOCK_REASON + " INTEGER NOT NULL DEFAULT 0," +
+
+                    Voicemails._DATA + " TEXT," +
+                    Voicemails.HAS_CONTENT + " INTEGER," +
+                    Voicemails.MIME_TYPE + " TEXT," +
+                    Voicemails.SOURCE_DATA + " TEXT," +
+                    Voicemails.SOURCE_PACKAGE + " TEXT," +
+                    Voicemails.TRANSCRIPTION + " TEXT," +
+                    Voicemails.TRANSCRIPTION_STATE + " INTEGER NOT NULL DEFAULT 0," +
+                    Voicemails.STATE + " INTEGER," +
+                    Voicemails.DIRTY + " INTEGER NOT NULL DEFAULT 0," +
+                    Voicemails.DELETED + " INTEGER NOT NULL DEFAULT 0," +
+                    Voicemails.BACKED_UP + " INTEGER NOT NULL DEFAULT 0," +
+                    Voicemails.RESTORED + " INTEGER NOT NULL DEFAULT 0," +
+                    Voicemails.ARCHIVED + " INTEGER NOT NULL DEFAULT 0," +
+                    Voicemails.IS_OMTP_VOICEMAIL + " INTEGER NOT NULL DEFAULT 0" +
+                    ");");
+
+            String allTheColumns = Calls._ID + ", " +
+                    Calls.NUMBER + ", " +
+                    Calls.NUMBER_PRESENTATION + ", " +
+                    Calls.POST_DIAL_DIGITS + ", " +
+                    Calls.VIA_NUMBER + ", " +
+                    Calls.DATE + ", " +
+                    Calls.DURATION + ", " +
+                    Calls.DATA_USAGE + ", " +
+                    Calls.TYPE + ", " +
+                    Calls.FEATURES + ", " +
+                    Calls.PHONE_ACCOUNT_COMPONENT_NAME + ", " +
+                    Calls.PHONE_ACCOUNT_ID + ", " +
+                    Calls.PHONE_ACCOUNT_ADDRESS + ", " +
+                    Calls.PHONE_ACCOUNT_HIDDEN + ", " +
+                    Calls.SUB_ID + ", " +
+                    Calls.NEW + ", " +
+                    Calls.CACHED_NAME + ", " +
+                    Calls.CACHED_NUMBER_TYPE + ", " +
+                    Calls.CACHED_NUMBER_LABEL + ", " +
+                    Calls.COUNTRY_ISO + ", " +
+                    Calls.VOICEMAIL_URI + ", " +
+                    Calls.IS_READ + ", " +
+                    Calls.GEOCODED_LOCATION + ", " +
+                    Calls.CACHED_LOOKUP_URI + ", " +
+                    Calls.CACHED_MATCHED_NUMBER + ", " +
+                    Calls.CACHED_NORMALIZED_NUMBER + ", " +
+                    Calls.CACHED_PHOTO_ID + ", " +
+                    Calls.CACHED_PHOTO_URI + ", " +
+                    Calls.CACHED_FORMATTED_NUMBER + ", " +
+                    Calls.ADD_FOR_ALL_USERS + ", " +
+                    Calls.LAST_MODIFIED + ", " +
+                    Calls.CALL_SCREENING_COMPONENT_NAME + ", " +
+                    Calls.CALL_SCREENING_APP_NAME + ", " +
+                    Calls.BLOCK_REASON + ", " +
+
+                    Voicemails._DATA + ", " +
+                    Voicemails.HAS_CONTENT + ", " +
+                    Voicemails.MIME_TYPE + ", " +
+                    Voicemails.SOURCE_DATA + ", " +
+                    Voicemails.SOURCE_PACKAGE + ", " +
+                    Voicemails.TRANSCRIPTION + ", " +
+                    Voicemails.TRANSCRIPTION_STATE + ", " +
+                    Voicemails.STATE + ", " +
+                    Voicemails.DIRTY + ", " +
+                    Voicemails.DELETED + ", " +
+                    Voicemails.BACKED_UP + ", " +
+                    Voicemails.RESTORED + ", " +
+                    Voicemails.ARCHIVED + ", " +
+                    Voicemails.IS_OMTP_VOICEMAIL;
+
+            // .. so we insert into the new table all the values from the old table ...
+            db.execSQL("INSERT INTO " + Tables.CALLS + " (" +
+                    allTheColumns + ") SELECT " +
+                    allTheColumns + " FROM " + oldTable);
+
+            // .. and drop the old table we renamed.
+            db.execSQL("DROP TABLE " + oldTable);
+
+            db.setTransactionSuccessful();
+        } finally {
+            db.endTransaction();
+        }
+    }
+
+    /**
      * Perform the migration from the contacts2.db (of the latest version) to the current calllog/
      * voicemail status tables.
      */
diff --git a/src/com/android/providers/contacts/CallLogProvider.java b/src/com/android/providers/contacts/CallLogProvider.java
index f71a750..ff3e65c 100644
--- a/src/com/android/providers/contacts/CallLogProvider.java
+++ b/src/com/android/providers/contacts/CallLogProvider.java
@@ -157,6 +157,10 @@
         sCallsProjectionMap.put(Calls.CACHED_FORMATTED_NUMBER, Calls.CACHED_FORMATTED_NUMBER);
         sCallsProjectionMap.put(Calls.ADD_FOR_ALL_USERS, Calls.ADD_FOR_ALL_USERS);
         sCallsProjectionMap.put(Calls.LAST_MODIFIED, Calls.LAST_MODIFIED);
+        sCallsProjectionMap
+            .put(Calls.CALL_SCREENING_COMPONENT_NAME, Calls.CALL_SCREENING_COMPONENT_NAME);
+        sCallsProjectionMap.put(Calls.CALL_SCREENING_APP_NAME, Calls.CALL_SCREENING_APP_NAME);
+        sCallsProjectionMap.put(Calls.BLOCK_REASON, Calls.BLOCK_REASON);
     }
 
     private static final String ALLOWED_PACKAGE_FOR_TESTING = "com.android.providers.contacts";
diff --git a/src/com/android/providers/contacts/ContactDirectoryManager.java b/src/com/android/providers/contacts/ContactDirectoryManager.java
index 33e541d..8a1c88b 100644
--- a/src/com/android/providers/contacts/ContactDirectoryManager.java
+++ b/src/com/android/providers/contacts/ContactDirectoryManager.java
@@ -30,9 +30,9 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Directory;
+import android.sysprop.ContactsProperties;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -194,7 +194,7 @@
 
     @VisibleForTesting
     boolean isRescanNeeded() {
-        if ("1".equals(SystemProperties.get("debug.cp2.scan_all_packages", "0"))) {
+        if (ContactsProperties.debug_scan_all_packages().orElse(false)) {
             Log.w(TAG, "debug.cp2.scan_all_packages set to 1.");
             return true; // For debugging.
         }
diff --git a/src/com/android/providers/contacts/ContactsDatabaseHelper.java b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
index 9414ece..163b65d 100644
--- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@ -42,6 +42,7 @@
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.database.sqlite.SQLiteStatement;
+import android.icu.util.VersionInfo;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -83,6 +84,7 @@
 import android.provider.ContactsContract.StatusUpdates;
 import android.provider.ContactsContract.StreamItemPhotos;
 import android.provider.ContactsContract.StreamItems;
+import android.provider.DeviceConfig;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -103,8 +105,6 @@
 import com.android.providers.contacts.database.MoreDatabaseUtils;
 import com.android.providers.contacts.util.NeededForTesting;
 
-import libcore.icu.ICU;
-
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
@@ -137,9 +137,10 @@
      *   1100-1199 N
      *   1200-1299 O
      *   1300-1399 P
+     *   1400-1499 Q
      * </pre>
      */
-    static final int DATABASE_VERSION = 1300;
+    static final int DATABASE_VERSION = 1400;
     private static final int MINIMUM_SUPPORTED_VERSION = 700;
 
     @VisibleForTesting
@@ -147,6 +148,9 @@
 
     private static final int IDLE_CONNECTION_TIMEOUT_MS = 30000;
 
+    private static final String USE_STRICT_PHONE_NUMBER_COMPARISON_KEY
+            = "use_strict_phone_number_comparison";
+
     public interface Tables {
         public static final String CONTACTS = "contacts";
         public static final String DELETED_CONTACTS = "deleted_contacts";
@@ -334,9 +338,6 @@
         public static final String RAW_ENTITIES = "view_raw_entities";
         public static final String GROUPS = "view_groups";
 
-        /** The data_usage_stat table joined with other tables. */
-        public static final String DATA_USAGE_STAT = "view_data_usage_stat";
-
         /** The data_usage_stat table with the low-res columns. */
         public static final String DATA_USAGE_LR = "view_data_usage";
         public static final String STREAM_ITEMS = "view_stream_items";
@@ -423,11 +424,6 @@
         public static final String CONCRETE_PHOTO_FILE_ID = Tables.CONTACTS + "."
                 + Contacts.PHOTO_FILE_ID;
 
-        public static final String CONCRETE_RAW_TIMES_CONTACTED = Tables.CONTACTS + "."
-                + Contacts.RAW_TIMES_CONTACTED;
-        public static final String CONCRETE_RAW_LAST_TIME_CONTACTED = Tables.CONTACTS + "."
-                + Contacts.RAW_LAST_TIME_CONTACTED;
-
         public static final String CONCRETE_STARRED = Tables.CONTACTS + "." + Contacts.STARRED;
         public static final String CONCRETE_PINNED = Tables.CONTACTS + "." + Contacts.PINNED;
         public static final String CONCRETE_CUSTOM_RINGTONE = Tables.CONTACTS + "."
@@ -472,10 +468,6 @@
                 Tables.RAW_CONTACTS + "." + RawContacts.CUSTOM_RINGTONE;
         public static final String CONCRETE_SEND_TO_VOICEMAIL =
                 Tables.RAW_CONTACTS + "." + RawContacts.SEND_TO_VOICEMAIL;
-        public static final String CONCRETE_RAW_LAST_TIME_CONTACTED =
-                Tables.RAW_CONTACTS + "." + RawContacts.RAW_LAST_TIME_CONTACTED;
-        public static final String CONCRETE_RAW_TIMES_CONTACTED =
-                Tables.RAW_CONTACTS + "." + RawContacts.RAW_TIMES_CONTACTED;
         public static final String CONCRETE_STARRED =
                 Tables.RAW_CONTACTS + "." + RawContacts.STARRED;
         public static final String CONCRETE_PINNED =
@@ -749,18 +741,6 @@
         public static final String RAW_TIMES_USED = Data.RAW_TIMES_USED;
         public static final String LR_TIMES_USED = Data.LR_TIMES_USED;
 
-        public static final String CONCRETE_RAW_LAST_TIME_USED =
-                Tables.DATA_USAGE_STAT + "." + RAW_LAST_TIME_USED;
-
-        public static final String CONCRETE_RAW_TIMES_USED =
-                Tables.DATA_USAGE_STAT + "." + RAW_TIMES_USED;
-
-        public static final String CONCRETE_LR_LAST_TIME_USED =
-                Tables.DATA_USAGE_STAT + "." + LR_LAST_TIME_USED;
-
-        public static final String CONCRETE_LR_TIMES_USED =
-                Tables.DATA_USAGE_STAT + "." + LR_TIMES_USED;
-
         /** type: INTEGER */
         public static final String USAGE_TYPE_INT = "usage_type";
         public static final String CONCRETE_USAGE_TYPE =
@@ -929,60 +909,6 @@
         }
     }
 
-    /** Placeholder for the methods to build the "low-res" SQL expressions. */
-    @VisibleForTesting
-    interface LowRes {
-        /** To be replaced with a real column name.  Only used within this interface. */
-        String TEMPLATE_PLACEHOLDER = "XX";
-
-        /**
-         * To be replaced with a constant in the expression.
-         * Only used within this interface.
-         */
-        String CONSTANT_PLACEHOLDER = "YY";
-
-        /** Only used within this interface. */
-        int TIMES_USED_GRANULARITY = 10;
-
-        /** Only used within this interface. */
-        int LAST_TIME_USED_GRANULARITY = 24 * 60 * 60;
-
-        /**
-         * Template to build the "low-res times used/contacted".  Only used within this interface.
-         * The outermost cast is needed to tell SQLite that the result is of the integer type.
-         */
-        String TEMPLATE_TIMES_USED =
-                ("cast(ifnull((case when (XX) <= 0 then 0"
-                + " when (XX) < (YY) then (XX)"
-                + " else (cast((XX) as int) / (YY)) * (YY) end), 0) as int)")
-                .replaceAll(CONSTANT_PLACEHOLDER, String.valueOf(TIMES_USED_GRANULARITY));
-
-        /**
-         * Template to build the "low-res last time used/contacted".
-         * Only used within this interface.
-         * The outermost cast is needed to tell SQLite that the result is of the integer type.
-         */
-        String TEMPLATE_LAST_TIME_USED =
-                ("cast((cast((XX) as int) / (YY)) * (YY) as int)")
-                .replaceAll(CONSTANT_PLACEHOLDER, String.valueOf(LAST_TIME_USED_GRANULARITY));
-
-        /**
-         * Build the SQL expression for the "low-res times used/contacted" expression from the
-         * give column name.
-         */
-        static String getTimesUsedExpression(String column) {
-            return TEMPLATE_TIMES_USED.replaceAll(TEMPLATE_PLACEHOLDER, column);
-        }
-
-        /**
-         * Build the SQL expression for the "low-res last time used/contacted" expression from the
-         * give column name.
-         */
-        static String getLastTimeUsedExpression(String column) {
-            return TEMPLATE_LAST_TIME_USED.replaceAll(TEMPLATE_PLACEHOLDER, column);
-        }
-    }
-
     private static final String TAG = "ContactsDatabaseHelper";
 
     private static final String DATABASE_NAME = "contacts2.db";
@@ -1075,8 +1001,11 @@
         mContext = context;
         mSyncState = new SyncStateContentProviderHelper();
         mCountryMonitor = new CountryMonitor(context);
-        mUseStrictPhoneNumberComparison = resources.getBoolean(
-                com.android.internal.R.bool.config_use_strict_phone_number_comparation);
+        mUseStrictPhoneNumberComparison =
+                DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CONTACTS_PROVIDER,
+                        USE_STRICT_PHONE_NUMBER_COMPARISON_KEY,
+                resources.getBoolean(
+                    com.android.internal.R.bool.config_use_strict_phone_number_comparation));
     }
 
     public SQLiteDatabase getDatabase(boolean writable) {
@@ -1896,7 +1825,7 @@
         db.execSQL("DROP VIEW IF EXISTS " + Views.RAW_CONTACTS + ";");
         db.execSQL("DROP VIEW IF EXISTS " + Views.RAW_ENTITIES + ";");
         db.execSQL("DROP VIEW IF EXISTS " + Views.ENTITIES + ";");
-        db.execSQL("DROP VIEW IF EXISTS " + Views.DATA_USAGE_STAT + ";");
+        db.execSQL("DROP VIEW IF EXISTS view_data_usage_stat;");
         db.execSQL("DROP VIEW IF EXISTS " + Views.DATA_USAGE_LR + ";");
         db.execSQL("DROP VIEW IF EXISTS " + Views.STREAM_ITEMS + ";");
         db.execSQL("DROP VIEW IF EXISTS " + Views.METADATA_SYNC_STATE + ";");
@@ -1972,15 +1901,11 @@
                 + ContactsColumns.CONCRETE_SEND_TO_VOICEMAIL
                         + " AS " + Contacts.SEND_TO_VOICEMAIL + ","
 
-                + ContactsColumns.CONCRETE_RAW_LAST_TIME_CONTACTED
-                        + " AS " + Contacts.RAW_LAST_TIME_CONTACTED + ","
-                + ContactsColumns.CONCRETE_RAW_TIMES_CONTACTED
-                        + " AS " + Contacts.RAW_TIMES_CONTACTED + ","
+                + "0 AS " + Contacts.RAW_LAST_TIME_CONTACTED + ","
+                + "0 AS " + Contacts.RAW_TIMES_CONTACTED + ","
 
-                + LowRes.getLastTimeUsedExpression(ContactsColumns.CONCRETE_RAW_LAST_TIME_CONTACTED)
-                        + " AS " + Contacts.LR_LAST_TIME_CONTACTED + ","
-                + LowRes.getTimesUsedExpression(ContactsColumns.CONCRETE_RAW_TIMES_CONTACTED)
-                        + " AS " + Contacts.LR_TIMES_CONTACTED + ","
+                + "0 AS " + Contacts.LR_LAST_TIME_CONTACTED + ","
+                + "0 AS " + Contacts.LR_TIMES_CONTACTED + ","
 
                 + ContactsColumns.CONCRETE_STARRED
                         + " AS " + Contacts.STARRED + ","
@@ -2051,12 +1976,10 @@
         String rawContactOptionColumns =
                 RawContacts.CUSTOM_RINGTONE + ","
                 + RawContacts.SEND_TO_VOICEMAIL + ","
-                + RawContacts.RAW_LAST_TIME_CONTACTED + ","
-                + LowRes.getLastTimeUsedExpression(RawContacts.RAW_LAST_TIME_CONTACTED)
-                        + " AS " + RawContacts.LR_LAST_TIME_CONTACTED + ","
-                + RawContacts.RAW_TIMES_CONTACTED + ","
-                + LowRes.getTimesUsedExpression(RawContacts.RAW_TIMES_CONTACTED)
-                        + " AS " + RawContacts.LR_TIMES_CONTACTED + ","
+                + "0 AS " + RawContacts.RAW_LAST_TIME_CONTACTED + ","
+                + "0 AS " + RawContacts.LR_LAST_TIME_CONTACTED + ","
+                + "0 AS " + RawContacts.RAW_TIMES_CONTACTED + ","
+                + "0 AS " + RawContacts.LR_TIMES_CONTACTED + ","
                 + RawContacts.STARRED + ","
                 + RawContacts.PINNED;
 
@@ -2094,10 +2017,8 @@
                 + contactNameColumns + ", "
                 + baseContactColumns + ", "
 
-                + ContactsColumns.CONCRETE_RAW_LAST_TIME_CONTACTED
-                        + " AS " + Contacts.RAW_LAST_TIME_CONTACTED + ", "
-                + LowRes.getLastTimeUsedExpression(ContactsColumns.CONCRETE_RAW_LAST_TIME_CONTACTED)
-                        + " AS " + Contacts.LR_LAST_TIME_CONTACTED + ", "
+                + "0 AS " + Contacts.RAW_LAST_TIME_CONTACTED + ", "
+                + "0 AS " + Contacts.LR_LAST_TIME_CONTACTED + ", "
 
                 + ContactsColumns.CONCRETE_SEND_TO_VOICEMAIL
                         + " AS " + Contacts.SEND_TO_VOICEMAIL + ", "
@@ -2106,10 +2027,8 @@
                 + ContactsColumns.CONCRETE_PINNED
                 + " AS " + Contacts.PINNED + ", "
 
-                + ContactsColumns.CONCRETE_RAW_TIMES_CONTACTED
-                        + " AS " + Contacts.RAW_TIMES_CONTACTED + ", "
-                + LowRes.getTimesUsedExpression(ContactsColumns.CONCRETE_RAW_TIMES_CONTACTED)
-                        + " AS " + Contacts.LR_TIMES_CONTACTED;
+                + "0 AS " + Contacts.RAW_TIMES_CONTACTED + ", "
+                + "0 AS " + Contacts.LR_TIMES_CONTACTED;
 
         String contactsSelect = "SELECT "
                 + ContactsColumns.CONCRETE_ID + " AS " + Contacts._ID + ","
@@ -2199,44 +2118,22 @@
         db.execSQL("CREATE VIEW " + Views.ENTITIES + " AS "
                 + entitiesSelect);
 
-        // Data usage view, with the low res columns, with no joins.
+        // View on top of DATA_USAGE_STAT, which is always empty.
         final String dataUsageViewSelect = "SELECT "
                 + DataUsageStatColumns._ID + ", "
                 + DataUsageStatColumns.DATA_ID + ", "
                 + DataUsageStatColumns.USAGE_TYPE_INT + ", "
-                + DataUsageStatColumns.RAW_TIMES_USED + ", "
-                + DataUsageStatColumns.RAW_LAST_TIME_USED + ","
-                + LowRes.getTimesUsedExpression(DataUsageStatColumns.RAW_TIMES_USED)
-                    + " AS " + DataUsageStatColumns.LR_TIMES_USED + ","
-                + LowRes.getLastTimeUsedExpression(DataUsageStatColumns.RAW_LAST_TIME_USED)
-                    + " AS " + DataUsageStatColumns.LR_LAST_TIME_USED
-                + " FROM " + Tables.DATA_USAGE_STAT;
+                + "0 AS " + DataUsageStatColumns.RAW_TIMES_USED + ", "
+                + "0 AS " + DataUsageStatColumns.RAW_LAST_TIME_USED + ","
+                + "0 AS " + DataUsageStatColumns.LR_TIMES_USED + ","
+                + "0 AS " + DataUsageStatColumns.LR_LAST_TIME_USED
+                + " FROM " + Tables.DATA_USAGE_STAT
+                + " WHERE 0";
 
         // When the data_usage_stat table is needed with the low-res columns, use this, which is
         // faster than the DATA_USAGE_STAT view since it doesn't involve joins.
         db.execSQL("CREATE VIEW " + Views.DATA_USAGE_LR + " AS " + dataUsageViewSelect);
 
-        String dataUsageStatSelect = "SELECT "
-                + DataUsageStatColumns.CONCRETE_ID + " AS " + DataUsageStatColumns._ID + ", "
-                + DataUsageStatColumns.DATA_ID + ", "
-                + RawContactsColumns.CONCRETE_CONTACT_ID + " AS " + RawContacts.CONTACT_ID + ", "
-                + MimetypesColumns.CONCRETE_MIMETYPE + " AS " + Data.MIMETYPE + ", "
-                + DataUsageStatColumns.USAGE_TYPE_INT + ", "
-                + DataUsageStatColumns.RAW_TIMES_USED + ", "
-                + DataUsageStatColumns.RAW_LAST_TIME_USED + ", "
-                + DataUsageStatColumns.LR_TIMES_USED + ", "
-                + DataUsageStatColumns.LR_LAST_TIME_USED
-                + " FROM " + Views.DATA_USAGE_LR + " AS " + Tables.DATA_USAGE_STAT
-                + " JOIN " + Tables.DATA + " ON ("
-                +   DataColumns.CONCRETE_ID + "=" + DataUsageStatColumns.CONCRETE_DATA_ID + ")"
-                + " JOIN " + Tables.RAW_CONTACTS + " ON ("
-                +   RawContactsColumns.CONCRETE_ID + "=" + DataColumns.CONCRETE_RAW_CONTACT_ID
-                    + " )"
-                + " JOIN " + Tables.MIMETYPES + " ON ("
-                +   MimetypesColumns.CONCRETE_ID + "=" + DataColumns.CONCRETE_MIMETYPE_ID + ")";
-
-        db.execSQL("CREATE VIEW " + Views.DATA_USAGE_STAT + " AS " + dataUsageStatSelect);
-
         String streamItemSelect = "SELECT " +
                 StreamItemsColumns.CONCRETE_ID + ", " +
                 ContactsColumns.CONCRETE_ID + " AS " + StreamItems.CONTACT_ID + ", " +
@@ -2677,6 +2574,12 @@
             oldVersion = 1300;
         }
 
+        if (isUpgradeRequired(oldVersion, newVersion, 1400)) {
+            ContactsProvider2.deleteDataUsage(db);
+            upgradeViewsAndTriggers = true;
+            oldVersion = 1400;
+        }
+
         // We extracted "calls" and "voicemail_status" at this point, but we can't remove them here
         // yet, until CallLogDatabaseHelper moves the data.
 
@@ -2755,7 +2658,7 @@
         if (!dbLocale.equals(locales.toString())) {
             return true;
         }
-        final String curICUVersion = ICU.getIcuVersion();
+        final String curICUVersion = getDeviceIcuVersion();
         final String dbICUVersion = getProperty(DbProperties.ICU_VERSION,
                 "(unknown)");
         if (!curICUVersion.equals(dbICUVersion)) {
@@ -2766,10 +2669,14 @@
         return false;
     }
 
+    private static String getDeviceIcuVersion() {
+        return VersionInfo.ICU_VERSION.toString();
+    }
+
     private void upgradeLocaleData(SQLiteDatabase db, boolean rebuildSqliteStats) {
         final LocaleSet locales = LocaleSet.newDefault();
         Log.i(TAG, "Upgrading locale data for " + locales
-                + " (ICU v" + ICU.getIcuVersion() + ")");
+                + " (ICU v" + getDeviceIcuVersion() + ")");
         final long start = SystemClock.elapsedRealtime();
         rebuildLocaleData(db, locales, rebuildSqliteStats);
         Log.i(TAG, "Locale update completed in " + (SystemClock.elapsedRealtime() - start) + "ms");
@@ -2788,7 +2695,7 @@
         FastScrollingIndexCache.getInstance(mContext).invalidate();
         // Update the ICU version used to generate the locale derived data
         // so we can tell when we need to rebuild with new ICU versions.
-        PropertyUtils.setProperty(db, DbProperties.ICU_VERSION, ICU.getIcuVersion());
+        PropertyUtils.setProperty(db, DbProperties.ICU_VERSION, getDeviceIcuVersion());
         PropertyUtils.setProperty(db, DbProperties.LOCALE, locales.toString());
     }
 
@@ -2802,7 +2709,7 @@
             return;
         }
         Log.i(TAG, "Switching to locale " + locales
-                + " (ICU v" + ICU.getIcuVersion() + ")");
+                + " (ICU v" + getDeviceIcuVersion() + ")");
 
         final long start = SystemClock.elapsedRealtime();
         SQLiteDatabase db = getWritableDatabase();
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index 54b4a27..4104e37 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -62,7 +62,6 @@
 import android.os.RemoteException;
 import android.os.StrictMode;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.preference.PreferenceManager;
 import android.provider.BaseColumns;
@@ -107,6 +106,7 @@
 import android.provider.OpenableColumns;
 import android.provider.Settings.Global;
 import android.provider.SyncStateContract;
+import android.sysprop.ContactsProperties;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -216,15 +216,6 @@
     private static final String WRITE_PERMISSION = "android.permission.WRITE_CONTACTS";
     private static final String INTERACT_ACROSS_USERS = "android.permission.INTERACT_ACROSS_USERS";
 
-    /* package */ static final String UPDATE_TIMES_CONTACTED_CONTACTS_TABLE =
-          "UPDATE " + Tables.CONTACTS + " SET " + Contacts.RAW_TIMES_CONTACTED + "=" +
-          " ifnull(" + Contacts.RAW_TIMES_CONTACTED + ",0)+1" +
-          " WHERE " + Contacts._ID + "=?";
-
-    /* package */ static final String UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE =
-          "UPDATE " + Tables.RAW_CONTACTS + " SET " + RawContacts.RAW_TIMES_CONTACTED + "=" +
-          " ifnull(" + RawContacts.RAW_TIMES_CONTACTED + ",0)+1 " +
-          " WHERE " + RawContacts.CONTACT_ID + "=?";
 
     /* package */ static final String PHONEBOOK_COLLATOR_NAME = "PHONEBOOK";
 
@@ -291,28 +282,11 @@
 
     private static final int AGGREGATION_ALGORITHM_NEW_VERSION = 5;
 
-    private static final String AGGREGATE_CONTACTS = "sync.contacts.aggregate";
-
     private static final String CONTACT_MEMORY_FILE_NAME = "contactAssetFile";
 
-    /**
-     * If set to "1", we don't remove account data when accounts have been removed.
-     *
-     * This should be used sparingly; even though there are data still available, the UI
-     * don't know anything about them, so they won't show up in the contact filter screen, and
-     * the contact card/editor may get confused to see unknown custom mimetypes.
-     *
-     * We can't spell it out because a property name must be less than 32 chars.
-     */
-    private static final String DEBUG_PROPERTY_KEEP_STALE_ACCOUNT_DATA =
-            "debug.contacts.ksad";
-
     public static final ProfileAwareUriMatcher sUriMatcher =
             new ProfileAwareUriMatcher(UriMatcher.NO_MATCH);
 
-    private static final String FREQUENT_ORDER_BY = DataUsageStatColumns.RAW_TIMES_USED + " DESC,"
-            + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
-
     public static final int CONTACTS = 1000;
     public static final int CONTACTS_ID = 1001;
     public static final int CONTACTS_LOOKUP = 1002;
@@ -595,36 +569,6 @@
             " WHERE " + RawContacts.CONTACT_ID + " = ?1 AND " + Contacts.PINNED + " <= " +
             PinnedPositions.DEMOTED;
 
-    // Contacts contacted within the last 3 days (in seconds)
-    private static final long LAST_TIME_USED_3_DAYS_SEC = 3L * 24 * 60 * 60;
-
-    // Contacts contacted within the last 7 days (in seconds)
-    private static final long LAST_TIME_USED_7_DAYS_SEC = 7L * 24 * 60 * 60;
-
-    // Contacts contacted within the last 14 days (in seconds)
-    private static final long LAST_TIME_USED_14_DAYS_SEC = 14L * 24 * 60 * 60;
-
-    // Contacts contacted within the last 30 days (in seconds)
-    private static final long LAST_TIME_USED_30_DAYS_SEC = 30L * 24 * 60 * 60;
-
-    private static final String RAW_TIME_SINCE_LAST_USED_SEC =
-            "(strftime('%s', 'now') - " + DataUsageStatColumns.RAW_LAST_TIME_USED + "/1000)";
-
-    private static final String LR_TIME_SINCE_LAST_USED_SEC =
-            "(strftime('%s', 'now') - " + DataUsageStatColumns.LR_LAST_TIME_USED + "/1000)";
-
-    private static final String SORT_BY_DATA_USAGE =
-            "(CASE WHEN " + RAW_TIME_SINCE_LAST_USED_SEC + " < " + LAST_TIME_USED_3_DAYS_SEC +
-            " THEN 0 " +
-                    " WHEN " + RAW_TIME_SINCE_LAST_USED_SEC + " < " + LAST_TIME_USED_7_DAYS_SEC +
-            " THEN 1 " +
-                    " WHEN " + RAW_TIME_SINCE_LAST_USED_SEC + " < " + LAST_TIME_USED_14_DAYS_SEC +
-            " THEN 2 " +
-                    " WHEN " + RAW_TIME_SINCE_LAST_USED_SEC + " < " + LAST_TIME_USED_30_DAYS_SEC +
-            " THEN 3 " +
-            " ELSE 4 END), " +
-            DataUsageStatColumns.RAW_TIMES_USED + " DESC";
-
     /*
      * Sorting order for email address suggestions: first starred, then the rest.
      * Within the two groups:
@@ -637,7 +581,6 @@
     private static final String EMAIL_FILTER_SORT_ORDER =
         Contacts.STARRED + " DESC, "
         + Data.IS_SUPER_PRIMARY + " DESC, "
-        + SORT_BY_DATA_USAGE + ", "
         + Contacts.IN_VISIBLE_GROUP + " DESC, "
         + Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC, "
         + Data.CONTACT_ID + ", "
@@ -676,7 +619,7 @@
             .add(Contacts.DISPLAY_NAME_SOURCE)
             .add(Contacts.IN_DEFAULT_DIRECTORY)
             .add(Contacts.IN_VISIBLE_GROUP)
-            .add(Contacts.LR_LAST_TIME_CONTACTED)
+            .add(Contacts.LR_LAST_TIME_CONTACTED, "0")
             .add(Contacts.LOOKUP_KEY)
             .add(Contacts.PHONETIC_NAME)
             .add(Contacts.PHONETIC_NAME_STYLE)
@@ -693,7 +636,7 @@
             .add(ContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE)
             .add(Contacts.STARRED)
             .add(Contacts.PINNED)
-            .add(Contacts.LR_TIMES_CONTACTED)
+            .add(Contacts.LR_TIMES_CONTACTED, "0")
             .add(Contacts.HAS_PHONE_NUMBER)
             .add(Contacts.CONTACT_LAST_UPDATED_TIMESTAMP)
             .build();
@@ -796,8 +739,8 @@
             .build();
 
     private static final ProjectionMap sDataUsageColumns = ProjectionMap.builder()
-            .add(Data.LR_TIMES_USED, Tables.DATA_USAGE_STAT + "." + Data.LR_TIMES_USED)
-            .add(Data.LR_LAST_TIME_USED, Tables.DATA_USAGE_STAT + "." + Data.LR_LAST_TIME_USED)
+            .add(Data.LR_TIMES_USED, "0")
+            .add(Data.LR_LAST_TIME_USED, "0")
             .build();
 
     /** Contains just BaseColumns._COUNT */
@@ -830,12 +773,8 @@
 
     private static final ProjectionMap sStrequentFrequentProjectionMap = ProjectionMap.builder()
             .addAll(sContactsProjectionMap)
-            // Note this should ideally be "lowres(SUM)" rather than "SUM(lowres)", but we do it
-            // this way for performance reasons.
-            .add(DataUsageStatColumns.LR_TIMES_USED,
-                    "SUM(" + DataUsageStatColumns.CONCRETE_LR_TIMES_USED + ")")
-            .add(DataUsageStatColumns.LR_LAST_TIME_USED,
-                    "MAX(" + DataUsageStatColumns.CONCRETE_LR_LAST_TIME_USED + ")")
+            .add(DataUsageStatColumns.LR_TIMES_USED, "0")
+            .add(DataUsageStatColumns.LR_LAST_TIME_USED, "0")
             .build();
 
     /**
@@ -847,8 +786,8 @@
     private static final ProjectionMap sStrequentPhoneOnlyProjectionMap
             = ProjectionMap.builder()
             .addAll(sContactsProjectionMap)
-            .add(DataUsageStatColumns.LR_TIMES_USED)
-            .add(DataUsageStatColumns.LR_LAST_TIME_USED)
+            .add(DataUsageStatColumns.LR_TIMES_USED, "0")
+            .add(DataUsageStatColumns.LR_LAST_TIME_USED, "0")
             .add(Phone.NUMBER)
             .add(Phone.TYPE)
             .add(Phone.LABEL)
@@ -1004,6 +943,8 @@
             .add(PhoneLookup.TYPE, Phone.TYPE)
             .add(PhoneLookup.LABEL, Phone.LABEL)
             .add(PhoneLookup.NORMALIZED_NUMBER, Phone.NORMALIZED_NUMBER)
+            .add(Data.PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME)
+            .add(Data.PREFERRED_PHONE_ACCOUNT_ID)
             .build();
 
     /** Contains the just the {@link Groups} columns */
@@ -1644,7 +1585,7 @@
                 createPhotoPriorityResolver(getContext()), mNameSplitter, mCommonNicknameCache)
                 : new ContactAggregator(this, mContactsHelper,
                 createPhotoPriorityResolver(getContext()), mNameSplitter, mCommonNicknameCache);
-        mContactAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true));
+        mContactAggregator.setEnabled(ContactsProperties.aggregate_contacts().orElse(true));
         initDataRowHandlers(mDataRowHandlers, mContactsHelper, mContactAggregator,
                 mContactsPhotoStore);
     }
@@ -1676,10 +1617,10 @@
                 : new ContactAggregator2(this, mContactsHelper,
                         createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache);
 
-        mContactAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true));
+        mContactAggregator.setEnabled(ContactsProperties.aggregate_contacts().orElse(true));
         mProfileAggregator = new ProfileAggregator(this, mProfileHelper,
                 createPhotoPriorityResolver(context), mNameSplitter, mCommonNicknameCache);
-        mProfileAggregator.setEnabled(SystemProperties.getBoolean(AGGREGATE_CONTACTS, true));
+        mProfileAggregator.setEnabled(ContactsProperties.aggregate_contacts().orElse(true));
         mSearchIndexManager = new SearchIndexManager(this);
         mContactsPhotoStore = new PhotoStore(getContext().getFilesDir(), mContactsHelper);
         mProfilePhotoStore =
@@ -3698,7 +3639,7 @@
             }
 
             case CONTACTS_DELETE_USAGE: {
-                return deleteDataUsage();
+                return deleteDataUsage(db);
             }
 
             case RAW_CONTACTS:
@@ -4002,8 +3943,7 @@
                 /* callerIsMetadataSyncAdapter =*/false);
     }
 
-    private int deleteDataUsage() {
-        final SQLiteDatabase db = mDbHelper.get().getWritableDatabase();
+    static int deleteDataUsage(SQLiteDatabase db) {
         db.execSQL("UPDATE " + Tables.RAW_CONTACTS + " SET " +
                 Contacts.RAW_TIMES_CONTACTED + "=0," +
                 Contacts.RAW_LAST_TIME_CONTACTED + "=NULL");
@@ -4247,7 +4187,7 @@
             }
 
             case DATA_USAGE_FEEDBACK_ID: {
-                count = handleDataUsageFeedback(uri) ? 1 : 0;
+                count = 0;
                 break;
             }
 
@@ -4521,21 +4461,20 @@
      * LAST_TIME_CONTACTED.
      */
     private ContentValues fixUpUsageColumnsForEdit(ContentValues cv) {
-        if (!cv.containsKey(Contacts.LR_LAST_TIME_CONTACTED)
-                && !cv.containsKey(Contacts.LR_TIMES_CONTACTED)) {
+        final boolean hasLastTime = cv.containsKey(Contacts.LR_LAST_TIME_CONTACTED);
+        final boolean hasTimes = cv.containsKey(Contacts.LR_TIMES_CONTACTED);
+        if (!hasLastTime && !hasTimes) {
             return cv;
         }
         final ContentValues ret = new ContentValues(cv);
-
-        ContactsDatabaseHelper.copyLongValue(
-                ret, Contacts.RAW_LAST_TIME_CONTACTED,
-                ret, Contacts.LR_LAST_TIME_CONTACTED);
-        ContactsDatabaseHelper.copyLongValue(
-                ret, Contacts.RAW_TIMES_CONTACTED,
-                ret, Contacts.LR_TIMES_CONTACTED);
-
-        ret.remove(Contacts.LR_LAST_TIME_CONTACTED);
-        ret.remove(Contacts.LR_TIMES_CONTACTED);
+        if (hasLastTime) {
+            ret.putNull(Contacts.RAW_LAST_TIME_CONTACTED);
+            ret.remove(Contacts.LR_LAST_TIME_CONTACTED);
+        }
+        if (hasTimes) {
+            ret.put(Contacts.RAW_TIMES_CONTACTED, 0);
+            ret.remove(Contacts.LR_TIMES_CONTACTED);
+        }
         return ret;
     }
 
@@ -4797,12 +4736,12 @@
         ContactsDatabaseHelper.copyLongValue(
                 values, RawContacts.SEND_TO_VOICEMAIL,
                 inputValues, Contacts.SEND_TO_VOICEMAIL);
-        ContactsDatabaseHelper.copyLongValue(
-                values, RawContacts.RAW_LAST_TIME_CONTACTED,
-                inputValues, Contacts.RAW_LAST_TIME_CONTACTED);
-        ContactsDatabaseHelper.copyLongValue(
-                values, RawContacts.RAW_TIMES_CONTACTED,
-                inputValues, Contacts.RAW_TIMES_CONTACTED);
+        if (inputValues.containsKey(RawContacts.RAW_LAST_TIME_CONTACTED)) {
+            values.putNull(RawContacts.RAW_LAST_TIME_CONTACTED);
+        }
+        if (inputValues.containsKey(RawContacts.RAW_TIMES_CONTACTED)) {
+            values.put(RawContacts.RAW_TIMES_CONTACTED, 0);
+        }
         ContactsDatabaseHelper.copyLongValue(
                 values, RawContacts.STARRED,
                 inputValues, Contacts.STARRED);
@@ -4862,12 +4801,12 @@
         ContactsDatabaseHelper.copyLongValue(
                 values, RawContacts.SEND_TO_VOICEMAIL,
                 inputValues, Contacts.SEND_TO_VOICEMAIL);
-        ContactsDatabaseHelper.copyLongValue(
-                values, RawContacts.RAW_LAST_TIME_CONTACTED,
-                inputValues, Contacts.RAW_LAST_TIME_CONTACTED);
-        ContactsDatabaseHelper.copyLongValue(
-                values, RawContacts.RAW_TIMES_CONTACTED,
-                inputValues, Contacts.RAW_TIMES_CONTACTED);
+        if (inputValues.containsKey(RawContacts.RAW_LAST_TIME_CONTACTED)) {
+            values.putNull(RawContacts.RAW_LAST_TIME_CONTACTED);
+        }
+        if (inputValues.containsKey(RawContacts.RAW_TIMES_CONTACTED)) {
+            values.put(RawContacts.RAW_TIMES_CONTACTED, 0);
+        }
         ContactsDatabaseHelper.copyLongValue(
                 values, RawContacts.STARRED,
                 inputValues, Contacts.STARRED);
@@ -4881,11 +4820,6 @@
         int rslt = db.update(Tables.CONTACTS, values, Contacts._ID + "=?",
                 mSelectionArgs1);
 
-        if (inputValues.containsKey(Contacts.RAW_LAST_TIME_CONTACTED) &&
-                !inputValues.containsKey(Contacts.RAW_TIMES_CONTACTED)) {
-            db.execSQL(UPDATE_TIMES_CONTACTED_CONTACTS_TABLE, mSelectionArgs1);
-            db.execSQL(UPDATE_TIMES_CONTACTED_RAWCONTACTS_TABLE, mSelectionArgs1);
-        }
         return rslt;
     }
 
@@ -5112,20 +5046,6 @@
                         dataValues, null, null, /* callerIsSyncAdapter =*/true,
                         /* callerIsMetadataSyncAdapter =*/true);
 
-                // Update UsageStats.
-                for (int j = 0; j < fieldData.mUsageStatsList.size(); j++) {
-                    final UsageStats usageStats = fieldData.mUsageStatsList.get(j);
-                    final String usageType = usageStats.mUsageType;
-                    final int typeInt = getDataUsageFeedbackType(usageType.toLowerCase(), null);
-                    final long lastTimeUsed = usageStats.mLastTimeUsed;
-                    final int timesUsed = usageStats.mTimesUsed;
-                    ContentValues usageStatsValues = new ContentValues();
-                    usageStatsValues.put(DataUsageStatColumns.DATA_ID, dataId);
-                    usageStatsValues.put(DataUsageStatColumns.USAGE_TYPE_INT, typeInt);
-                    usageStatsValues.put(DataUsageStatColumns.RAW_LAST_TIME_USED, lastTimeUsed);
-                    usageStatsValues.put(DataUsageStatColumns.RAW_TIMES_USED, timesUsed);
-                    updateDataUsageStats(db, usageStatsValues);
-                }
             }
         }
 
@@ -5232,9 +5152,8 @@
         if (!haveAccountsChanged(systemAccounts)) {
             return false;
         }
-        if ("1".equals(SystemProperties.get(DEBUG_PROPERTY_KEEP_STALE_ACCOUNT_DATA))) {
-            Log.w(TAG, "Accounts changed, but not removing stale data for " +
-                    DEBUG_PROPERTY_KEEP_STALE_ACCOUNT_DATA);
+        if (ContactsProperties.keep_stale_account_data().orElse(false)) {
+            Log.w(TAG, "Accounts changed, but not removing stale data for debug.contacts.ksad");
             return true;
         }
         Log.i(TAG, "Accounts changed");
@@ -6000,11 +5919,8 @@
             }
             case CONTACTS_STREQUENT_FILTER:
             case CONTACTS_STREQUENT: {
-                // Basically the resultant SQL should look like this:
-                // (SQL for listing starred items)
-                // UNION ALL
-                // (SQL for listing frequently contacted items)
-                // ORDER BY ...
+                // Note we used to use a union query to merge starred contacts and frequent
+                // contacts. Since we no longer have frequent contacts, we don't use union any more.
 
                 final boolean phoneOnly = readBooleanQueryParameter(
                         uri, ContactsContract.STREQUENT_PHONE_ONLY, false);
@@ -6027,9 +5943,6 @@
                 // String that will store the query for starred contacts. For phone only queries,
                 // these will return a list of all phone numbers that belong to starred contacts.
                 final String starredInnerQuery;
-                // String that will store the query for frequents. These JOINS can be very slow
-                // if assembled in the wrong order. Be sure to test changes against huge databases.
-                final String frequentInnerQuery;
 
                 if (phoneOnly) {
                     final StringBuilder tableBuilder = new StringBuilder();
@@ -6067,7 +5980,7 @@
                             phoneMimeTypeId + ", " + sipMimeTypeId + ")) AND (" +
                             RawContacts.CONTACT_ID + " IN " + Tables.DEFAULT_DIRECTORY + ")"));
                     starredInnerQuery = qb.buildQuery(subProjection, null, null,
-                        null, Data.IS_SUPER_PRIMARY + " DESC," + SORT_BY_DATA_USAGE, null);
+                        null, Data.IS_SUPER_PRIMARY + " DESC", null);
 
                     qb = new SQLiteQueryBuilder();
                     qb.setStrict(true);
@@ -6095,9 +6008,6 @@
                             DataColumns.MIMETYPE_ID + " IN (" +
                             phoneMimeTypeId + ", " + sipMimeTypeId + ")) AND (" +
                             RawContacts.CONTACT_ID + " IN " + Tables.DEFAULT_DIRECTORY + ")"));
-                    frequentInnerQuery = qb.buildQuery(subProjection, null, null, null,
-                            SORT_BY_DATA_USAGE, "25");
-
                 } else {
                     // Build the first query for starred contacts
                     qb.setStrict(true);
@@ -6108,53 +6018,9 @@
                             DbQueryUtils.concatenateClauses(selection, Contacts.STARRED + "=1"),
                             Contacts._ID, null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC",
                             null);
-
-                    // Reset the builder, and build the second query for frequents contacts
-                    qb = new SQLiteQueryBuilder();
-                    qb.setStrict(true);
-
-                    setTablesAndProjectionMapForContacts(qb, projection, true);
-                    qb.setProjectionMap(sStrequentFrequentProjectionMap);
-                    qb.appendWhere(DbQueryUtils.concatenateClauses(
-                            selection,
-                            "(" + Contacts.STARRED + " =0 OR " + Contacts.STARRED + " IS NULL)"));
-                    // Note frequentInnerQuery is a grouping query, so the "IN default_directory"
-                    // selection needs to be in HAVING, not in WHERE.
-                    final String HAVING =
-                            RawContacts.CONTACT_ID + " IN " + Tables.DEFAULT_DIRECTORY;
-                    frequentInnerQuery = qb.buildQuery(subProjection,
-                            null, Contacts._ID, HAVING, SORT_BY_DATA_USAGE, "25");
                 }
 
-                // We need to wrap the inner queries in an extra select, because they contain
-                // their own SORT and LIMIT
-
-                // Phone numbers that were used more than 30 days ago are dropped from frequents
-                final String frequentQuery = "SELECT * FROM (" + frequentInnerQuery + ") WHERE " +
-                        LR_TIME_SINCE_LAST_USED_SEC + "<" + LAST_TIME_USED_30_DAYS_SEC;
-                final String starredQuery = "SELECT * FROM (" + starredInnerQuery + ")";
-
-                // Put them together
-                final String unionQuery =
-                        qb.buildUnionQuery(new String[] {starredQuery, frequentQuery}, null, null);
-
-                // Here, we need to use selection / selectionArgs (supplied from users) "twice",
-                // as we want them both for starred items and for frequently contacted items.
-                //
-                // e.g. if the user specify selection = "starred =?" and selectionArgs = "0",
-                // the resultant SQL should be like:
-                // SELECT ... WHERE starred =? AND ...
-                // UNION ALL
-                // SELECT ... WHERE starred =? AND ...
-                String[] doubledSelectionArgs = null;
-                if (selectionArgs != null) {
-                    final int length = selectionArgs.length;
-                    doubledSelectionArgs = new String[length * 2];
-                    System.arraycopy(selectionArgs, 0, doubledSelectionArgs, 0, length);
-                    System.arraycopy(selectionArgs, 0, doubledSelectionArgs, length, length);
-                }
-
-                Cursor cursor = db.rawQuery(unionQuery, doubledSelectionArgs);
+                Cursor cursor = db.rawQuery(starredInnerQuery, selectionArgs);
                 if (cursor != null) {
                     cursor.setNotificationUri(
                             getContext().getContentResolver(), ContactsContract.AUTHORITY_URI);
@@ -6166,12 +6032,8 @@
                 setTablesAndProjectionMapForContacts(qb, projection, true);
                 qb.setProjectionMap(sStrequentFrequentProjectionMap);
                 groupBy = Contacts._ID;
-                having = Contacts._ID + " IN " + Tables.DEFAULT_DIRECTORY;
-                if (!TextUtils.isEmpty(sortOrder)) {
-                    sortOrder = FREQUENT_ORDER_BY + ", " + sortOrder;
-                } else {
-                    sortOrder = FREQUENT_ORDER_BY;
-                }
+                selection = "(0)";
+                selectionArgs = null;
                 break;
             }
 
@@ -8042,17 +7904,20 @@
             SQLiteQueryBuilder qb, String[] projection, boolean includeDataUsageStat) {
         StringBuilder sb = new StringBuilder();
         if (includeDataUsageStat) {
-            sb.append(Views.DATA_USAGE_STAT + " AS " + Tables.DATA_USAGE_STAT);
+            // The result will always be empty, but we still need the columns.
+            sb.append(Tables.DATA_USAGE_STAT);
             sb.append(" INNER JOIN ");
         }
 
         sb.append(Views.CONTACTS);
 
         // Just for frequently contacted contacts in Strequent URI handling.
+        // We no longer support frequent, so we do "(0)", but we still need to execute the query
+        // for the columns.
         if (includeDataUsageStat) {
             sb.append(" ON (" +
                     DbQueryUtils.concatenateClauses(
-                            DataUsageStatColumns.CONCRETE_RAW_TIMES_USED + " > 0",
+                            "(0)",
                             RawContacts.CONTACT_ID + "=" + Views.CONTACTS + "." + Contacts._ID) +
                     ")");
         }
@@ -8438,38 +8303,20 @@
     }
 
     private void appendDataUsageStatJoin(StringBuilder sb, int usageType, String dataIdColumn) {
-        if (usageType != USAGE_TYPE_ALL) {
-            sb.append(" LEFT OUTER JOIN " + Views.DATA_USAGE_LR +
-                    " as " + Tables.DATA_USAGE_STAT +
-                    " ON (" + DataUsageStatColumns.CONCRETE_DATA_ID + "=");
-            sb.append(dataIdColumn);
-            sb.append(" AND " + DataUsageStatColumns.CONCRETE_USAGE_TYPE + "=");
-            sb.append(usageType);
-            sb.append(")");
-        } else {
-            sb.append(
-                    " LEFT OUTER JOIN " +
-                        "(SELECT " +
-                            DataUsageStatColumns.DATA_ID + " as STAT_DATA_ID," +
-                            " SUM(ifnull(" + DataUsageStatColumns.RAW_TIMES_USED +
-                                ",0)) as " + DataUsageStatColumns.RAW_TIMES_USED + ", " +
-                            " MAX(ifnull(" + DataUsageStatColumns.RAW_LAST_TIME_USED +
-                                ",0)) as " + DataUsageStatColumns.RAW_LAST_TIME_USED + "," +
-
-                            // Note this is not ideal -- we should use "lowres(sum(LR_TIMES_USED))"
-                            // here, but for performance reasons we just do it simple.
-                            " SUM(ifnull(" + DataUsageStatColumns.LR_TIMES_USED +
-                                ",0)) as " + DataUsageStatColumns.LR_TIMES_USED + ", " +
-
-                            " MAX(ifnull(" + DataUsageStatColumns.LR_LAST_TIME_USED +
-                                ",0)) as " + DataUsageStatColumns.LR_LAST_TIME_USED +
-                        " FROM " + Views.DATA_USAGE_LR + " GROUP BY " +
-                            DataUsageStatColumns.DATA_ID + ") as " + Tables.DATA_USAGE_STAT
-                    );
-            sb.append(" ON (STAT_DATA_ID=");
-            sb.append(dataIdColumn);
-            sb.append(")");
-        }
+        sb.append(
+                // 0 rows, just populate the columns.
+                " LEFT OUTER JOIN " +
+                "(SELECT " +
+                "0 as STAT_DATA_ID," +
+                "0 as " + DataUsageStatColumns.RAW_TIMES_USED + ", " +
+                "0 as " + DataUsageStatColumns.RAW_LAST_TIME_USED + "," +
+                "0 as " + DataUsageStatColumns.LR_TIMES_USED + ", " +
+                "0 as " + DataUsageStatColumns.LR_LAST_TIME_USED +
+                " where 0) as " + Tables.DATA_USAGE_STAT
+        );
+        sb.append(" ON (STAT_DATA_ID=");
+        sb.append(dataIdColumn);
+        sb.append(")");
     }
 
     private void appendContactPresenceJoin(
@@ -9844,181 +9691,6 @@
         db.execSQL(UNDEMOTE_RAW_CONTACT, arg);
     }
 
-    private boolean handleDataUsageFeedback(Uri uri) {
-        final long currentTimeMillis = Clock.getInstance().currentTimeMillis();
-        final String usageType = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE);
-        final String[] ids = uri.getLastPathSegment().trim().split(",");
-        final ArrayList<Long> dataIds = new ArrayList<Long>(ids.length);
-
-        for (String id : ids) {
-            dataIds.add(Long.valueOf(id));
-        }
-        final boolean successful;
-        if (TextUtils.isEmpty(usageType)) {
-            Log.w(TAG, "Method for data usage feedback isn't specified. Ignoring.");
-            successful = false;
-        } else {
-            successful = updateDataUsageStat(dataIds, usageType, currentTimeMillis) > 0;
-        }
-
-        // Handle old API. This doesn't affect the result of this entire method.
-        final StringBuilder rawContactIdSelect = new StringBuilder();
-        rawContactIdSelect.append("SELECT " + Data.RAW_CONTACT_ID + " FROM " + Tables.DATA +
-                " WHERE " + Data._ID + " IN (");
-        for (int i = 0; i < ids.length; i++) {
-            if (i > 0) {
-                rawContactIdSelect.append(",");
-            }
-            rawContactIdSelect.append(ids[i]);
-        }
-        rawContactIdSelect.append(")");
-
-        final SQLiteDatabase db = mDbHelper.get().getWritableDatabase();
-
-        final Set<Long> rawContactIds = new ArraySet<>();
-        final Cursor cursor = db.rawQuery(rawContactIdSelect.toString(), null);
-        try {
-            cursor.moveToPosition(-1);
-            while (cursor.moveToNext()) {
-                final long rid =   cursor.getLong(0);
-                mTransactionContext.get().markRawContactMetadataDirty(rid,
-                        /* isMetadataSyncAdapter =*/false);
-                rawContactIds.add(rid);
-            }
-        } finally {
-            cursor.close();
-        }
-
-        mSelectionArgs1[0] = String.valueOf(currentTimeMillis);
-        final String rids = TextUtils.join(",", rawContactIds);
-
-        db.execSQL("UPDATE " + Tables.RAW_CONTACTS +
-                " SET " + RawContacts.RAW_LAST_TIME_CONTACTED + "=?" +
-                "," + RawContacts.RAW_TIMES_CONTACTED + "=" +
-                    "ifnull(" + RawContacts.RAW_TIMES_CONTACTED + ",0) + 1" +
-                " WHERE " + RawContacts._ID + " IN (" + rids + ")"
-                , mSelectionArgs1);
-        db.execSQL("UPDATE " + Tables.CONTACTS +
-                " SET " + Contacts.RAW_LAST_TIME_CONTACTED + "=?1" +
-                "," + Contacts.RAW_TIMES_CONTACTED + "=" +
-                    "ifnull(" + Contacts.RAW_TIMES_CONTACTED + ",0) + 1" +
-                "," + Contacts.CONTACT_LAST_UPDATED_TIMESTAMP + "=?1" +
-                " WHERE " + Contacts._ID + " IN (SELECT " + RawContacts.CONTACT_ID +
-                    " FROM " + Tables.RAW_CONTACTS +
-                    " WHERE " + RawContacts._ID + " IN (" + rids + "))"
-                , mSelectionArgs1);
-
-        return successful;
-    }
-
-    private interface DataUsageStatQuery {
-        String TABLE = Tables.DATA_USAGE_STAT;
-        String[] COLUMNS = new String[] {DataUsageStatColumns._ID};
-        int ID = 0;
-        String SELECTION = DataUsageStatColumns.DATA_ID + " =? AND "
-                + DataUsageStatColumns.USAGE_TYPE_INT + " =?";
-    }
-
-    /**
-     * Update {@link Tables#DATA_USAGE_STAT}.
-     *
-     * @return the number of rows affected.
-     */
-    @VisibleForTesting
-    /* package */ int updateDataUsageStat(
-            List<Long> dataIds, String type, long currentTimeMillis) {
-
-        final SQLiteDatabase db = mDbHelper.get().getWritableDatabase();
-
-        final String typeString = String.valueOf(getDataUsageFeedbackType(type, null));
-        final String currentTimeMillisString = String.valueOf(currentTimeMillis);
-
-        for (long dataId : dataIds) {
-            final String dataIdString = String.valueOf(dataId);
-            mSelectionArgs2[0] = dataIdString;
-            mSelectionArgs2[1] = typeString;
-            final Cursor cursor = db.query(DataUsageStatQuery.TABLE,
-                    DataUsageStatQuery.COLUMNS, DataUsageStatQuery.SELECTION,
-                    mSelectionArgs2, null, null, null);
-            try {
-                if (cursor.moveToFirst()) {
-                    final long id = cursor.getLong(DataUsageStatQuery.ID);
-
-                    mSelectionArgs2[0] = currentTimeMillisString;
-                    mSelectionArgs2[1] = String.valueOf(id);
-
-                    db.execSQL("UPDATE " + Tables.DATA_USAGE_STAT +
-                            " SET " + DataUsageStatColumns.RAW_TIMES_USED + "=" +
-                                "ifnull(" + DataUsageStatColumns.RAW_TIMES_USED +",0)+1" +
-                            "," + DataUsageStatColumns.RAW_LAST_TIME_USED + "=?" +
-                            " WHERE " + DataUsageStatColumns._ID + "=?",
-                            mSelectionArgs2);
-                } else {
-                    mSelectionArgs4[0] = dataIdString;
-                    mSelectionArgs4[1] = typeString;
-                    mSelectionArgs4[2] = "1"; // times used
-                    mSelectionArgs4[3] = currentTimeMillisString;
-                    db.execSQL("INSERT INTO " + Tables.DATA_USAGE_STAT +
-                            "(" + DataUsageStatColumns.DATA_ID +
-                            "," + DataUsageStatColumns.USAGE_TYPE_INT +
-                            "," + DataUsageStatColumns.RAW_TIMES_USED +
-                            "," + DataUsageStatColumns.RAW_LAST_TIME_USED +
-                            ") VALUES (?,?,?,?)",
-                            mSelectionArgs4);
-                }
-            } finally {
-                cursor.close();
-            }
-        }
-
-        return dataIds.size();
-    }
-
-    /**
-     * Directly update {@link Tables#DATA_USAGE_STAT}; used for metadata sync.
-     * Update or insert usageType, lastTimeUsed, and timesUsed for specific dataId.
-     */
-    private void updateDataUsageStats(SQLiteDatabase db, ContentValues values) {
-        final String dataId = values.getAsString(DataUsageStatColumns.DATA_ID);
-        final String type = values.getAsString(DataUsageStatColumns.USAGE_TYPE_INT);
-        final String lastTimeUsed = values.getAsString(DataUsageStatColumns.RAW_LAST_TIME_USED);
-        final String timesUsed = values.getAsString(DataUsageStatColumns.RAW_TIMES_USED);
-
-        mSelectionArgs2[0] = dataId;
-        mSelectionArgs2[1] = type;
-        final Cursor cursor = db.query(DataUsageStatQuery.TABLE,
-                DataUsageStatQuery.COLUMNS, DataUsageStatQuery.SELECTION,
-                mSelectionArgs2, null, null, null);
-
-        try {
-            if (cursor.moveToFirst()) {
-                final long id = cursor.getLong(DataUsageStatQuery.ID);
-
-                mSelectionArgs3[0] = lastTimeUsed;
-                mSelectionArgs3[1] = timesUsed;
-                mSelectionArgs3[2] = String.valueOf(id);
-                db.execSQL("UPDATE " + Tables.DATA_USAGE_STAT +
-                        " SET " + DataUsageStatColumns.RAW_LAST_TIME_USED + "=?" +
-                        "," + DataUsageStatColumns.RAW_TIMES_USED + "=?" +
-                        " WHERE " + DataUsageStatColumns._ID + "=?",
-                        mSelectionArgs3);
-            } else {
-                mSelectionArgs4[0] = dataId;
-                mSelectionArgs4[1] = type;
-                mSelectionArgs4[2] = timesUsed;
-                mSelectionArgs4[3] = lastTimeUsed;
-                db.execSQL("INSERT INTO " + Tables.DATA_USAGE_STAT +
-                        "(" + DataUsageStatColumns.DATA_ID +
-                        "," + DataUsageStatColumns.USAGE_TYPE_INT +
-                        "," + DataUsageStatColumns.RAW_TIMES_USED +
-                        "," + DataUsageStatColumns.RAW_LAST_TIME_USED +
-                        ") VALUES (?,?,?,?)",
-                        mSelectionArgs4);
-            }
-        } finally {
-            cursor.close();
-        }
-    }
 
     /**
      * Returns a sort order String for promoting data rows (email addresses, phone numbers, etc.)
@@ -10175,6 +9847,13 @@
                         mFastScrollingIndexCacheRequestCount),
                 safeDiv(mTotalTimeFastScrollingIndexGenerate, mFastScrollingIndexCacheMissCount));
         pw.println();
+
+        pw.print("mUseStrictPhoneNumberComparison=");
+        if (mContactsHelper != null) {
+            pw.println(mContactsHelper.getUseStrictPhoneNumberComparisonParameter());
+        }
+        pw.println();
+
         pw.println();
 
         // DB queries may be blocked and timed out, so do it at the end.
diff --git a/src/com/android/providers/contacts/ContactsUpgradeReceiver.java b/src/com/android/providers/contacts/ContactsUpgradeReceiver.java
index 6f50a14..c8816ac 100644
--- a/src/com/android/providers/contacts/ContactsUpgradeReceiver.java
+++ b/src/com/android/providers/contacts/ContactsUpgradeReceiver.java
@@ -16,6 +16,7 @@
 
 package com.android.providers.contacts;
 
+import android.icu.util.VersionInfo;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -26,8 +27,6 @@
 import android.os.RemoteException;
 import android.util.Log;
 
-import libcore.icu.ICU;
-
 /**
  * This will be launched during system boot, after the core system has
  * been brought up but before any non-persistent processes have been
@@ -56,7 +55,7 @@
             final SharedPreferences prefs = context.getSharedPreferences(TAG, Context.MODE_PRIVATE);
             final int prefDbVersion = prefs.getInt(PREF_DB_VERSION, 0);
 
-            final String curIcuVersion = ICU.getIcuVersion();
+            final String curIcuVersion = VersionInfo.ICU_VERSION.toString();
             final String curOsVersion = getOsVersionString();
 
             final String prefIcuVersion = prefs.getString(PREF_ICU_VERSION, "");
diff --git a/src/com/android/providers/contacts/NameSplitter.java b/src/com/android/providers/contacts/NameSplitter.java
index 50b50fb..ddd294f 100644
--- a/src/com/android/providers/contacts/NameSplitter.java
+++ b/src/com/android/providers/contacts/NameSplitter.java
@@ -945,33 +945,6 @@
             bestGuess = guess;
         }
 
-        guess = guessFullNameStyle(name.middleName);
-        if (guess != FullNameStyle.UNDEFINED) {
-            if (guess != FullNameStyle.CJK && guess != FullNameStyle.WESTERN) {
-                name.fullNameStyle = guess;
-                return;
-            }
-            bestGuess = guess;
-        }
-
-        guess = guessFullNameStyle(name.prefix);
-        if (guess != FullNameStyle.UNDEFINED) {
-            if (guess != FullNameStyle.CJK && guess != FullNameStyle.WESTERN) {
-                name.fullNameStyle = guess;
-                return;
-            }
-            bestGuess = guess;
-        }
-
-        guess = guessFullNameStyle(name.suffix);
-        if (guess != FullNameStyle.UNDEFINED) {
-            if (guess != FullNameStyle.CJK && guess != FullNameStyle.WESTERN) {
-                name.fullNameStyle = guess;
-                return;
-            }
-            bestGuess = guess;
-        }
-
         name.fullNameStyle = bestGuess;
     }
 
diff --git a/src/com/android/providers/contacts/PhotoProcessor.java b/src/com/android/providers/contacts/PhotoProcessor.java
index b49e792..643d92d 100644
--- a/src/com/android/providers/contacts/PhotoProcessor.java
+++ b/src/com/android/providers/contacts/PhotoProcessor.java
@@ -22,7 +22,7 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.os.SystemProperties;
+import android.sysprop.ContactsProperties;
 
 import com.android.providers.contacts.util.MemoryUtils;
 import com.google.common.annotations.VisibleForTesting;
@@ -61,11 +61,10 @@
         final boolean isExpensiveDevice =
                 MemoryUtils.getTotalMemorySize() >= PhotoSizes.LARGE_RAM_THRESHOLD;
 
-        sMaxThumbnailDim = SystemProperties.getInt(
-                PhotoSizes.SYS_PROPERTY_THUMBNAIL_SIZE, PhotoSizes.DEFAULT_THUMBNAIL);
+        sMaxThumbnailDim = ContactsProperties.thumbnail_size().orElse(
+                PhotoSizes.DEFAULT_THUMBNAIL);
 
-        sMaxDisplayPhotoDim = SystemProperties.getInt(
-                PhotoSizes.SYS_PROPERTY_DISPLAY_PHOTO_SIZE,
+        sMaxDisplayPhotoDim = ContactsProperties.display_photo_size().orElse(
                 isExpensiveDevice
                         ? PhotoSizes.DEFAULT_DISPLAY_PHOTO_LARGE_MEMORY
                         : PhotoSizes.DEFAULT_DISPLAY_PHOTO_MEMORY_CONSTRAINED);
@@ -95,12 +94,6 @@
          * photos
          */
         public static final int LARGE_RAM_THRESHOLD = 640 * 1024 * 1024;
-
-        /** If present, overrides the size given in {@link #DEFAULT_THUMBNAIL} */
-        public static final String SYS_PROPERTY_THUMBNAIL_SIZE = "contacts.thumbnail_size";
-
-        /** If present, overrides the size determined for the display photo */
-        public static final String SYS_PROPERTY_DISPLAY_PHOTO_SIZE = "contacts.display_photo_size";
     }
 
     private final int mMaxDisplayPhotoDim;
diff --git a/test_common/Android.bp b/test_common/Android.bp
new file mode 100644
index 0000000..b30e2e3
--- /dev/null
+++ b/test_common/Android.bp
@@ -0,0 +1,23 @@
+// Copyright (C) 2016 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.
+
+java_library {
+    name: "ContactsProviderTestUtils",
+    srcs: ["src/**/*.java"],
+    libs: [
+        "android.test.runner",
+        "androidx.test.rules",
+        "mockito-target-minus-junit4",
+    ],
+}
diff --git a/test_common/Android.mk b/test_common/Android.mk
deleted file mode 100644
index 2965f8a..0000000
--- a/test_common/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := \
-    android.test.runner \
-    android-support-test \
-    mockito-target-minus-junit4
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := ContactsProviderTestUtils
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/Android.bp b/tests/Android.bp
new file mode 100644
index 0000000..b15ded4
--- /dev/null
+++ b/tests/Android.bp
@@ -0,0 +1,23 @@
+android_test {
+    name: "ContactsProviderTests",
+    static_libs: [
+        "ContactsProviderTestUtils",
+        "androidx.test.rules",
+        "mockito-target-minus-junit4",
+    ],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+        "android.test.mock",
+    ],
+
+    // Only compile source java files in this apk.
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    test_suites: ["device-tests"],
+    instrumentation_for: "ContactsProvider",
+    certificate: "shared",
+    optimize: {
+        enabled: false,
+    },
+}
diff --git a/tests/Android.mk b/tests/Android.mk
deleted file mode 100644
index 02ea81e..0000000
--- a/tests/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    ContactsProviderTestUtils \
-    android-support-test \
-    mockito-target-minus-junit4
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := ContactsProviderTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_INSTRUMENTATION_FOR := ContactsProvider
-LOCAL_CERTIFICATE := shared
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 15a90fa..4d81c5f 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -36,14 +36,8 @@
         </service>
     </application>
 
-    <!--
-    The test declared in this instrumentation will be run along with tests declared by
-    all other applications via the command: "adb shell itr".
-    The "itr" command will find all tests declared by all applications. If you want to run just these
-    tests on their own then use the command:
-    "adb shell am instrument -w com.android.providers.contacts.tests/android.test.InstrumentationTestRunner"
-    -->
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.providers.contacts"
         android:label="Contacts Provider Tests">
     </instrumentation>
diff --git a/tests/AndroidTest.xml b/tests/AndroidTest.xml
index 3c4a3ab..cdf0c7d 100644
--- a/tests/AndroidTest.xml
+++ b/tests/AndroidTest.xml
@@ -20,9 +20,8 @@
 
     <option name="test-suite-tag" value="apct" />
     <option name="test-tag" value="ContactsProviderTests" />
-    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.providers.contacts.tests" />
-        <option name="runner" value="android.test.InstrumentationTestRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
 </configuration>
diff --git a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
index 74642cb..91a76a3 100644
--- a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
@@ -1234,14 +1234,13 @@
     private static final String[] DATA_USAGE_PROJECTION =
             new String[] {Data.DATA1, Data.TIMES_USED, Data.LAST_TIME_USED};
 
-    protected void assertDataUsageCursorContains(Uri uri, String data1, int timesUsed,
-            int lastTimeUsed) {
+    protected void assertDataUsageZero(Uri uri, String data1) {
         final Cursor cursor = mResolver.query(uri, DATA_USAGE_PROJECTION, null, null,
                 null);
         try {
             dumpCursor(cursor);
-            assertCursorHasAnyRecordMatch(cursor, cv(Data.DATA1, data1, Data.TIMES_USED, timesUsed,
-                    Data.LAST_TIME_USED, lastTimeUsed));
+            assertCursorHasAnyRecordMatch(cursor, cv(Data.DATA1, data1, Data.TIMES_USED, 0,
+                    Data.LAST_TIME_USED, 0));
         } finally {
             cursor.close();
         }
diff --git a/tests/src/com/android/providers/contacts/BaseDatabaseHelperUpgradeTest.java b/tests/src/com/android/providers/contacts/BaseDatabaseHelperUpgradeTest.java
index 0eb12ad..ae12f1b 100644
--- a/tests/src/com/android/providers/contacts/BaseDatabaseHelperUpgradeTest.java
+++ b/tests/src/com/android/providers/contacts/BaseDatabaseHelperUpgradeTest.java
@@ -17,7 +17,6 @@
 
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
-import android.test.AndroidTestCase;
 
 import junit.framework.AssertionFailedError;
 
@@ -29,7 +28,7 @@
  * Run the test like this: <code> runtest -c com.android.providers.contacts.BaseDatabaseHelperUpgradeTest
  * contactsprov </code>
  */
-public abstract class BaseDatabaseHelperUpgradeTest extends AndroidTestCase {
+public abstract class BaseDatabaseHelperUpgradeTest extends FixedAndroidTestCase {
 
     protected static final String INTEGER = "INTEGER";
     protected static final String TEXT = "TEXT";
diff --git a/tests/src/com/android/providers/contacts/CallLogInsertionHelperTest.java b/tests/src/com/android/providers/contacts/CallLogInsertionHelperTest.java
index 7bb88a8..6122ff0 100644
--- a/tests/src/com/android/providers/contacts/CallLogInsertionHelperTest.java
+++ b/tests/src/com/android/providers/contacts/CallLogInsertionHelperTest.java
@@ -19,12 +19,10 @@
 import android.content.ContentValues;
 import android.provider.CallLog.Calls;
 
-import android.test.AndroidTestCase;
-
 /**
  * Test cases for {@link com.android.providers.contacts.DefaultCallLogInsertionHelper}.
  */
-public class CallLogInsertionHelperTest extends AndroidTestCase {
+public class CallLogInsertionHelperTest extends FixedAndroidTestCase {
 
     /**
      * The default insertion helper under test.
diff --git a/tests/src/com/android/providers/contacts/CallLogMigrationTest.java b/tests/src/com/android/providers/contacts/CallLogMigrationTest.java
index 3cbecb8..767b62f 100644
--- a/tests/src/com/android/providers/contacts/CallLogMigrationTest.java
+++ b/tests/src/com/android/providers/contacts/CallLogMigrationTest.java
@@ -18,7 +18,6 @@
 import android.content.Context;
 import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteDatabase;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 
 import java.io.File;
@@ -28,7 +27,7 @@
 import java.io.OutputStream;
 
 @LargeTest
-public class CallLogMigrationTest extends AndroidTestCase {
+public class CallLogMigrationTest extends FixedAndroidTestCase {
 
     private void writeAssetFileToDisk(String assetName, File diskPath) throws IOException {
         final Context context = getTestContext();
diff --git a/tests/src/com/android/providers/contacts/CallLogProviderTest.java b/tests/src/com/android/providers/contacts/CallLogProviderTest.java
index f607846..babfaff 100644
--- a/tests/src/com/android/providers/contacts/CallLogProviderTest.java
+++ b/tests/src/com/android/providers/contacts/CallLogProviderTest.java
@@ -61,7 +61,7 @@
             Voicemails.DIRTY,
             Voicemails.DELETED};
     /** Total number of columns exposed by call_log provider. */
-    private static final int NUM_CALLLOG_FIELDS = 31;
+    private static final int NUM_CALLLOG_FIELDS = 34;
 
     private CallLogProviderTestable mCallLogProvider;
 
diff --git a/tests/src/com/android/providers/contacts/ContactLocaleUtilsTest.java b/tests/src/com/android/providers/contacts/ContactLocaleUtilsTest.java
index 8e71bef..a19a2f2 100644
--- a/tests/src/com/android/providers/contacts/ContactLocaleUtilsTest.java
+++ b/tests/src/com/android/providers/contacts/ContactLocaleUtilsTest.java
@@ -17,11 +17,8 @@
 package com.android.providers.contacts;
 
 import android.provider.ContactsContract.FullNameStyle;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
 
-import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -30,7 +27,7 @@
 import java.util.Locale;
 
 @SmallTest
-public class ContactLocaleUtilsTest extends AndroidTestCase {
+public class ContactLocaleUtilsTest extends FixedAndroidTestCase {
     private static final String TAG = "ContactLocaleUtilsTest";
 
     private static final String PHONE_NUMBER_1 = "+1 (650) 555-1212";
diff --git a/tests/src/com/android/providers/contacts/ContactsDatabaseHelperTest.java b/tests/src/com/android/providers/contacts/ContactsDatabaseHelperTest.java
index 8cf9ea4..a9867c5 100644
--- a/tests/src/com/android/providers/contacts/ContactsDatabaseHelperTest.java
+++ b/tests/src/com/android/providers/contacts/ContactsDatabaseHelperTest.java
@@ -29,12 +29,11 @@
 import android.test.MoreAsserts;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
 
-import com.android.providers.contacts.ContactsDatabaseHelper.LowRes;
 import com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns;
 import com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns;
 import com.android.providers.contacts.ContactsDatabaseHelper.Tables;
+
 import com.google.android.collect.Sets;
 
 import java.util.HashSet;
@@ -455,48 +454,6 @@
         }
     }
 
-    private Integer checkGetTimesUsedExpression(Integer value) {
-        return getIntegerFromExpression(LowRes.getTimesUsedExpression(
-                value == null ? "NULL" : String.valueOf(value)));
-    }
-
-    public void testGetTimesUsedExpression() {
-        assertEquals((Object) 0, checkGetTimesUsedExpression(null));
-        assertEquals((Object) 0, checkGetTimesUsedExpression(-1));
-        assertEquals((Object) 0, checkGetTimesUsedExpression(-10));
-        assertEquals((Object) 0, checkGetTimesUsedExpression(0));
-        for (int i = 1; i < 10; i++) {
-            assertEquals("value=" + i, (Object) i, checkGetTimesUsedExpression(i));
-        }
-        for (int i = 10; i < 20; i++) {
-            assertEquals("value=" + i, (Object) 10, checkGetTimesUsedExpression(i));
-        }
-        for (int i = 20; i < 30; i++) {
-            assertEquals("value=" + i, (Object) 20, checkGetTimesUsedExpression(i));
-        }
-
-        assertEquals((Object) 123450, checkGetTimesUsedExpression(123456));
-    }
-
-    private Integer checkGetLastTimeUsedExpression(Integer value) {
-        return getIntegerFromExpression(LowRes.getLastTimeUsedExpression(
-                value == null ? "NULL" : String.valueOf(value)));
-    }
-
-    public void testGetLastTimeUsedExpression() {
-        assertEquals((Object) null, checkGetLastTimeUsedExpression(null));
-        assertEquals((Object) 0, checkGetLastTimeUsedExpression(0));
-        assertEquals((Object) 0, checkGetLastTimeUsedExpression(1));
-        assertEquals((Object) 0, checkGetLastTimeUsedExpression(86399));
-        assertEquals((Object) 86400, checkGetLastTimeUsedExpression(86400));
-
-        for (int i = 1; i < 3; i++) {
-            assertEquals((Object) (86400 * i), checkGetLastTimeUsedExpression(86400 * i));
-            assertEquals((Object) (86400 * i), checkGetLastTimeUsedExpression(86400 * i + 1));
-            assertEquals((Object) (86400 * i), checkGetLastTimeUsedExpression(86400 * i + 86399));
-        }
-    }
-
     public void testNotifyProviderStatusChange() throws Exception {
         final AtomicReference<Uri> calledUri = new AtomicReference<>();
 
diff --git a/tests/src/com/android/providers/contacts/ContactsIcuTest.java b/tests/src/com/android/providers/contacts/ContactsIcuTest.java
index 16583ae..7d3bdcf 100644
--- a/tests/src/com/android/providers/contacts/ContactsIcuTest.java
+++ b/tests/src/com/android/providers/contacts/ContactsIcuTest.java
@@ -17,14 +17,13 @@
 
 import android.icu.text.AlphabeticIndex;
 import android.icu.text.AlphabeticIndex.ImmutableIndex;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
 import java.util.Arrays;
 import java.util.Locale;
 
-public class ContactsIcuTest extends AndroidTestCase {
+public class ContactsIcuTest extends FixedAndroidTestCase {
     private static final String TAG = "ContactsIcuTest";
 
     private static ImmutableIndex buildIndex(String... localeTags) {
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
index 6c76709..88e32e6 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
@@ -985,11 +985,10 @@
         Uri rowUri = mResolver.insert(RawContacts.CONTENT_URI, values);
         long rawContactId = ContentUris.parseId(rowUri);
 
-        values.put(RawContacts.LAST_TIME_CONTACTED, 86400);
-        values.put(RawContacts.TIMES_CONTACTED, 10);
+        values.put(RawContacts.LAST_TIME_CONTACTED, 0);
+        values.put(RawContacts.TIMES_CONTACTED, 0);
 
         assertStoredValues(rowUri, values);
-        assertSelection(RawContacts.CONTENT_URI, values, RawContacts._ID, rawContactId);
         assertNetworkNotified(true);
     }
 
@@ -1334,12 +1333,11 @@
         values.put(Contacts.DISPLAY_NAME, "Meghan Knox");
         values.put(Contacts.CUSTOM_RINGTONE, "d");
         values.put(Contacts.SEND_TO_VOICEMAIL, 1);
-        values.put(Contacts.LAST_TIME_CONTACTED, 86400);
-        values.put(Contacts.TIMES_CONTACTED, 54320);
+        values.put(Contacts.LAST_TIME_CONTACTED, 0);
+        values.put(Contacts.TIMES_CONTACTED, 0);
         values.put(Contacts.STARRED, 1);
 
         assertStoredValues(ContentUris.withAppendedId(Phone.CONTENT_URI, phoneId), values);
-        assertSelection(Phone.CONTENT_URI, values, Data._ID, phoneId);
     }
 
     public void testPhonesWithMergedContacts() {
@@ -2519,13 +2517,12 @@
         values.put(Contacts.DISPLAY_NAME, "Meghan Knox");
         values.put(Contacts.CUSTOM_RINGTONE, "d");
         values.put(Contacts.SEND_TO_VOICEMAIL, 1);
-        values.put(Contacts.LAST_TIME_CONTACTED, 86400);
-        values.put(Contacts.TIMES_CONTACTED, 54320);
+        values.put(Contacts.LAST_TIME_CONTACTED, 0);
+        values.put(Contacts.TIMES_CONTACTED, 0);
         values.put(Contacts.STARRED, 1);
 
         assertStoredValues(Email.CONTENT_URI, values);
         assertStoredValues(ContentUris.withAppendedId(Email.CONTENT_URI, emailId), values);
-        assertSelection(Email.CONTENT_URI, values, Data._ID, emailId);
 
         // Check if the provider detects duplicated email addresses.
         final Uri emailUri2 = insertEmail(rawContactId, "meghan@acme.com");
@@ -2718,12 +2715,6 @@
         assertStoredValuesOrderly(filterUri, v3, v1, v2);
     }
 
-    /**
-     * Test primary emails are sorted below emails used last.
-     *
-     * primary may be set without super primary.  Only super primary indicates "default" in the
-     * contact ui.
-     */
     public void testEmailFilterUsageOverPrimarySort() {
         final long rawContactId = RawContactUtil.createRawContact(mResolver, TestUtil.ACCOUNT_1);
         final Uri emailUri1 = insertEmail(rawContactId, "account1@testemail.com");
@@ -2739,9 +2730,9 @@
         final ContentValues v2 = cv(Email.ADDRESS, "account2@testemail.com");
         final ContentValues v3 = cv(Email.ADDRESS, "account3@testemail.com");
 
-        // Test that account 3 is first even though account 1 and 2 have higher usage.
+        // No usage stats any more, so v3 is still the first.
         Uri filterUri = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "acc");
-        assertStoredValuesOrderly(filterUri, v1, v2, v3);
+        assertStoredValuesOrderly(filterUri, v3, v1, v2);
     }
 
     /** Tests {@link DataUsageFeedback} correctly promotes a data row instead of a raw contact. */
@@ -2788,13 +2779,13 @@
                         RawContacts.TIMES_CONTACTED, 0
                         ),
                 cv(RawContacts._ID, rawContactId2,
-                        RawContacts.TIMES_CONTACTED, 1
+                        RawContacts.TIMES_CONTACTED, 0
                         )
                 );
 
-        // account3@email.com should be the first.
-        assertStoredValuesOrderly(filterUri1, new ContentValues[] { v3, v1, v2 });
-        assertStoredValuesOrderly(filterUri3, new ContentValues[] { v3, v1, v2 });
+        // No more interaction counter, so the order doesn't change.
+        assertStoredValuesOrderly(filterUri1, new ContentValues[] { v1, v2, v3 });
+        assertStoredValuesOrderly(filterUri3, new ContentValues[] { v1, v2, v3 });
     }
 
     public void testAddQueryParametersFromUri() {
@@ -2873,71 +2864,6 @@
         }
     }
 
-    /**
-     * Tests {@link DataUsageFeedback} correctly bucketize contacts using each
-     * {@link DataUsageStatColumns#RAW_LAST_TIME_USED}
-     */
-    public void testEmailFilterSortOrderWithOldHistory() {
-        long rawContactId1 = RawContactUtil.createRawContact(mResolver);
-        long dataId1 = ContentUris.parseId(insertEmail(rawContactId1, "address1@email.com"));
-        long dataId2 = ContentUris.parseId(insertEmail(rawContactId1, "address2@email.com"));
-        long dataId3 = ContentUris.parseId(insertEmail(rawContactId1, "address3@email.com"));
-        long dataId4 = ContentUris.parseId(insertEmail(rawContactId1, "address4@email.com"));
-
-        Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "address");
-
-        ContentValues v1 = new ContentValues();
-        v1.put(Email.ADDRESS, "address1@email.com");
-        ContentValues v2 = new ContentValues();
-        v2.put(Email.ADDRESS, "address2@email.com");
-        ContentValues v3 = new ContentValues();
-        v3.put(Email.ADDRESS, "address3@email.com");
-        ContentValues v4 = new ContentValues();
-        v4.put(Email.ADDRESS, "address4@email.com");
-
-        final ContactsProvider2 provider = (ContactsProvider2) getProvider();
-
-        long nowInMillis = System.currentTimeMillis();
-        long yesterdayInMillis = (nowInMillis - 24 * 60 * 60 * 1000);
-        long sevenDaysAgoInMillis = (nowInMillis - 7 * 24 * 60 * 60 * 1000);
-        long oneYearAgoInMillis = (nowInMillis - 365L * 24 * 60 * 60 * 1000);
-
-        // address4 is contacted just once yesterday.
-        provider.updateDataUsageStat(Arrays.asList(dataId4),
-                DataUsageFeedback.USAGE_TYPE_LONG_TEXT, yesterdayInMillis);
-
-        // address3 is contacted twice 1 week ago.
-        provider.updateDataUsageStat(Arrays.asList(dataId3),
-                DataUsageFeedback.USAGE_TYPE_LONG_TEXT, sevenDaysAgoInMillis);
-        provider.updateDataUsageStat(Arrays.asList(dataId3),
-                DataUsageFeedback.USAGE_TYPE_LONG_TEXT, sevenDaysAgoInMillis);
-
-        // address2 is contacted three times 1 year ago.
-        provider.updateDataUsageStat(Arrays.asList(dataId2),
-                DataUsageFeedback.USAGE_TYPE_LONG_TEXT, oneYearAgoInMillis);
-        provider.updateDataUsageStat(Arrays.asList(dataId2),
-                DataUsageFeedback.USAGE_TYPE_LONG_TEXT, oneYearAgoInMillis);
-        provider.updateDataUsageStat(Arrays.asList(dataId2),
-                DataUsageFeedback.USAGE_TYPE_LONG_TEXT, oneYearAgoInMillis);
-
-        // auto-complete should prefer recently contacted methods
-        assertStoredValuesOrderly(filterUri1, new ContentValues[] { v4, v3, v2, v1 });
-
-        // Pretend address2 is contacted right now
-        provider.updateDataUsageStat(Arrays.asList(dataId2),
-                DataUsageFeedback.USAGE_TYPE_LONG_TEXT, nowInMillis);
-
-        // Now address2 is the most recently used address
-        assertStoredValuesOrderly(filterUri1, new ContentValues[] { v2, v4, v3, v1 });
-
-        // Pretend address1 is contacted right now
-        provider.updateDataUsageStat(Arrays.asList(dataId1),
-                DataUsageFeedback.USAGE_TYPE_LONG_TEXT, nowInMillis);
-
-        // address2 is preferred to address1 as address2 is used 4 times in total
-        assertStoredValuesOrderly(filterUri1, new ContentValues[] { v2, v1, v4, v3 });
-    }
-
     public void testUpdateFromMetadataEntry() {
         String accountType1 = "accountType1";
         String accountName1 = "accountName1";
@@ -3030,8 +2956,7 @@
         assertStoredValue(dataUri2, Data.IS_SUPER_PRIMARY, 0);
         final Uri dataUriWithUsageType = Data.CONTENT_URI.buildUpon().appendQueryParameter(
                 DataUsageFeedback.USAGE_TYPE, usageTypeString).build();
-        assertDataUsageCursorContains(dataUriWithUsageType, emailAddress, 5,
-                1111111 / 86400 * 86400);
+        assertDataUsageZero(dataUriWithUsageType, emailAddress);
 
         // Update AggregationException table.
         RawContactInfo aggregationContact = new RawContactInfo(
@@ -3496,9 +3421,8 @@
                 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO);
         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
 
-        values.put(Contacts.TIMES_CONTACTED, 4);
+        values.put(Contacts.TIMES_CONTACTED, 0);
         assertStoredValues(contactUri, values);
-        assertSelection(Contacts.CONTENT_URI, values, Contacts._ID, contactId);
     }
 
     public void testQueryContactWithStatusUpdate() {
@@ -3510,10 +3434,9 @@
         values.put(Contacts.CONTACT_CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA);
         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
 
-        values.put(Contacts.TIMES_CONTACTED, 4);
+        values.put(Contacts.TIMES_CONTACTED, 0);
 
         assertStoredValuesWithProjection(contactUri, values);
-        assertSelectionWithProjection(Contacts.CONTENT_URI, values, Contacts._ID, contactId);
     }
 
     public void testQueryContactFilterByName() {
@@ -3534,7 +3457,7 @@
         values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE);
 
         Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goulash");
-        values.put(Contacts.TIMES_CONTACTED, 4);
+        values.put(Contacts.TIMES_CONTACTED, 0);
         assertStoredValuesWithProjection(filterUri1, values);
 
         assertContactFilter(contactId, "goolash");
@@ -3569,7 +3492,7 @@
         values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE);
 
         Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goog411@acme.com");
-        values.put(Contacts.TIMES_CONTACTED, 4);
+        values.put(Contacts.TIMES_CONTACTED, 0);
         assertStoredValuesWithProjection(filterUri1, values);
 
         assertContactFilter(contactId, "goog");
@@ -3596,7 +3519,7 @@
         values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE);
 
         Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "18004664411");
-        values.put(Contacts.TIMES_CONTACTED, 4);
+        values.put(Contacts.TIMES_CONTACTED, 0);
         assertStoredValuesWithProjection(filterUri1, values);
 
         assertContactFilter(contactId, "18004664411");
@@ -3611,7 +3534,7 @@
 
     /**
      * Checks ContactsProvider2 works well with strequent Uris. The provider should return starred
-     * contacts and frequently used contacts.
+     * contacts.
      */
     public void testQueryContactStrequent() {
         ContentValues values1 = new ContentValues();
@@ -3644,20 +3567,20 @@
         // Send feedback for the 3rd phone number, pretending we called that person via phone.
         sendFeedback(phoneNumber3, DataUsageFeedback.USAGE_TYPE_CALL, values3);
 
-        values3.put(Contacts.TIMES_CONTACTED, 10); // Low res.
+        values3.put(Contacts.TIMES_CONTACTED, 0);
 
         // After the feedback, 3rd contact should be shown after starred one.
         assertStoredValuesOrderly(Contacts.CONTENT_STREQUENT_URI,
-                new ContentValues[] { values4, values3 });
+                new ContentValues[] { values4 });
 
         sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values1);
         // Twice.
         sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values1);
 
         // After the feedback, 1st and 3rd contacts should be shown after starred one.
-        values1.put(Contacts.TIMES_CONTACTED, 2);
+        values1.put(Contacts.TIMES_CONTACTED, 0);
         assertStoredValuesOrderly(Contacts.CONTENT_STREQUENT_URI,
-                new ContentValues[] { values4, values1, values3 });
+                new ContentValues[] { values4 });
 
         // With phone-only parameter, 1st and 4th contacts shouldn't be returned because:
         // 1st: feedbacks are only about email, not about phone call.
@@ -3665,48 +3588,7 @@
         Uri phoneOnlyStrequentUri = Contacts.CONTENT_STREQUENT_URI.buildUpon()
                 .appendQueryParameter(ContactsContract.STREQUENT_PHONE_ONLY, "true")
                 .build();
-        assertStoredValuesOrderly(phoneOnlyStrequentUri, new ContentValues[] { values3 });
-
-        // Now the 4th contact has three phone numbers, one of which is called twice and
-        // the other once
-        final String phoneNumber4 = "18004664414";
-        final String phoneNumber5 = "18004664415";
-        final String phoneNumber6 = "18004664416";
-        insertPhoneNumber(rawContactId4, phoneNumber4);
-        insertPhoneNumber(rawContactId4, phoneNumber5);
-        insertPhoneNumber(rawContactId4, phoneNumber6);
-        values3.put(Phone.NUMBER, phoneNumber3);
-        values4.put(Phone.NUMBER, phoneNumber4);
-
-        sendFeedback(phoneNumber5, DataUsageFeedback.USAGE_TYPE_CALL, values4);
-        sendFeedback(phoneNumber5, DataUsageFeedback.USAGE_TYPE_CALL, values4);
-        sendFeedback(phoneNumber6, DataUsageFeedback.USAGE_TYPE_CALL, values4);
-
-        // Create a ContentValues object representing the second phone number of contact 4
-        final ContentValues values5 = new ContentValues(values4);
-        values5.put(Phone.NUMBER, phoneNumber5);
-
-        // Create a ContentValues object representing the third phone number of contact 4
-        final ContentValues values6 = new ContentValues(values4);
-        values6.put(Phone.NUMBER, phoneNumber6);
-
-        // Phone only strequent should return all phone numbers belonging to the 4th contact,
-        // and then contact 3.
-        assertStoredValuesOrderly(phoneOnlyStrequentUri, new ContentValues[] {values5, values6,
-                values4, values3});
-
-        // Send feedback for the 2rd phone number, pretending we send the person a SMS message.
-        sendFeedback(phoneNumber2, DataUsageFeedback.USAGE_TYPE_SHORT_TEXT, values1);
-
-        values1.put(Contacts.TIMES_CONTACTED, 1); // Low res.
-
-        // SMS feedback shouldn't affect phone-only results.
-        assertStoredValuesOrderly(phoneOnlyStrequentUri, new ContentValues[] {values5, values6,
-                values4, values3});
-
-        values4.remove(Phone.NUMBER);
-        Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_STREQUENT_FILTER_URI, "fay");
-        assertStoredValues(filterUri, values4);
+        assertStoredValuesOrderly(phoneOnlyStrequentUri, new ContentValues[] { });
     }
 
     public void testQueryContactStrequentFrequentOrder() {
@@ -3804,27 +3686,14 @@
         // before cid5 and cid6, which were contacted at the same time.
         // cid2 will not show up because it was contacted more than 30 days ago
 
-        assertStoredValuesOrderly(Contacts.CONTENT_STREQUENT_URI,
-                cv(Contacts._ID, cid8),
-                cv(Contacts._ID, cid7),
-                cv(Contacts._ID, cid1),
-                cv(Contacts._ID, cid5),
-                cv(Contacts._ID, cid6),
-                cv(Contacts._ID, cid3),
-                cv(Contacts._ID, cid4));
+        assertStoredValuesOrderly(Contacts.CONTENT_STREQUENT_URI);
 
         // Check the order -- phone only frequent, which is data based.
         // Note this is based on data, and only looks at phone numbers, so the order is different
         // now.
         // did1, did2 will not show up because they were used to make calls more than 30 days ago.
         assertStoredValuesOrderly(Contacts.CONTENT_STREQUENT_URI.buildUpon()
-                    .appendQueryParameter(ContactsContract.STREQUENT_PHONE_ONLY, "1").build(),
-                cv(Data._ID, did8),
-                cv(Data._ID, did7),
-                cv(Data._ID, did5),
-                cv(Data._ID, did6),
-                cv(Data._ID, did3),
-                cv(Data._ID, did4));
+                    .appendQueryParameter(ContactsContract.STREQUENT_PHONE_ONLY, "1").build());
     }
 
     /**
@@ -3850,32 +3719,32 @@
 
         sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values1);
 
-        assertStoredValues(Contacts.CONTENT_FREQUENT_URI, values1);
+        assertStoredValues(Contacts.CONTENT_FREQUENT_URI);
 
         // Pretend email was sent to the address twice.
         sendFeedback(email2, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values2);
         sendFeedback(email2, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values2);
 
-        values1.put(Contacts.TIMES_CONTACTED, 1);
-        values2.put(Contacts.TIMES_CONTACTED, 2);
-        assertStoredValues(Contacts.CONTENT_FREQUENT_URI, new ContentValues[] {values2, values1});
+        values1.put(Contacts.TIMES_CONTACTED, 0);
+        values2.put(Contacts.TIMES_CONTACTED, 0);
+        assertStoredValues(Contacts.CONTENT_FREQUENT_URI);
 
         for (int i = 0; i < 10; i++) {
             sendFeedback(phoneNumber3, DataUsageFeedback.USAGE_TYPE_CALL, values3);
         }
 
-        values3.put(Contacts.TIMES_CONTACTED, 10); // low res.
+        values3.put(Contacts.TIMES_CONTACTED, 0);
 
-        assertStoredValues(Contacts.CONTENT_FREQUENT_URI,
-                new ContentValues[] {values3, values2, values1});
+        assertStoredValues(Contacts.CONTENT_FREQUENT_URI);
+
 
         // Test it works with selection/selectionArgs
         assertStoredValues(Contacts.CONTENT_FREQUENT_URI,
-                Contacts.STARRED + "=?", new String[] {"0"},
-                new ContentValues[] {values2, values1});
+                Contacts.STARRED + "=?", new String[] {"0"}
+                );
         assertStoredValues(Contacts.CONTENT_FREQUENT_URI,
-                Contacts.STARRED + "=?", new String[] {"1"},
-                new ContentValues[] {values3});
+                Contacts.STARRED + "=?", new String[] {"1"}
+                );
 
         values3.put(Contacts.STARRED, 0);
         assertEquals(1,
@@ -3883,11 +3752,11 @@
                         String.valueOf(contactId3)),
                 values3, null, null));
         assertStoredValues(Contacts.CONTENT_FREQUENT_URI,
-                Contacts.STARRED + "=?", new String[] {"0"},
-                new ContentValues[] {values3, values2, values1});
+                Contacts.STARRED + "=?", new String[] {"0"}
+                );
         assertStoredValues(Contacts.CONTENT_FREQUENT_URI,
-                Contacts.STARRED + "=?", new String[] {"1"},
-                new ContentValues[] {});
+                Contacts.STARRED + "=?", new String[] {"1"}
+                );
     }
 
     public void testQueryContactFrequentExcludingInvisible() {
@@ -3904,17 +3773,19 @@
         sendFeedback(email2, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values2);
 
         // First, we have two contacts in frequent.
-        assertStoredValues(Contacts.CONTENT_FREQUENT_URI, new ContentValues[] {values2, values1});
+        assertStoredValues(Contacts.CONTENT_FREQUENT_URI);
 
         // Contact 2 goes invisible.
         markInvisible(cid2);
 
         // Now we have only 1 frequent.
-        assertStoredValues(Contacts.CONTENT_FREQUENT_URI, new ContentValues[] {values1});
+        assertStoredValues(Contacts.CONTENT_FREQUENT_URI);
 
     }
 
     public void testQueryDataUsageStat() {
+        // Now all data usage stats are zero as of Q.
+
         ContentValues values1 = new ContentValues();
         final String email1 = "a@acme.com";
         final long cid1 = createContact(values1, "Noah", "Tever", "18004664411",
@@ -3925,51 +3796,48 @@
 
         sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values1);
 
-        assertDataUsageCursorContains(Data.CONTENT_URI, "a@acme.com", 1, 0);
+        assertDataUsageZero(Data.CONTENT_URI, "a@acme.com");
 
         sMockClock.setCurrentTimeMillis(86400 + 123);
         sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_LONG_TEXT, values1);
 
-        assertDataUsageCursorContains(Data.CONTENT_URI, "a@acme.com", 2, 86400);
+        assertDataUsageZero(Data.CONTENT_URI, "a@acme.com");
 
         sMockClock.setCurrentTimeMillis(86400 * 3 + 123);
         for (int i = 0; i < 11; i++) {
             sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_SHORT_TEXT, values1);
         }
 
-        // Note here, "a@acme.com" has two data stats rows, 2 and 11.  What we get here's the sum
-        // of the lowres values, so # times will be 12, instead of 10 (which is the lowres of the
-        // sum).
-        assertDataUsageCursorContains(Data.CONTENT_URI, "a@acme.com", 12, 86400 * 3);
+        assertDataUsageZero(Data.CONTENT_URI, "a@acme.com");
 
         final Uri dataUriWithUsageTypeLongText = Data.CONTENT_URI.buildUpon().appendQueryParameter(
                 DataUsageFeedback.USAGE_TYPE, DataUsageFeedback.USAGE_TYPE_LONG_TEXT).build();
 
-        assertDataUsageCursorContains(dataUriWithUsageTypeLongText, "a@acme.com", 2, 86400 * 1);
+        assertDataUsageZero(dataUriWithUsageTypeLongText, "a@acme.com");
 
         sMockClock.setCurrentTimeMillis(86400 * 4 + 123);
         sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_CALL, values1);
         sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_CALL, values1);
         sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_CALL, values1);
 
-        assertDataUsageCursorContains(Data.CONTENT_URI, "a@acme.com", 15, 86400 * 4);
+        assertDataUsageZero(Data.CONTENT_URI, "a@acme.com");
 
         sMockClock.setCurrentTimeMillis(86400 * 5 + 123);
         for (int i = 0; i < 10; i++) {
             sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_CALL, values1);
         }
-        assertDataUsageCursorContains(Data.CONTENT_URI, "a@acme.com", 22, 86400 * 5);
+        assertDataUsageZero(Data.CONTENT_URI, "a@acme.com");
 
         sMockClock.setCurrentTimeMillis(86400 * 6 + 123);
         for (int i = 0; i < 10; i++) {
             sendFeedback(email1, DataUsageFeedback.USAGE_TYPE_CALL, values1);
         }
-        assertDataUsageCursorContains(Data.CONTENT_URI, "a@acme.com", 32, 86400 * 6);
+        assertDataUsageZero(Data.CONTENT_URI, "a@acme.com");
 
         final Uri dataUriWithUsageTypeCall = Data.CONTENT_URI.buildUpon().appendQueryParameter(
                 DataUsageFeedback.USAGE_TYPE, DataUsageFeedback.USAGE_TYPE_CALL).build();
 
-        assertDataUsageCursorContains(dataUriWithUsageTypeCall, "a@acme.com", 20, 86400 * 6);
+        assertDataUsageZero(dataUriWithUsageTypeCall, "a@acme.com");
     }
 
     public void testQueryContactGroup() {
@@ -4171,11 +4039,10 @@
         long nonProfileRawContactId = createBasicNonProfileContact(nonProfileValues);
         long nonProfileContactId = queryContactId(nonProfileRawContactId);
 
-        nonProfileValues.put(Contacts.TIMES_CONTACTED, 4);
-        profileValues.put(Contacts.TIMES_CONTACTED, 4);
+        nonProfileValues.put(Contacts.TIMES_CONTACTED, 0);
+        profileValues.put(Contacts.TIMES_CONTACTED, 0);
 
         assertStoredValues(Contacts.CONTENT_URI, nonProfileValues);
-        assertSelection(Contacts.CONTENT_URI, nonProfileValues, Contacts._ID, nonProfileContactId);
 
         assertStoredValues(Profile.CONTENT_URI, profileValues);
     }
@@ -4187,7 +4054,7 @@
         // Create a non-profile contact - this should be returned.
         ContentValues nonProfileValues = new ContentValues();
         createBasicNonProfileContact(nonProfileValues);
-        nonProfileValues.put(Contacts.TIMES_CONTACTED, 4);
+        nonProfileValues.put(Contacts.TIMES_CONTACTED, 0);
         assertStoredValues(Contacts.CONTENT_URI, new ContentValues[] {nonProfileValues});
     }
 
@@ -4195,7 +4062,7 @@
         ContentValues profileValues = new ContentValues();
         createBasicProfileContact(profileValues);
 
-        profileValues.put(Contacts.TIMES_CONTACTED, 4);
+        profileValues.put(Contacts.TIMES_CONTACTED, 0);
         assertStoredValues(Profile.CONTENT_URI, profileValues);
     }
 
@@ -4244,7 +4111,7 @@
 
         // The raw contact view doesn't include the photo ID.
         profileValues.remove(Contacts.PHOTO_ID);
-        profileValues.put(Contacts.TIMES_CONTACTED, 4);
+        profileValues.put(Contacts.TIMES_CONTACTED, 0);
         assertStoredValues(Profile.CONTENT_RAW_CONTACTS_URI, profileValues);
     }
 
@@ -4254,7 +4121,7 @@
 
         // The raw contact view doesn't include the photo ID.
         profileValues.remove(Contacts.PHOTO_ID);
-        profileValues.put(Contacts.TIMES_CONTACTED, 4);
+        profileValues.put(Contacts.TIMES_CONTACTED, 0);
         assertStoredValues(ContentUris.withAppendedId(
                 Profile.CONTENT_RAW_CONTACTS_URI, profileRawContactId), profileValues);
     }
@@ -7191,7 +7058,7 @@
         assertMetadataNetworkNotified(true);
     }
 
-    public void testMarkAsMetadataDirtyForUsageStatsChange() {
+    public void testMarkAsMetadataNotDirtyForUsageStatsChange() {
         // Enable metadataSync flag.
         final ContactsProvider2 cp = (ContactsProvider2) getProvider();
         cp.setMetadataSyncForTest(true);
@@ -7200,9 +7067,9 @@
         final long did1a = ContentUris.parseId(insertEmail(rid1, "email_1_a@email.com"));
         updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, did1a);
 
-        assertMetadataDirty(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rid1),
-                true);
-        assertMetadataNetworkNotified(true);
+        // Usage feedback no longer works, so "false".
+        assertMetadataDirty(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rid1), false);
+        assertMetadataNetworkNotified(false);
     }
 
     public void testMarkAsMetadataDirtyForDataPrimarySettingInsert() {
@@ -8821,7 +8688,7 @@
         }
     }
 
-    public void testMarkMetadataDirtyWhenDataUsageUpdate() {
+    public void testMarkMetadataNotDirtyWhenDataUsageUpdate() {
         // Enable metadataSync flag.
         final ContactsProvider2 cp = (ContactsProvider2) getProvider();
         cp.setMetadataSyncForTest(true);
@@ -8834,9 +8701,10 @@
         updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, did1a);
 
         assertDirty(rawContactUri, false);
-        assertMetadataDirty(rawContactUri, true);
+        // Usage feedback no longer works, so "false".
+        assertMetadataDirty(rawContactUri, false);
         assertNetworkNotified(false);
-        assertMetadataNetworkNotified(true);
+        assertMetadataNetworkNotified(false);
     }
 
     public void testDataUsageFeedbackAndDelete() {
@@ -8882,24 +8750,24 @@
         // Test 1. touch data 1a
         updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, did1a);
 
-        // Now, there's a single frequent.  (contact 1)
-        assertRowCount(1, Contacts.CONTENT_STREQUENT_URI, null, null);
+        // (We no longer populate frequent, so 0.)
+        assertRowCount(0, Contacts.CONTENT_STREQUENT_URI, null, null);
 
         sMockClock.advanceDay();
 
         // Test 2. touch data 1a, 2a and 3a
         updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, did1a, did2a, did3a);
 
-        // Now, contact 1 and 3 are in frequent.
-        assertRowCount(2, Contacts.CONTENT_STREQUENT_URI, null, null);
+        // (We no longer populate frequent, so 0.)
+        assertRowCount(0, Contacts.CONTENT_STREQUENT_URI, null, null);
 
         sMockClock.advanceDay();
 
         // Test 2. touch data 2p (call)
         updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_CALL, did2p);
 
-        // There're still two frequent.
-        assertRowCount(2, Contacts.CONTENT_STREQUENT_URI, null, null);
+        // (We no longer populate frequent, so 0.)
+        assertRowCount(0, Contacts.CONTENT_STREQUENT_URI, null, null);
 
         sMockClock.advanceDay();
 
@@ -8907,68 +8775,32 @@
         updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_SHORT_TEXT, did2p, did3p);
 
         // Let's check the tables.
-// TODO more tests?
+
         // Fist, check the data_usage_stat table, which has no public URI.
         assertStoredValuesDb("SELECT " + DataUsageStatColumns.DATA_ID +
                 "," + DataUsageStatColumns.USAGE_TYPE_INT +
                 "," + DataUsageStatColumns.RAW_TIMES_USED +
                 "," + DataUsageStatColumns.RAW_LAST_TIME_USED +
-                " FROM " + Tables.DATA_USAGE_STAT, null,
-                cv(DataUsageStatColumns.DATA_ID, did1a,
-                        DataUsageStatColumns.USAGE_TYPE_INT,
-                            DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT,
-                        DataUsageStatColumns.RAW_TIMES_USED, 2,
-                        DataUsageStatColumns.RAW_LAST_TIME_USED, startTime + 86400
-                        ),
-                cv(DataUsageStatColumns.DATA_ID, did2a,
-                        DataUsageStatColumns.USAGE_TYPE_INT,
-                            DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT,
-                        DataUsageStatColumns.RAW_TIMES_USED, 1,
-                        DataUsageStatColumns.RAW_LAST_TIME_USED, startTime + 86400
-                        ),
-                cv(DataUsageStatColumns.DATA_ID, did3a,
-                        DataUsageStatColumns.USAGE_TYPE_INT,
-                            DataUsageStatColumns.USAGE_TYPE_INT_LONG_TEXT,
-                        DataUsageStatColumns.RAW_TIMES_USED, 1,
-                        DataUsageStatColumns.RAW_LAST_TIME_USED, startTime + 86400
-                        ),
-                cv(DataUsageStatColumns.DATA_ID, did2p,
-                        DataUsageStatColumns.USAGE_TYPE_INT,
-                            DataUsageStatColumns.USAGE_TYPE_INT_CALL,
-                        DataUsageStatColumns.RAW_TIMES_USED, 1,
-                        DataUsageStatColumns.RAW_LAST_TIME_USED, startTime + 86400 * 2
-                        ),
-                cv(DataUsageStatColumns.DATA_ID, did2p,
-                        DataUsageStatColumns.USAGE_TYPE_INT,
-                            DataUsageStatColumns.USAGE_TYPE_INT_SHORT_TEXT,
-                        DataUsageStatColumns.RAW_TIMES_USED, 1,
-                        DataUsageStatColumns.RAW_LAST_TIME_USED, startTime + 86400 * 3
-                        ),
-                cv(DataUsageStatColumns.DATA_ID, did3p,
-                        DataUsageStatColumns.USAGE_TYPE_INT,
-                            DataUsageStatColumns.USAGE_TYPE_INT_SHORT_TEXT,
-                        DataUsageStatColumns.RAW_TIMES_USED, 1,
-                        DataUsageStatColumns.RAW_LAST_TIME_USED, startTime + 86400 * 3
-                        )
+                " FROM " + Tables.DATA_USAGE_STAT, null
                 );
 
         // Next, check the raw_contacts table
         assertStoredValuesWithProjection(RawContacts.CONTENT_URI,
                 cv(RawContacts._ID, rid1,
-                        RawContacts.TIMES_CONTACTED, 2,
-                        RawContacts.LAST_TIME_CONTACTED, (startTime + 86400) / 86400 * 86400
+                        RawContacts.TIMES_CONTACTED, 0,
+                        RawContacts.LAST_TIME_CONTACTED, 0
                         ),
                 cv(RawContacts._ID, rid2,
-                        RawContacts.TIMES_CONTACTED, 3,
-                        RawContacts.LAST_TIME_CONTACTED, (startTime + 86400 * 3) / 86400 * 86400
+                        RawContacts.TIMES_CONTACTED, 0,
+                        RawContacts.LAST_TIME_CONTACTED, 0
                         ),
                 cv(RawContacts._ID, rid3,
-                        RawContacts.TIMES_CONTACTED, 2,
-                        RawContacts.LAST_TIME_CONTACTED, (startTime + 86400 * 3) / 86400 * 86400
+                        RawContacts.TIMES_CONTACTED, 0,
+                        RawContacts.LAST_TIME_CONTACTED, 0
                         ),
                 cv(RawContacts._ID, rid4,
                         RawContacts.TIMES_CONTACTED, 0,
-                        RawContacts.LAST_TIME_CONTACTED, null // 4 wasn't touched.
+                        RawContacts.LAST_TIME_CONTACTED, 0
                         )
                 );
 
@@ -8979,12 +8811,12 @@
         // at once.
         assertStoredValuesWithProjection(Contacts.CONTENT_URI,
                 cv(Contacts._ID, cid1,
-                        Contacts.TIMES_CONTACTED, 4,
-                        Contacts.LAST_TIME_CONTACTED, (startTime + 86400 * 3) / 86400 * 86400
+                        Contacts.TIMES_CONTACTED, 0,
+                        Contacts.LAST_TIME_CONTACTED, 0
                         ),
                 cv(Contacts._ID, cid3,
-                        Contacts.TIMES_CONTACTED, 2,
-                        Contacts.LAST_TIME_CONTACTED, (startTime + 86400 * 3) / 86400 * 86400
+                        Contacts.TIMES_CONTACTED, 0,
+                        Contacts.LAST_TIME_CONTACTED, 0
                         ),
                 cv(Contacts._ID, cid4,
                         Contacts.TIMES_CONTACTED, 0,
@@ -9937,7 +9769,7 @@
     private void sendFeedback(String data1, String usageType, ContentValues values) {
         final long dataId = getStoredLongValue(Data.CONTENT_URI,
                 Data.DATA1 + "=?", new String[] { data1 }, Data._ID);
-        MoreAsserts.assertNotEqual(0, updateDataUsageFeedback(usageType, dataId));
+        assertEquals(0, updateDataUsageFeedback(usageType, dataId));
         if (values != null && values.containsKey(Contacts.TIMES_CONTACTED)) {
             values.put(Contacts.TIMES_CONTACTED, values.getAsInteger(Contacts.TIMES_CONTACTED) + 1);
         }
@@ -9946,7 +9778,7 @@
     private void updateDataUsageFeedback(String usageType, Uri resultUri) {
         final long id = ContentUris.parseId(resultUri);
         final boolean successful = updateDataUsageFeedback(usageType, id) > 0;
-        assertTrue(successful);
+        assertFalse(successful); // shouldn't succeed
     }
 
     private int updateDataUsageFeedback(String usageType, long... ids) {
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2TransactionTest.java b/tests/src/com/android/providers/contacts/ContactsProvider2TransactionTest.java
index 03c9e75..d7b78d6 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2TransactionTest.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2TransactionTest.java
@@ -197,7 +197,7 @@
     private void checkStoredContact() {
         assertStoredValues(Contacts.CONTENT_URI, cv(
                 Contacts.DISPLAY_NAME, "Regular Contact",
-                RawContacts.LAST_TIME_CONTACTED, 86400 * 21
+                RawContacts.LAST_TIME_CONTACTED, 0
                 ));
     }
 
@@ -227,7 +227,7 @@
     private void checkStoredProfile() {
         assertStoredValues(Profile.CONTENT_URI, cv(
                 Contacts.DISPLAY_NAME, "Profile Contact",
-                RawContacts.LAST_TIME_CONTACTED, 86400 * 11
+                RawContacts.LAST_TIME_CONTACTED, 0
                 ));
     }
 
diff --git a/tests/src/com/android/providers/contacts/ContactsTaskSchedulerTest.java b/tests/src/com/android/providers/contacts/ContactsTaskSchedulerTest.java
index df7196d..fe53c28 100644
--- a/tests/src/com/android/providers/contacts/ContactsTaskSchedulerTest.java
+++ b/tests/src/com/android/providers/contacts/ContactsTaskSchedulerTest.java
@@ -15,7 +15,6 @@
  */
 package com.android.providers.contacts;
 
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 
 import java.util.ArrayList;
@@ -25,7 +24,7 @@
 import java.util.concurrent.TimeUnit;
 
 @LargeTest
-public class ContactsTaskSchedulerTest extends AndroidTestCase {
+public class ContactsTaskSchedulerTest extends FixedAndroidTestCase {
     private static final int SHUTDOWN_SECONDS = 3;
 
     private static class MyContactsTaskScheduler extends ContactsTaskScheduler {
diff --git a/tests/src/com/android/providers/contacts/EnterpriseContactsCursorWrapperTest.java b/tests/src/com/android/providers/contacts/EnterpriseContactsCursorWrapperTest.java
index 66cebfc..7ae7b57 100644
--- a/tests/src/com/android/providers/contacts/EnterpriseContactsCursorWrapperTest.java
+++ b/tests/src/com/android/providers/contacts/EnterpriseContactsCursorWrapperTest.java
@@ -19,7 +19,6 @@
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.provider.ContactsContract.PhoneLookup;
-import android.test.AndroidTestCase;
 import android.test.MoreAsserts;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -27,7 +26,7 @@
 
 
 @SmallTest
-public class EnterpriseContactsCursorWrapperTest extends AndroidTestCase {
+public class EnterpriseContactsCursorWrapperTest extends FixedAndroidTestCase {
 
     public void testWrappedResults() {
         final String[] projection = new String[] {
diff --git a/tests/src/com/android/providers/contacts/FastScrollingIndexCacheTest.java b/tests/src/com/android/providers/contacts/FastScrollingIndexCacheTest.java
index 4580ce1..08625cd 100644
--- a/tests/src/com/android/providers/contacts/FastScrollingIndexCacheTest.java
+++ b/tests/src/com/android/providers/contacts/FastScrollingIndexCacheTest.java
@@ -20,14 +20,13 @@
 import android.os.Bundle;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.RawContacts;
-import android.test.AndroidTestCase;
 import android.test.MoreAsserts;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.providers.contacts.util.MockSharedPreferences;
 
 @SmallTest
-public class FastScrollingIndexCacheTest extends AndroidTestCase {
+public class FastScrollingIndexCacheTest extends FixedAndroidTestCase {
     private MockSharedPreferences mPrefs;
     private FastScrollingIndexCache mCache;
 
diff --git a/tests/src/com/android/providers/contacts/FixedAndroidTestCase.java b/tests/src/com/android/providers/contacts/FixedAndroidTestCase.java
new file mode 100644
index 0000000..5f0bda5
--- /dev/null
+++ b/tests/src/com/android/providers/contacts/FixedAndroidTestCase.java
@@ -0,0 +1,32 @@
+/*
+ * 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.providers.contacts;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+
+import androidx.test.InstrumentationRegistry;
+
+/**
+ * {@link FixedAndroidTestCase#getTestContext} isn't set when executed on the support test runner. This
+ * class works around that.
+ */
+public class FixedAndroidTestCase extends AndroidTestCase {
+    @Override
+    public Context getTestContext() {
+        return InstrumentationRegistry.getContext();
+    }
+}
diff --git a/tests/src/com/android/providers/contacts/MetadataEntryParserTest.java b/tests/src/com/android/providers/contacts/MetadataEntryParserTest.java
index be4df57..fe6ed13 100644
--- a/tests/src/com/android/providers/contacts/MetadataEntryParserTest.java
+++ b/tests/src/com/android/providers/contacts/MetadataEntryParserTest.java
@@ -17,7 +17,6 @@
 package com.android.providers.contacts;
 
 import android.content.Context;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import com.android.providers.contacts.MetadataEntryParser.AggregationData;
 import com.android.providers.contacts.MetadataEntryParser.FieldData;
@@ -41,7 +40,7 @@
  * </code>
  */
 @SmallTest
-public class MetadataEntryParserTest extends AndroidTestCase {
+public class MetadataEntryParserTest extends FixedAndroidTestCase {
 
     public void testErrorForEmptyInput() {
         try {
diff --git a/tests/src/com/android/providers/contacts/NameSplitterTest.java b/tests/src/com/android/providers/contacts/NameSplitterTest.java
index d9007fc..e0e5753 100644
--- a/tests/src/com/android/providers/contacts/NameSplitterTest.java
+++ b/tests/src/com/android/providers/contacts/NameSplitterTest.java
@@ -233,6 +233,25 @@
         assertFullNameStyle(FullNameStyle.CHINESE, "\uFF5C--(\u675C\u9D51)");
     }
 
+    public void testGuessFullNameStyleChineseMixed() {
+        createNameSplitter(Locale.CHINA);
+        // Both first and last names are Chinese.
+        assertFullNameStyle(FullNameStyle.CHINESE, "\u675C \u9D51");
+        // Last name is Chinese, first name is English.
+        assertFullNameStyle(FullNameStyle.CHINESE, "\u675C Juan");
+        // Last name is English, first name is Chinese.
+        assertFullNameStyle(FullNameStyle.CHINESE, "Du \u9D51");
+        // Both first and last names are English, prefix, middle, suffix are all Chinese.
+        Name name = new Name();
+        name.prefix = "\u524D";
+        name.givenNames = "Du";
+        name.middleName = "\u5C0F";
+        name.familyName = "Juan";
+        name.suffix = "\u540E";
+        mNameSplitter.guessNameStyle(name);
+        // guessFullNameStyle() only look at last and first name.
+        assertEquals(FullNameStyle.WESTERN, name.fullNameStyle);
+    }
 
     public void testGuessPhoneticNameStyle() {
 
diff --git a/tests/src/com/android/providers/contacts/PhoneLookupWithStarPrefixTest.java b/tests/src/com/android/providers/contacts/PhoneLookupWithStarPrefixTest.java
index cd86a42..d595580 100644
--- a/tests/src/com/android/providers/contacts/PhoneLookupWithStarPrefixTest.java
+++ b/tests/src/com/android/providers/contacts/PhoneLookupWithStarPrefixTest.java
@@ -16,12 +16,11 @@
 
 package com.android.providers.contacts;
 
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.SmallTest;
 
 @LargeTest
-public class PhoneLookupWithStarPrefixTest extends AndroidTestCase {
+public class PhoneLookupWithStarPrefixTest extends FixedAndroidTestCase {
 
     @SmallTest
     public void testNormalizeNumberWithStar() {
diff --git a/tests/src/com/android/providers/contacts/PhotoLoadingTestCase.java b/tests/src/com/android/providers/contacts/PhotoLoadingTestCase.java
index 4b159a8..4b199c6 100644
--- a/tests/src/com/android/providers/contacts/PhotoLoadingTestCase.java
+++ b/tests/src/com/android/providers/contacts/PhotoLoadingTestCase.java
@@ -17,7 +17,6 @@
 package com.android.providers.contacts;
 
 import android.content.res.Resources;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.google.android.collect.Maps;
@@ -31,7 +30,7 @@
  * Adds support for loading photo files easily from test resources.
  */
 @SmallTest
-public class PhotoLoadingTestCase extends AndroidTestCase {
+public class PhotoLoadingTestCase extends FixedAndroidTestCase {
 
     private Map<Integer, PhotoEntry> photoResourceCache = Maps.newHashMap();
     protected static enum PhotoSize {
diff --git a/tests/src/com/android/providers/contacts/PhotoPriorityResolverTest.java b/tests/src/com/android/providers/contacts/PhotoPriorityResolverTest.java
index b105595..a2dd81d 100644
--- a/tests/src/com/android/providers/contacts/PhotoPriorityResolverTest.java
+++ b/tests/src/com/android/providers/contacts/PhotoPriorityResolverTest.java
@@ -16,7 +16,6 @@
 
 package com.android.providers.contacts;
 
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 
 /**
@@ -29,7 +28,7 @@
  * </code>
  */
 @MediumTest
-public class PhotoPriorityResolverTest extends AndroidTestCase {
+public class PhotoPriorityResolverTest extends FixedAndroidTestCase {
 
     public void testLoadPicturePriorityFromXml() {
         PhotoPriorityResolver resolver = new PhotoPriorityResolver(getContext());
diff --git a/tests/src/com/android/providers/contacts/PhotoProcessorTest.java b/tests/src/com/android/providers/contacts/PhotoProcessorTest.java
index 4b59be9..ab7b7fc 100644
--- a/tests/src/com/android/providers/contacts/PhotoProcessorTest.java
+++ b/tests/src/com/android/providers/contacts/PhotoProcessorTest.java
@@ -20,7 +20,6 @@
 import android.graphics.Color;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.providers.contacts.tests.R;
@@ -34,7 +33,7 @@
  * Most of tests are covered by {@link PhotoStoreTest}.
  */
 @SmallTest
-public class PhotoProcessorTest extends AndroidTestCase {
+public class PhotoProcessorTest extends FixedAndroidTestCase {
 
     public void testTransparency() throws IOException {
         final Drawable source = getTestContext().getResources().getDrawable(
diff --git a/tests/src/com/android/providers/contacts/TestUtils.java b/tests/src/com/android/providers/contacts/TestUtils.java
index 322e5b4..689ea7c 100644
--- a/tests/src/com/android/providers/contacts/TestUtils.java
+++ b/tests/src/com/android/providers/contacts/TestUtils.java
@@ -20,15 +20,16 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
 import android.os.FileUtils;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Profile;
 import android.provider.ContactsContract.RawContacts;
-import android.support.annotation.Nullable;
-import android.database.sqlite.SQLiteDatabase;
-import android.net.Uri;
 import android.util.Log;
 
+import androidx.annotation.Nullable;
+
 import com.android.providers.contacts.ContactsDatabaseHelper.Tables;
 
 import junit.framework.Assert;
diff --git a/tests/src/com/android/providers/contacts/VoicemailProviderTest.java b/tests/src/com/android/providers/contacts/VoicemailProviderTest.java
index d20b9b3..9f9ef00 100644
--- a/tests/src/com/android/providers/contacts/VoicemailProviderTest.java
+++ b/tests/src/com/android/providers/contacts/VoicemailProviderTest.java
@@ -21,10 +21,8 @@
 
 import android.content.ContentUris;
 import android.content.ContentValues;
-import android.database.ContentObserver;
 import android.database.Cursor;
 import android.net.Uri;
-import android.os.Handler;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.provider.CallLog;
@@ -741,28 +739,6 @@
         assertStoredValues(uri, values);
     }
 
-    public void testStatusUpdate_observerNotified() throws Exception {
-        Uri uri = insertTestStatusEntry();
-        ContentValues values = getTestStatusValues();
-        values.put(Status.DATA_CHANNEL_STATE, Status.DATA_CHANNEL_STATE_NO_CONNECTION);
-        values.put(Status.NOTIFICATION_CHANNEL_STATE,
-            Status.NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING);
-        values.put(Status.SOURCE_TYPE,
-            "vvm_type_test2");
-        Boolean[] observerTriggered = new Boolean[]{false};
-        mResolver.registerContentObserver(Status.CONTENT_URI, true,
-            new ContentObserver(new Handler()) {
-                @Override
-                public void onChange(boolean selfChange, Uri uri) {
-                    observerTriggered[0] = true;
-                }
-            });
-
-        mResolver.update(uri, values, null, null);
-
-        assertTrue(observerTriggered[0]);
-    }
-
     public void testStatusUpsert() throws Exception {
         ContentValues values = getTestStatusValues();
         mResolver.insert(statusUri(), values);
diff --git a/tests/src/com/android/providers/contacts/aggregation/util/ContactMatcherTest.java b/tests/src/com/android/providers/contacts/aggregation/util/ContactMatcherTest.java
index 301902a..09a0b78 100644
--- a/tests/src/com/android/providers/contacts/aggregation/util/ContactMatcherTest.java
+++ b/tests/src/com/android/providers/contacts/aggregation/util/ContactMatcherTest.java
@@ -16,12 +16,12 @@
 package com.android.providers.contacts.aggregation.util;
 
 import com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType;
+import com.android.providers.contacts.FixedAndroidTestCase;
 
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
 @SmallTest
-public class ContactMatcherTest extends AndroidTestCase {
+public class ContactMatcherTest extends FixedAndroidTestCase {
 
     public void testMatchName_invalidHexDecimal() {
         final ContactMatcher matcher = new ContactMatcher();
diff --git a/tests/src/com/android/providers/contacts/enterprise/EnterprisePolicyGuardTest.java b/tests/src/com/android/providers/contacts/enterprise/EnterprisePolicyGuardTest.java
index 99ff9a1..c068459 100644
--- a/tests/src/com/android/providers/contacts/enterprise/EnterprisePolicyGuardTest.java
+++ b/tests/src/com/android/providers/contacts/enterprise/EnterprisePolicyGuardTest.java
@@ -24,7 +24,6 @@
 import android.os.UserManager;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Directory;
-import android.test.AndroidTestCase;
 import android.test.mock.MockContext;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -36,12 +35,14 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import com.android.providers.contacts.FixedAndroidTestCase;
+
 
 /**
  * Unit tests for {@link EnterprisePolicyGuard}.
  */
 @SmallTest
-public class EnterprisePolicyGuardTest extends AndroidTestCase {
+public class EnterprisePolicyGuardTest extends FixedAndroidTestCase {
     private static final String SYSTEM_PROPERTY_DEXMAKER_DEXCACHE = "dexmaker.dexcache";
 
     private static final int CONTACT_ID = 10;
diff --git a/tests/src/com/android/providers/contacts/sqlite/DatabaseAnalyzerTest.java b/tests/src/com/android/providers/contacts/sqlite/DatabaseAnalyzerTest.java
index 568e1e8..8367ef5 100644
--- a/tests/src/com/android/providers/contacts/sqlite/DatabaseAnalyzerTest.java
+++ b/tests/src/com/android/providers/contacts/sqlite/DatabaseAnalyzerTest.java
@@ -16,14 +16,14 @@
 
 package com.android.providers.contacts.sqlite;
 
-import android.test.AndroidTestCase;
 
 import com.android.providers.contacts.ContactsDatabaseHelper;
+import com.android.providers.contacts.FixedAndroidTestCase;
 import com.android.providers.contacts.TestUtils;
 
 import java.util.List;
 
-public class DatabaseAnalyzerTest extends AndroidTestCase {
+public class DatabaseAnalyzerTest extends FixedAndroidTestCase {
     public void testFindTableViewsAllowingColumns() {
         final ContactsDatabaseHelper dbh =
                 ContactsDatabaseHelper.getNewInstanceForTest(getContext(),
diff --git a/tests/src/com/android/providers/contacts/sqlite/SqlCheckerTest.java b/tests/src/com/android/providers/contacts/sqlite/SqlCheckerTest.java
index ee2b5be..b69b427 100644
--- a/tests/src/com/android/providers/contacts/sqlite/SqlCheckerTest.java
+++ b/tests/src/com/android/providers/contacts/sqlite/SqlCheckerTest.java
@@ -15,16 +15,16 @@
  */
 package com.android.providers.contacts.sqlite;
 
-import android.test.AndroidTestCase;
 import android.test.MoreAsserts;
 
+import com.android.providers.contacts.FixedAndroidTestCase;
 import com.android.providers.contacts.sqlite.SqlChecker.InvalidSqlException;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
-public class SqlCheckerTest extends AndroidTestCase {
+public class SqlCheckerTest extends FixedAndroidTestCase {
     private ArrayList<String> getTokens(String sql) {
         final ArrayList<String> tokens = new ArrayList<>();
 
diff --git a/tests/src/com/android/providers/contacts/util/SelectionBuilderTest.java b/tests/src/com/android/providers/contacts/util/SelectionBuilderTest.java
index 7adbeca..4615fbd 100644
--- a/tests/src/com/android/providers/contacts/util/SelectionBuilderTest.java
+++ b/tests/src/com/android/providers/contacts/util/SelectionBuilderTest.java
@@ -16,14 +16,15 @@
 
 package com.android.providers.contacts.util;
 
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.providers.contacts.FixedAndroidTestCase;
+
 /**
  * Unit tests for {@link SelectionBuilder}.
  */
 @SmallTest
-public class SelectionBuilderTest extends AndroidTestCase {
+public class SelectionBuilderTest extends FixedAndroidTestCase {
     public void testEmptyClauses() {
         assertEquals(null, new SelectionBuilder(null).build());
         assertEquals(null, new SelectionBuilder("").build());
diff --git a/tests/src/com/android/providers/contacts/util/TypedUriMatcherImplTest.java b/tests/src/com/android/providers/contacts/util/TypedUriMatcherImplTest.java
index 329e6e2..d2a7b14 100644
--- a/tests/src/com/android/providers/contacts/util/TypedUriMatcherImplTest.java
+++ b/tests/src/com/android/providers/contacts/util/TypedUriMatcherImplTest.java
@@ -17,9 +17,10 @@
 package com.android.providers.contacts.util;
 
 import android.net.Uri;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.providers.contacts.FixedAndroidTestCase;
+
 /**
  * Unit tests for {@link TypedUriMatcherImpl}.
  * Run the test like this:
@@ -28,7 +29,7 @@
  * </code>
  */
 @SmallTest
-public class TypedUriMatcherImplTest extends AndroidTestCase {
+public class TypedUriMatcherImplTest extends FixedAndroidTestCase {
     /** URI type used for testing. */
     private static enum TestUriType implements UriType {
         NO_MATCH(null),
diff --git a/tests/src/com/android/providers/contacts/util/UserUtilsTest.java b/tests/src/com/android/providers/contacts/util/UserUtilsTest.java
index 611ad3f..93613cf 100644
--- a/tests/src/com/android/providers/contacts/util/UserUtilsTest.java
+++ b/tests/src/com/android/providers/contacts/util/UserUtilsTest.java
@@ -15,21 +15,19 @@
  */
 package com.android.providers.contacts.util;
 
-import com.android.providers.contacts.ContactsActor;
-import com.android.providers.contacts.ContactsActor.MockUserManager;
-import com.android.providers.contacts.SynchronousContactsProvider2;
-
-import android.content.ContentProvider;
-import android.content.Context;
-import android.os.UserManager;
-import android.provider.ContactsContract;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
 import static com.android.providers.contacts.ContactsActor.PACKAGE_GREY;
 
+import android.content.Context;
+import android.provider.ContactsContract;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.providers.contacts.ContactsActor;
+import com.android.providers.contacts.ContactsActor.MockUserManager;
+import com.android.providers.contacts.FixedAndroidTestCase;
+import com.android.providers.contacts.SynchronousContactsProvider2;
+
 @SmallTest
-public class UserUtilsTest extends AndroidTestCase {
+public class UserUtilsTest extends FixedAndroidTestCase {
 
     protected ContactsActor mActor;
 
diff --git a/tests2/Android.bp b/tests2/Android.bp
new file mode 100644
index 0000000..9a2351a
--- /dev/null
+++ b/tests2/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2016 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.
+//
+
+android_test {
+    name: "ContactsProviderTests2",
+    static_libs: [
+        "ContactsProviderTestUtils",
+        "androidx.test.rules",
+        "mockito-target-minus-junit4",
+    ],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    test_suites: ["device-tests"],
+    instrumentation_for: "ContactsProvider",
+    certificate: "shared",
+    optimize: {
+        enabled: false,
+    },
+}
diff --git a/tests2/Android.mk b/tests2/Android.mk
deleted file mode 100644
index 4ba0a12..0000000
--- a/tests2/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# Copyright (C) 2016 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    ContactsProviderTestUtils \
-    android-support-test \
-    mockito-target-minus-junit4
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := ContactsProviderTests2
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_INSTRUMENTATION_FOR := ContactsProvider
-LOCAL_CERTIFICATE := shared
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
diff --git a/tests2/AndroidManifest.xml b/tests2/AndroidManifest.xml
index 7678bd2..fc00251 100644
--- a/tests2/AndroidManifest.xml
+++ b/tests2/AndroidManifest.xml
@@ -30,6 +30,6 @@
     </application>
 
     <instrumentation
-        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.providers.contacts.tests2" />
 </manifest>
diff --git a/tests2/AndroidTest.xml b/tests2/AndroidTest.xml
index 29fdc83..957350b 100644
--- a/tests2/AndroidTest.xml
+++ b/tests2/AndroidTest.xml
@@ -20,9 +20,8 @@
 
     <option name="test-suite-tag" value="apct" />
     <option name="test-tag" value="ContactsProviderTests2" />
-    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.providers.contacts.tests2" />
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
 </configuration>
diff --git a/tests2/src/com/android/providers/contacts/tests2/AllUriTest.java b/tests2/src/com/android/providers/contacts/tests2/AllUriTest.java
index 2aa6a61..30fd3be 100644
--- a/tests2/src/com/android/providers/contacts/tests2/AllUriTest.java
+++ b/tests2/src/com/android/providers/contacts/tests2/AllUriTest.java
@@ -371,14 +371,18 @@
     public void testSelect() {
         for (String[] path : URIs) {
             if (!supportsQuery(path)) continue;
-            final Uri uri = getUri(path);
+            try {
+                final Uri uri = getUri(path);
 
-            checkQueryExecutable(uri, // uri
-                    null, // projection
-                    null, // selection
-                    null, // selection args
-                    null // sort order
-                    );
+                checkQueryExecutable(uri, // uri
+                        null, // projection
+                        null, // selection
+                        null, // selection args
+                        null // sort order
+                        );
+            } catch (Throwable th) {
+                addFailure("Failed: URI=" + path[0] + " Message=" + th.getMessage(), th);
+            }
         }
         failIfFailed();
     }
@@ -386,12 +390,16 @@
     public void testNoHiddenColumns() {
         for (String[] path : URIs) {
             if (!supportsQuery(path)) continue;
-            final Uri uri = getUri(path);
+            try {
+                final Uri uri = getUri(path);
 
-            for (String column : getColumns(uri)) {
-                if (column.toLowerCase().startsWith(ContactsContract.HIDDEN_COLUMN_PREFIX)) {
-                    addFailure("Uri " + uri + " returned hidden column " + column, null);
+                for (String column : getColumns(uri)) {
+                    if (column.toLowerCase().startsWith(ContactsContract.HIDDEN_COLUMN_PREFIX)) {
+                        addFailure("Uri " + uri + " returned hidden column " + column, null);
+                    }
                 }
+            } catch (Throwable th) {
+                addFailure("Failed: URI=" + path[0] + " Message=" + th.getMessage(), th);
             }
         }
         failIfFailed();
@@ -649,41 +657,45 @@
         for (String[] path : URIs) {
             final Uri uri = getUri(path);
 
-            cv.clear();
-            if (supportsQuery(path)) {
-                cv.put(getColumns(uri)[0], 1);
-            } else {
-                cv.put("_id", 1);
-            }
-            if (uri.toString().contains("syncstate")) {
-                cv.put(SyncState.ACCOUNT_NAME, "abc");
-                cv.put(SyncState.ACCOUNT_TYPE, "def");
-            }
-
-            checkExecutable("insert", uri, supportsInsert(path), () -> {
-                final Uri newUri = mResolver.insert(uri, cv);
-                if (newUri == null) {
-                    addFailure("Insert for '" + uri + "' returned null.", null);
+            try {
+                cv.clear();
+                if (supportsQuery(path)) {
+                    cv.put(getColumns(uri)[0], 1);
                 } else {
-                    // "profile/raw_contacts/#" is missing update support.  too late to add, so
-                    // just skip.
-                    if (!newUri.toString().startsWith(
-                            "content://com.android.contacts/profile/raw_contacts/")) {
-                        checkExecutable("insert -> update", newUri, true, () -> {
-                            mResolver.update(newUri, cv, null, null);
+                    cv.put("_id", 1);
+                }
+                if (uri.toString().contains("syncstate")) {
+                    cv.put(SyncState.ACCOUNT_NAME, "abc");
+                    cv.put(SyncState.ACCOUNT_TYPE, "def");
+                }
+
+                checkExecutable("insert", uri, supportsInsert(path), () -> {
+                    final Uri newUri = mResolver.insert(uri, cv);
+                    if (newUri == null) {
+                        addFailure("Insert for '" + uri + "' returned null.", null);
+                    } else {
+                        // "profile/raw_contacts/#" is missing update support.  too late to add, so
+                        // just skip.
+                        if (!newUri.toString().startsWith(
+                                "content://com.android.contacts/profile/raw_contacts/")) {
+                            checkExecutable("insert -> update", newUri, true, () -> {
+                                mResolver.update(newUri, cv, null, null);
+                            });
+                        }
+                        checkExecutable("insert -> delete", newUri, true, () -> {
+                            mResolver.delete(newUri, null, null);
                         });
                     }
-                    checkExecutable("insert -> delete", newUri, true, () -> {
-                        mResolver.delete(newUri, null, null);
-                    });
-                }
-            });
-            checkExecutable("update", uri, supportsUpdate(path), () -> {
-                mResolver.update(uri, cv, "1=2", null);
-            });
-            checkExecutable("delete", uri, supportsDelete(path), () -> {
-                mResolver.delete(uri, "1=2", null);
-            });
+                });
+                checkExecutable("update", uri, supportsUpdate(path), () -> {
+                    mResolver.update(uri, cv, "1=2", null);
+                });
+                checkExecutable("delete", uri, supportsDelete(path), () -> {
+                    mResolver.delete(uri, "1=2", null);
+                });
+            } catch (Throwable th) {
+                addFailure("Failed: URI=" + uri + " Message=" + th.getMessage(), th);
+            }
         }
         failIfFailed();
     }