Use framework API to get local contacts account

Test: built the app and manually verified that the local account
is available when no google account is present but is hidden when a
google account is added and it has not contacts.

Bug: 155985097

Change-Id: I7d15c10ce154aabf6d6ced06459c49ac4a7e5053
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index bc37284..58e1ba5 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -16,8 +16,8 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.contacts"
-          android:versionCode="10732"
-          android:versionName="1.7.32">
+          android:versionCode="10733"
+          android:versionName="1.7.33">
 
     <uses-sdk
         android:minSdkVersion="21"
diff --git a/proguard.flags b/proguard.flags
index 782aa7e..9543f9d 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -57,7 +57,6 @@
 -keep class com.android.contacts.model.BuilderWrapper { *; }
 -keep class com.android.contacts.model.Contact { *; }
 -keep class com.android.contacts.model.ContactLoader { *; }
--keep class com.android.contacts.model.Cp2DeviceLocalAccountLocator { *; }
 -keep class com.android.contacts.model.CPOWrapper { *; }
 -keep class com.android.contacts.model.dataitem.DataItem { *; }
 -keep class com.android.contacts.model.dataitem.DataKind { *; }
diff --git a/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java b/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
index dea134b..8f0509b 100644
--- a/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
@@ -141,7 +141,8 @@
             mAccountListAdapter = new AccountsListAdapter(this, accounts);
             accountListView.setAdapter(mAccountListAdapter);
             accountListView.setOnItemClickListener(mAccountListItemClickListener);
-        } else if (numAccounts == 1 && !accounts.get(0).getAccount().isNullAccount()) {
+        } else if (numAccounts == 1
+                && !accounts.get(0).getAccount().equals(AccountWithDataSet.getLocalAccount(this))) {
             // If the user has 1 writable account we will just show the user a message with 2
             // possible action buttons.
             view = View.inflate(this,
diff --git a/src/com/android/contacts/editor/ContactEditorUtils.java b/src/com/android/contacts/editor/ContactEditorUtils.java
index 517c2c7..0e9b5c9 100644
--- a/src/com/android/contacts/editor/ContactEditorUtils.java
+++ b/src/com/android/contacts/editor/ContactEditorUtils.java
@@ -38,9 +38,11 @@
 public class ContactEditorUtils {
     private static final String TAG = "ContactEditorUtils";
 
+    private final Context mContext;
     private final ContactsPreferences mContactsPrefs;
 
     private ContactEditorUtils(Context context) {
+        mContext = context;
         mContactsPrefs = new ContactsPreferences(context);
     }
 
@@ -122,7 +124,7 @@
     public void maybeUpdateDefaultAccount(List<AccountWithDataSet> currentWritableAccounts) {
         if (currentWritableAccounts.size() == 1) {
             final AccountWithDataSet onlyAccount = currentWritableAccounts.get(0);
-            if (!onlyAccount.isNullAccount()
+            if (!onlyAccount.equals(AccountWithDataSet.getLocalAccount(mContext))
                     && !onlyAccount.equals(mContactsPrefs.getDefaultAccount())) {
                 mContactsPrefs.setDefaultAccount(onlyAccount);
             }
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index 196e67f..5a14b09 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -27,17 +27,14 @@
 import android.content.SharedPreferences;
 import android.content.SyncStatusObserver;
 import android.content.pm.PackageManager;
-import android.database.ContentObserver;
-import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
-import android.provider.ContactsContract;
-import androidx.core.content.ContextCompat;
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
 import android.text.TextUtils;
 import android.util.Log;
 
-import com.android.contacts.Experiments;
+import androidx.core.content.ContextCompat;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+
 import com.android.contacts.R;
 import com.android.contacts.list.ContactListFilterController;
 import com.android.contacts.model.account.AccountInfo;
@@ -49,10 +46,10 @@
 import com.android.contacts.model.account.GoogleAccountType;
 import com.android.contacts.model.dataitem.DataKind;
 import com.android.contacts.util.concurrent.ContactsExecutors;
-import com.android.contactsbind.experiments.Flags;
-import com.google.common.base.Preconditions;
+
 import com.google.common.base.Function;
 import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.google.common.util.concurrent.FutureCallback;
@@ -376,7 +373,7 @@
      */
     public AccountTypeManagerImpl(Context context) {
         mContext = context;
-        mLocalAccountLocator = DeviceLocalAccountLocator.create(context);
+        mLocalAccountLocator = new DeviceLocalAccountLocator(context, AccountManager.get(context));
         mTypeProvider = new AccountTypeProvider(context);
         mFallbackAccountType = new FallbackAccountType(context);
 
@@ -405,26 +402,6 @@
 
         ContentResolver.addStatusChangeListener(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, this);
 
-        // Observe changes to RAW_CONTACTS so that we will update the list of "Device" accounts
-        // if a new device contact is added or removed.
-        mContext.getContentResolver().registerContentObserver(
-                ContactsContract.RawContacts.CONTENT_URI, /* notifyDescendents */ true,
-                new ContentObserver(mMainThreadHandler) {
-                    @Override
-                    public boolean deliverSelfNotifications() {
-                        return true;
-                    }
-
-                    @Override
-                    public void onChange(boolean selfChange) {
-                        reloadLocalAccounts();
-                    }
-
-                    @Override
-                    public void onChange(boolean selfChange, Uri uri) {
-                        reloadLocalAccounts();
-                    }
-                });
         loadAccountTypes();
     }
 
diff --git a/src/com/android/contacts/model/Cp2DeviceLocalAccountLocator.java b/src/com/android/contacts/model/Cp2DeviceLocalAccountLocator.java
deleted file mode 100644
index 32912dc..0000000
--- a/src/com/android/contacts/model/Cp2DeviceLocalAccountLocator.java
+++ /dev/null
@@ -1,139 +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.
- */
-package com.android.contacts.model;
-
-import android.accounts.AccountManager;
-import android.content.ContentResolver;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.ContactsContract;
-import androidx.annotation.VisibleForTesting;
-
-import com.android.contacts.model.account.AccountWithDataSet;
-import com.android.contacts.util.DeviceLocalAccountTypeFactory;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Attempts to create accounts for "Device" contacts by querying
- * CP2 for records with {@link android.provider.ContactsContract.RawContacts#ACCOUNT_TYPE} columns
- * that do not exist for any account returned by {@link AccountManager#getAccounts()}
- *
- * This class should be used from a background thread since it does DB queries
- */
-public class Cp2DeviceLocalAccountLocator extends DeviceLocalAccountLocator {
-
-    // Note this class is assuming ACCOUNT_NAME and ACCOUNT_TYPE have same values in
-    // RawContacts, Groups, and Settings. This assumption simplifies the code somewhat and it
-    // is true right now and unlikely to ever change.
-    @VisibleForTesting
-    static String[] PROJECTION = new String[] {
-            ContactsContract.RawContacts.ACCOUNT_NAME, ContactsContract.RawContacts.ACCOUNT_TYPE,
-            ContactsContract.RawContacts.DATA_SET
-    };
-
-    private static final int COL_NAME = 0;
-    private static final int COL_TYPE = 1;
-    private static final int COL_DATA_SET = 2;
-
-    private final ContentResolver mResolver;
-    private final DeviceLocalAccountTypeFactory mAccountTypeFactory;
-
-    private final String mSelection;
-    private final String[] mSelectionArgs;
-
-    public Cp2DeviceLocalAccountLocator(ContentResolver contentResolver,
-            DeviceLocalAccountTypeFactory factory,
-            Set<String> knownAccountTypes) {
-        mResolver = contentResolver;
-        mAccountTypeFactory = factory;
-
-        mSelection = getSelection(knownAccountTypes);
-        mSelectionArgs = getSelectionArgs(knownAccountTypes);
-    }
-
-    @Override
-    public List<AccountWithDataSet> getDeviceLocalAccounts() {
-
-        final Set<AccountWithDataSet> localAccounts = new HashSet<>();
-
-        // Many device accounts have default groups associated with them.
-        addAccountsFromQuery(ContactsContract.Groups.CONTENT_URI, localAccounts);
-        addAccountsFromQuery(ContactsContract.Settings.CONTENT_URI, localAccounts);
-        addAccountsFromQuery(ContactsContract.RawContacts.CONTENT_URI, localAccounts);
-
-        return new ArrayList<>(localAccounts);
-    }
-
-    private void addAccountsFromQuery(Uri uri, Set<AccountWithDataSet> accounts) {
-        final Cursor cursor = mResolver.query(uri, PROJECTION, mSelection, mSelectionArgs, null);
-
-        if (cursor == null) return;
-
-        try {
-            addAccountsFromCursor(cursor, accounts);
-        } finally {
-            cursor.close();
-        }
-    }
-
-    private void addAccountsFromCursor(Cursor cursor, Set<AccountWithDataSet> accounts) {
-        while (cursor.moveToNext()) {
-            final String name = cursor.getString(COL_NAME);
-            final String type = cursor.getString(COL_TYPE);
-            final String dataSet = cursor.getString(COL_DATA_SET);
-
-            if (DeviceLocalAccountTypeFactory.Util.isLocalAccountType(
-                    mAccountTypeFactory, type)) {
-                accounts.add(new AccountWithDataSet(name, type, dataSet));
-            }
-        }
-    }
-
-    @VisibleForTesting
-    public String getSelection() {
-        return mSelection;
-    }
-
-    @VisibleForTesting
-    public String[] getSelectionArgs() {
-        return mSelectionArgs;
-    }
-
-    private static String getSelection(Set<String> knownAccountTypes) {
-        final StringBuilder sb = new StringBuilder()
-                .append(ContactsContract.RawContacts.ACCOUNT_TYPE).append(" IS NULL");
-        if (knownAccountTypes.isEmpty()) {
-            return sb.toString();
-        }
-        sb.append(" OR ").append(ContactsContract.RawContacts.ACCOUNT_TYPE).append(" NOT IN (");
-        for (String ignored : knownAccountTypes) {
-            sb.append("?,");
-        }
-        // Remove trailing ','
-        sb.deleteCharAt(sb.length() - 1).append(')');
-        return sb.toString();
-    }
-
-    private static String[] getSelectionArgs(Set<String> knownAccountTypes) {
-        if (knownAccountTypes.isEmpty()) return null;
-
-        return knownAccountTypes.toArray(new String[knownAccountTypes.size()]);
-    }
-}
diff --git a/src/com/android/contacts/model/DeviceLocalAccountLocator.java b/src/com/android/contacts/model/DeviceLocalAccountLocator.java
index 2b987d3..e8a2ba0 100644
--- a/src/com/android/contacts/model/DeviceLocalAccountLocator.java
+++ b/src/com/android/contacts/model/DeviceLocalAccountLocator.java
@@ -18,92 +18,40 @@
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.content.Context;
-import android.database.Cursor;
 import android.provider.ContactsContract;
 
-import com.android.contacts.Experiments;
 import com.android.contacts.model.account.AccountWithDataSet;
 import com.android.contacts.model.account.GoogleAccountType;
-import com.android.contactsbind.ObjectFactory;
-import com.android.contactsbind.experiments.Flags;
 
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 /**
  * Attempts to detect accounts for device contacts
  */
-public abstract class DeviceLocalAccountLocator {
+public final class DeviceLocalAccountLocator {
+
+    private final Context mContext;
+    private final AccountManager mAccountManager;
+    private final List<AccountWithDataSet> mLocalAccount;
+
+    public DeviceLocalAccountLocator(Context context, AccountManager accountManager) {
+        mContext = context;
+        mAccountManager = accountManager;
+        mLocalAccount = Collections.singletonList(AccountWithDataSet.getLocalAccount(context));
+    }
 
     /**
      * Returns a list of device local accounts
      */
-    public abstract List<AccountWithDataSet> getDeviceLocalAccounts();
+    public List<AccountWithDataSet> getDeviceLocalAccounts() {
+        @SuppressWarnings("MissingPermission") final Account[] accounts = mAccountManager
+                .getAccountsByType(GoogleAccountType.ACCOUNT_TYPE);
 
-    // This works on Nexus and AOSP because the local device account is the null account but most
-    // OEMs have a special account name and type for their device account.
-    public static final DeviceLocalAccountLocator NULL_ONLY = new DeviceLocalAccountLocator() {
-        @Override
-        public List<AccountWithDataSet> getDeviceLocalAccounts() {
-            return Collections.singletonList(AccountWithDataSet.getNullAccount());
-        }
-    };
-
-    public static DeviceLocalAccountLocator create(Context context,
-            Set<String> knownAccountTypes) {
-        if (Flags.getInstance().getBoolean(Experiments.CP2_DEVICE_ACCOUNT_DETECTION_ENABLED)) {
-            return new Cp2DeviceLocalAccountLocator(context.getContentResolver(),
-                    ObjectFactory.getDeviceLocalAccountTypeFactory(context), knownAccountTypes);
-        }
-        return NULL_ONLY;
-    }
-
-    public static DeviceLocalAccountLocator create(Context context) {
-        final AccountManager accountManager =
-                (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
-        final Set<String> knownTypes = new HashSet<>();
-        for (Account account : accountManager.getAccounts()) {
-            knownTypes.add(account.type);
-        }
-        if (Flags.getInstance().getBoolean(Experiments.CP2_DEVICE_ACCOUNT_DETECTION_ENABLED)) {
-            return new Cp2DeviceLocalAccountLocator(context.getContentResolver(),
-                    ObjectFactory.getDeviceLocalAccountTypeFactory(context), knownTypes);
+        if (accounts.length > 0 && !mLocalAccount.get(0).hasData(mContext)) {
+            return Collections.emptyList();
         } else {
-            return new NexusDeviceAccountLocator(context, accountManager);
-        }
-    }
-
-    /**
-     * On Nexus the "device" account uses "null" values for the account name and type columns
-     *
-     * <p>However, the focus sync adapter migrates contacts from this null account to a Google
-     * account if one exists. Hence, the device account should be returned only when there is no
-     * Google Account added or when there already exists contacts in the null account.
-     * </p>
-     */
-    public static class NexusDeviceAccountLocator extends DeviceLocalAccountLocator {
-        private final Context mContext;
-        private final AccountManager mAccountManager;
-
-
-        public NexusDeviceAccountLocator(Context context, AccountManager accountManager) {
-            mContext = context;
-            mAccountManager = accountManager;
-        }
-
-        @Override
-        public List<AccountWithDataSet> getDeviceLocalAccounts() {
-            @SuppressWarnings("MissingPermission")
-            final Account[] accounts = mAccountManager
-                    .getAccountsByType(GoogleAccountType.ACCOUNT_TYPE);
-
-            if (accounts.length > 0 && !AccountWithDataSet.getNullAccount().hasData(mContext)) {
-                return Collections.emptyList();
-            } else {
-                return Collections.singletonList(AccountWithDataSet.getNullAccount());
-            }
+            return mLocalAccount;
         }
     }
 }
diff --git a/src/com/android/contacts/model/account/AccountWithDataSet.java b/src/com/android/contacts/model/account/AccountWithDataSet.java
index a163139..9671762 100644
--- a/src/com/android/contacts/model/account/AccountWithDataSet.java
+++ b/src/com/android/contacts/model/account/AccountWithDataSet.java
@@ -28,8 +28,6 @@
 import android.provider.ContactsContract.RawContacts;
 import android.text.TextUtils;
 
-import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.preference.ContactsPreferences;
 import com.google.common.base.Objects;
 import com.google.common.collect.Lists;
 
@@ -88,6 +86,14 @@
         return new AccountWithDataSet(null, null, null);
     }
 
+    public static AccountWithDataSet getLocalAccount(Context context) {
+        return new AccountWithDataSet(
+                RawContacts.getLocalAccountName(context),
+                RawContacts.getLocalAccountType(context),
+                null
+        );
+    }
+
     public Account getAccountOrNull() {
         if (name != null && type != null) {
             return new Account(name, type);
diff --git a/src/com/android/contacts/preference/ContactsPreferences.java b/src/com/android/contacts/preference/ContactsPreferences.java
index 85da891..e92c356 100644
--- a/src/com/android/contacts/preference/ContactsPreferences.java
+++ b/src/com/android/contacts/preference/ContactsPreferences.java
@@ -16,7 +16,6 @@
 
 package com.android.contacts.preference;
 
-import android.app.backup.BackupAgent;
 import android.app.backup.BackupManager;
 import android.content.Context;
 import android.content.SharedPreferences;
@@ -27,9 +26,10 @@
 import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
+import android.text.TextUtils;
+
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
-import android.text.TextUtils;
 
 import com.android.contacts.R;
 import com.android.contacts.model.account.AccountWithDataSet;
@@ -256,15 +256,16 @@
             currentWritableAccounts) {
         final AccountWithDataSet defaultAccount = getDefaultAccount();
 
+        AccountWithDataSet localAccount = AccountWithDataSet.getLocalAccount(mContext);
         // This shouldn't occur anymore because a "device" account is added in the case that there
         // are no other accounts but if there are no writable accounts then the default has been
         // initialized if it is "device"
         if (currentWritableAccounts.isEmpty()) {
-            return defaultAccount == null || !defaultAccount.isNullAccount();
+            return defaultAccount == null || !defaultAccount.equals(localAccount);
         }
 
         if (currentWritableAccounts.size() == 1
-                && !currentWritableAccounts.get(0).isNullAccount()) {
+                && !currentWritableAccounts.get(0).equals(localAccount)) {
             return false;
         }
 
diff --git a/tests/src/com/android/contacts/model/Cp2DeviceLocalAccountLocatorTests.java b/tests/src/com/android/contacts/model/Cp2DeviceLocalAccountLocatorTests.java
deleted file mode 100644
index 7dbf933..0000000
--- a/tests/src/com/android/contacts/model/Cp2DeviceLocalAccountLocatorTests.java
+++ /dev/null
@@ -1,218 +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.
- */
-package com.android.contacts.model;
-
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.net.Uri;
-import android.os.CancellationSignal;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.RawContacts;
-import androidx.annotation.Nullable;
-import android.test.AndroidTestCase;
-import android.test.mock.MockContentResolver;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.contacts.test.mocks.MockContentProvider;
-import com.android.contacts.tests.FakeDeviceAccountTypeFactory;
-import com.android.contacts.util.DeviceLocalAccountTypeFactory;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-
-@SmallTest
-public class Cp2DeviceLocalAccountLocatorTests extends AndroidTestCase {
-
-    // Basic smoke test that just checks that it doesn't throw when loading from CP2. We don't
-    // care what CP2 actually contains for this.
-    public void testShouldNotCrash() {
-        final DeviceLocalAccountLocator sut = new Cp2DeviceLocalAccountLocator(
-                getContext().getContentResolver(),
-                new DeviceLocalAccountTypeFactory.Default(getContext()),
-                Collections.<String>emptySet());
-        sut.getDeviceLocalAccounts();
-        // We didn't throw so it passed
-    }
-
-    public void test_getDeviceLocalAccounts_returnsEmptyListWhenQueryReturnsNull() {
-        final DeviceLocalAccountLocator sut = createWithQueryResult(null);
-        assertTrue(sut.getDeviceLocalAccounts().isEmpty());
-    }
-
-    public void test_getDeviceLocalAccounts_returnsEmptyListWhenNoRawContactsHaveDeviceType() {
-        final DeviceLocalAccountLocator sut = createWithQueryResult(queryResult(
-                        "user", "com.example",
-                        "user", "com.example",
-                        "user", "com.example"));
-        assertTrue(sut.getDeviceLocalAccounts().isEmpty());
-    }
-
-    public void test_getDeviceLocalAccounts_returnsListWithItemForNullAccount() {
-        final DeviceLocalAccountLocator sut = createWithQueryResult(queryResult(
-                "user", "com.example",
-                null, null,
-                "user", "com.example",
-                null, null));
-
-        assertEquals(1, sut.getDeviceLocalAccounts().size());
-    }
-
-    public void test_getDeviceLocalAccounts_containsItemForEachDeviceAccount() {
-        final DeviceLocalAccountTypeFactory stubFactory = new FakeDeviceAccountTypeFactory()
-                .withDeviceTypes(null, "vnd.sec.contact.phone")
-                .withSimTypes("vnd.sec.contact.sim");
-        final DeviceLocalAccountLocator sut = createLocator(queryResult(
-                "user", "com.example",
-                "user", "com.example",
-                "phone_account", "vnd.sec.contact.phone",
-                null, null,
-                "phone_account", "vnd.sec.contact.phone",
-                "user", "com.example",
-                null, null,
-                "sim_account", "vnd.sec.contact.sim",
-                "sim_account_2", "vnd.sec.contact.sim"
-        ), stubFactory);
-
-
-        assertEquals(4, sut.getDeviceLocalAccounts().size());
-    }
-
-    public void test_getDeviceLocalAccounts_doesNotContainItemsForKnownAccountTypes() {
-        final Cp2DeviceLocalAccountLocator sut = new Cp2DeviceLocalAccountLocator(
-                getContext().getContentResolver(), new FakeDeviceAccountTypeFactory(),
-                new HashSet<>(Arrays.asList("com.example", "com.example.1")));
-
-        assertTrue("Selection should filter known accounts",
-                sut.getSelection().contains("NOT IN (?,?)"));
-
-        final List<String> args = Arrays.asList(sut.getSelectionArgs());
-        assertEquals(2, args.size());
-        assertTrue("Selection args is missing an expected value", args.contains("com.example"));
-        assertTrue("Selection args is missing an expected value", args.contains("com.example.1"));
-    }
-
-    public void test_getDeviceLocalAccounts_includesAccountsFromSettings() {
-        final DeviceLocalAccountTypeFactory stubFactory = new FakeDeviceAccountTypeFactory()
-                .withDeviceTypes(null, "vnd.sec.contact.phone")
-                .withSimTypes("vnd.sec.contact.sim");
-        final DeviceLocalAccountLocator sut = createLocator(new FakeContactsProvider()
-                .withQueryResult(ContactsContract.Settings.CONTENT_URI, queryResult(
-                        "phone_account", "vnd.sec.contact.phone",
-                        "sim_account", "vnd.sec.contact.sim"
-                )), stubFactory);
-
-        assertEquals(2, sut.getDeviceLocalAccounts().size());
-    }
-
-    public void test_getDeviceLocalAccounts_includesAccountsFromGroups() {
-        final DeviceLocalAccountTypeFactory stubFactory = new FakeDeviceAccountTypeFactory()
-                .withDeviceTypes(null, "vnd.sec.contact.phone")
-                .withSimTypes("vnd.sec.contact.sim");
-        final DeviceLocalAccountLocator sut = createLocator(new FakeContactsProvider()
-                .withQueryResult(ContactsContract.Groups.CONTENT_URI, queryResult(
-                        "phone_account", "vnd.sec.contact.phone",
-                        "sim_account", "vnd.sec.contact.sim"
-                )), stubFactory);
-
-        assertEquals(2, sut.getDeviceLocalAccounts().size());
-    }
-
-    private DeviceLocalAccountLocator createWithQueryResult(
-            Cursor cursor) {
-        return createLocator(cursor, new DeviceLocalAccountTypeFactory.Default(mContext));
-    }
-
-    private DeviceLocalAccountLocator createLocator(ContentProvider contactsProvider,
-            DeviceLocalAccountTypeFactory localAccountTypeFactory) {
-        final DeviceLocalAccountLocator locator = new Cp2DeviceLocalAccountLocator(
-                createContentResolverWithProvider(contactsProvider),
-                localAccountTypeFactory, Collections.<String>emptySet());
-        return locator;
-    }
-
-    private DeviceLocalAccountLocator createLocator(Cursor cursor,
-            DeviceLocalAccountTypeFactory localAccountTypeFactory) {
-        final DeviceLocalAccountLocator locator = new Cp2DeviceLocalAccountLocator(
-                createStubResolverWithContentQueryResult(cursor),
-                localAccountTypeFactory,
-                Collections.<String>emptySet());
-        return locator;
-    }
-
-    private ContentResolver createContentResolverWithProvider(ContentProvider contactsProvider) {
-        final MockContentResolver resolver = new MockContentResolver();
-        resolver.addProvider(ContactsContract.AUTHORITY, contactsProvider);
-        return resolver;
-    }
-
-    private ContentResolver createStubResolverWithContentQueryResult(Cursor cursor) {
-        final MockContentResolver resolver = new MockContentResolver();
-        resolver.addProvider(ContactsContract.AUTHORITY, new FakeContactsProvider()
-                .withDefaultQueryResult(cursor));
-        return resolver;
-    }
-
-    private Cursor queryResult(String... nameTypePairs) {
-        final MatrixCursor cursor = new MatrixCursor(new String[]
-                { RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_TYPE, RawContacts.DATA_SET });
-        for (int i = 0; i < nameTypePairs.length; i+=2) {
-            cursor.newRow().add(nameTypePairs[i]).add(nameTypePairs[i+1])
-                    .add(null);
-        }
-        return cursor;
-    }
-
-    private static class FakeContactsProvider extends MockContentProvider {
-        public Cursor mNextQueryResult;
-        public Map<Uri, Cursor> mNextResultMapping = new HashMap<>();
-
-        public FakeContactsProvider() {}
-
-        public FakeContactsProvider withDefaultQueryResult(Cursor cursor) {
-            mNextQueryResult = cursor;
-            return this;
-        }
-
-        public FakeContactsProvider withQueryResult(Uri uri, Cursor cursor) {
-            mNextResultMapping.put(uri, cursor);
-            return this;
-        }
-
-        @Override
-        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-                String sortOrder) {
-            return query(uri, projection, selection, selectionArgs, sortOrder, null);
-        }
-
-        @Nullable
-        @Override
-        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-                String sortOrder, CancellationSignal cancellationSignal) {
-            final Cursor result = mNextResultMapping.get(uri);
-            if (result == null) {
-                return mNextQueryResult;
-            } else {
-                return result;
-            }
-        }
-    }
-}