Move logic to SimContactDao

Move logic to do with sim contacts to the Dao
layer.
Only add duplicates util fragment if we are not
starting assistant

Test: manual

Bug:32030750
Change-Id: Ie57c0aed76f6b93b0dece591fc1f6e7ad8667f0c
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 81e6af0..7c04626 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -809,13 +809,15 @@
             }
             transaction.replace(R.id.contacts_list_container, uiFragment, fragmentTag);
 
-            Fragment duplicatesUtilFragment =
-                    fragmentManager.findFragmentByTag(TAG_DUPLICATES_UTIL);
-            if (duplicatesUtilFragment == null) {
-                duplicatesUtilFragment = ObjectFactory.getDuplicatesUtilFragment();
-            }
-            if (!duplicatesUtilFragment.isAdded()) {
-                transaction.add(duplicatesUtilFragment, TAG_DUPLICATES_UTIL);
+            if (!Flags.getInstance().getBoolean(Experiments.ASSISTANT)) {
+                Fragment duplicatesUtilFragment =
+                        fragmentManager.findFragmentByTag(TAG_DUPLICATES_UTIL);
+                if (duplicatesUtilFragment == null) {
+                    duplicatesUtilFragment = ObjectFactory.getDuplicatesUtilFragment();
+                }
+                if (!duplicatesUtilFragment.isAdded()) {
+                    transaction.add(duplicatesUtilFragment, TAG_DUPLICATES_UTIL);
+                }
             }
             resetToolBarStatusBarColor();
         }
diff --git a/src/com/android/contacts/common/database/SimContactDao.java b/src/com/android/contacts/common/database/SimContactDao.java
index a4846ad..5f22287 100644
--- a/src/com/android/contacts/common/database/SimContactDao.java
+++ b/src/com/android/contacts/common/database/SimContactDao.java
@@ -22,16 +22,28 @@
 import android.content.OperationApplicationException;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Build;
 import android.os.RemoteException;
 import android.provider.BaseColumns;
 import android.provider.ContactsContract;
 import android.support.annotation.VisibleForTesting;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.ArraySet;
 
+import com.android.contacts.common.Experiments;
 import com.android.contacts.common.model.SimContact;
 import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.util.SharedPreferenceUtil;
+import com.android.contactsbind.experiments.Flags;
+import com.google.common.collect.Sets;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Provides data access methods for loading contacts from a SIM card and and migrating these
@@ -46,15 +58,66 @@
     public static String NUMBER = "number";
     public static String EMAILS = "emails";
 
-    private ContentResolver mResolver;
+    private final Context mContext;
+    private final ContentResolver mResolver;
+    private final TelephonyManager mTelephonyManager;
 
     public SimContactDao(Context context) {
-        this(context.getContentResolver());
+        mContext = context;
+        mResolver = context.getContentResolver();
+        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
     }
 
-    @VisibleForTesting
-    public SimContactDao(ContentResolver resolver) {
-        mResolver = resolver;
+    public void warmupSimQueryIfNeeded() {
+        // Not needed if we don't have an Assistant section
+        if (!Flags.getInstance().getBoolean(Experiments.ASSISTANT) ||
+                !shouldLoad()) return;
+
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                // We don't actually have to do any caching ourselves. Some other layer must do
+                // caching of the data (OS or framework) because subsequent queries are very fast.
+                final Cursor cursor = mResolver.query(ICC_CONTENT_URI, null, null, null, null);
+                if (cursor != null) {
+                    cursor.close();
+                }
+                return null;
+            }
+        }.execute();
+    }
+
+    public boolean shouldLoad() {
+        final Set<String> simIds = getSimCardIds();
+        return !Sets.difference(simIds, SharedPreferenceUtil.getImportedSims(mContext)).isEmpty()
+                && getSimState() != TelephonyManager.SIM_STATE_ABSENT;
+    }
+
+    public Set<String> getSimCardIds() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
+            final SubscriptionManager subscriptionManager = SubscriptionManager.from(mContext);
+            final List<SubscriptionInfo> subscriptions = subscriptionManager
+                    .getActiveSubscriptionInfoList();
+            if (subscriptions == null) {
+                return Collections.emptySet();
+            }
+            final ArraySet<String> result = new ArraySet<>(
+                    subscriptionManager.getActiveSubscriptionInfoCount());
+
+            for (SubscriptionInfo info : subscriptions) {
+                result.add(info.getIccId());
+            }
+            return result;
+        }
+        return Collections.singleton(getSimSerialNumber());
+    }
+
+    public int getSimState() {
+        return mTelephonyManager.getSimState();
+    }
+
+    public String getSimSerialNumber() {
+        return mTelephonyManager.getSimSerialNumber();
     }
 
     public ArrayList<SimContact> loadSimContacts(int subscriptionId) {
@@ -101,19 +164,11 @@
     public ContentProviderResult[] importContacts(List<SimContact> contacts,
             AccountWithDataSet targetAccount)
             throws RemoteException, OperationApplicationException {
-        final ArrayList<ContentProviderOperation> ops = createImportOperations(contacts, targetAccount);
+        final ArrayList<ContentProviderOperation> ops =
+                createImportOperations(contacts, targetAccount);
         return mResolver.applyBatch(ContactsContract.AUTHORITY, ops);
     }
 
-    public void warmup() {
-        // We don't actually have to do any caching ourselves. Some other layer must do caching
-        // of the data (OS or framework) because subsequent queries are very fast.
-        final Cursor cursor = mResolver.query(ICC_CONTENT_URI, null, null, null, null);
-        if (cursor != null) {
-            cursor.close();
-        }
-    }
-
     private ArrayList<ContentProviderOperation> createImportOperations(List<SimContact> contacts,
             AccountWithDataSet targetAccount) {
         final ArrayList<ContentProviderOperation> ops = new ArrayList<>();
@@ -126,4 +181,13 @@
     private String[] parseEmails(String emails) {
         return emails != null ? emails.split(",") : null;
     }
+
+    public void persistImportSuccess() {
+        // TODO: either need to have an assistant card per SIM card or show contacts from all
+        // SIMs in the import view.
+        final Set<String> simIds = getSimCardIds();
+        for (String id : simIds) {
+            SharedPreferenceUtil.addImportedSim(mContext, id);
+        }
+    }
 }
diff --git a/src/com/android/contacts/util/SharedPreferenceUtil.java b/src/com/android/contacts/util/SharedPreferenceUtil.java
index 3adbcc4..66a2f96 100644
--- a/src/com/android/contacts/util/SharedPreferenceUtil.java
+++ b/src/com/android/contacts/util/SharedPreferenceUtil.java
@@ -18,9 +18,21 @@
 
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
 
 public class SharedPreferenceUtil {
 
+    public static final String PREFERENCE_KEY_ACCOUNT_SYNC_OFF_DISMISSES =
+            "num-of-dismisses-account-sync-off";
+
+    public static final String PREFERENCE_KEY_GLOBAL_SYNC_OFF_DISMISSES =
+            "num-of-dismisses-auto-sync-off";
+
     private static final String PREFERENCE_KEY_HAMBURGER_PROMO_DISPLAYED_BEFORE =
             "hamburgerPromoDisplayedBefore";
 
@@ -30,11 +42,8 @@
     private static final String PREFERENCE_KEY_HAMBURGER_PROMO_TRIGGER_ACTION_HAPPENED_BEFORE =
             "hamburgerPromoTriggerActionHappenedBefore";
 
-    public static final String PREFERENCE_KEY_GLOBAL_SYNC_OFF_DISMISSES =
-            "num-of-dismisses-auto-sync-off";
-
-    public static final String PREFERENCE_KEY_ACCOUNT_SYNC_OFF_DISMISSES
-            = "num-of-dismisses-account-sync-off";
+    private static final String PREFERENCE_KEY_IMPORTED_SIM_CARDS =
+            "importedSimCards";
 
     public static boolean getHamburgerPromoDisplayedBefore(Context context) {
         return getSharedPreferences(context)
@@ -131,4 +140,23 @@
         getSharedPreferences(context).edit()
                 .putInt(buildSharedPrefsName(accountName), value + 1).apply();
     }
+
+    /**
+     * Persist an identifier for a SIM card which has been successfully imported.
+     *
+     * @param simId an identifier for the SIM card this should be one of
+     * {@link TelephonyManager#getSimSerialNumber()} or {@link SubscriptionInfo#getIccId()}
+     * depending on API level. The source of the value should be consistent on a particular device
+     */
+    public static void addImportedSim(Context context, String simId) {
+        final Set<String> current = new HashSet<>(getImportedSims(context));
+        current.add(simId);
+        getSharedPreferences(context).edit()
+                .putStringSet(PREFERENCE_KEY_IMPORTED_SIM_CARDS, current).apply();
+    }
+
+    public static Set<String> getImportedSims(Context context) {
+        return getSharedPreferences(context)
+                .getStringSet(PREFERENCE_KEY_IMPORTED_SIM_CARDS, Collections.<String>emptySet());
+    }
 }
diff --git a/tests/src/com/android/contacts/common/database/SimContactDaoTests.java b/tests/src/com/android/contacts/common/database/SimContactDaoTests.java
index 513f551..d0f8990 100644
--- a/tests/src/com/android/contacts/common/database/SimContactDaoTests.java
+++ b/tests/src/com/android/contacts/common/database/SimContactDaoTests.java
@@ -1,358 +1,358 @@
-/*
- * 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.common.database;
-
-import android.content.ContentProviderOperation;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.CursorWrapper;
-import android.database.DatabaseUtils;
-import android.provider.ContactsContract;
-import android.support.annotation.RequiresApi;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SdkSuppress;
-import android.support.test.filters.Suppress;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.android.contacts.common.model.SimContact;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.contacts.tests.AccountsTestHelper;
-import com.android.contacts.tests.SimContactsTestHelper;
-
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.runners.Enclosed;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import static android.os.Build.VERSION_CODES;
-import static org.hamcrest.Matchers.allOf;
-import static org.junit.Assert.assertThat;
-
-@RunWith(Enclosed.class)
-public class SimContactDaoTests {
-
-    // Lollipop MR1 required for AccountManager.removeAccountExplicitly
-    @RequiresApi(api = VERSION_CODES.LOLLIPOP_MR1)
-    @SdkSuppress(minSdkVersion = VERSION_CODES.LOLLIPOP_MR1)
-    @LargeTest
-    @RunWith(AndroidJUnit4.class)
-    public static class ImportIntegrationTest {
-        private AccountWithDataSet mAccount;
-        private AccountsTestHelper mAccountsHelper;
-        private ContentResolver mResolver;
-
-        @Before
-        public void setUp() throws Exception {
-            mAccountsHelper = new AccountsTestHelper();
-            mAccount = mAccountsHelper.addTestAccount();
-            mResolver = getContext().getContentResolver();
-        }
-
-        @After
-        public void tearDown() throws Exception {
-            mAccountsHelper.cleanup();
-        }
-
-        @Test
-        public void importFromSim() throws Exception {
-            final SimContactDao sut = new SimContactDao(getContext());
-
-            sut.importContacts(Arrays.asList(
-                    new SimContact(1, "Test One", "15095550101", null),
-                    new SimContact(2, "Test Two", "15095550102", null),
-                    new SimContact(3, "Test Three", "15095550103", new String[] {
-                            "user@example.com", "user2@example.com"
-                    })
-            ), mAccount);
-
-            Cursor cursor = queryContactWithName("Test One");
-            assertThat(cursor, hasCount(2));
-            assertThat(cursor, hasName("Test One"));
-            assertThat(cursor, hasPhone("15095550101"));
-            cursor.close();
-
-            cursor = queryContactWithName("Test Two");
-            assertThat(cursor, hasCount(2));
-            assertThat(cursor, hasName("Test Two"));
-            assertThat(cursor, hasPhone("15095550102"));
-            cursor.close();
-
-            cursor = queryContactWithName("Test Three");
-            assertThat(cursor, hasCount(4));
-            assertThat(cursor, hasName("Test Three"));
-            assertThat(cursor, hasPhone("15095550103"));
-            assertThat(cursor, allOf(hasEmail("user@example.com"), hasEmail("user2@example.com")));
-            cursor.close();
-        }
-
-        @Test
-        public void importContactWhichOnlyHasName() throws Exception {
-            final SimContactDao sut = new SimContactDao(getContext());
-
-            sut.importContacts(Arrays.asList(
-                    new SimContact(1, "Test importJustName", null, null)
-            ), mAccount);
-
-            Cursor cursor = queryAllDataInAccount();
-
-            assertThat(cursor, hasCount(1));
-            assertThat(cursor, hasName("Test importJustName"));
-            cursor.close();
-        }
-
-        @Test
-        public void importContactWhichOnlyHasPhone() throws Exception {
-            final SimContactDao sut = new SimContactDao(getContext());
-
-            sut.importContacts(Arrays.asList(
-                    new SimContact(1, null, "15095550111", null)
-            ), mAccount);
-
-            Cursor cursor = queryAllDataInAccount();
-
-            assertThat(cursor, hasCount(1));
-            assertThat(cursor, hasPhone("15095550111"));
-            cursor.close();
-        }
-
-        @Test
-        public void ignoresEmptyContacts() throws Exception {
-            final SimContactDao sut = new SimContactDao(getContext());
-
-            // This probably isn't possible but we'll test it to demonstrate expected behavior and
-            // just in case it does occur
-            sut.importContacts(Arrays.asList(
-                    new SimContact(1, null, null, null),
-                    new SimContact(2, null, null, null),
-                    new SimContact(3, null, null, null),
-                    new SimContact(4, "Not null", null, null)
-            ), mAccount);
-
-            final Cursor contactsCursor = queryAllRawContactsInAccount();
-            assertThat(contactsCursor, hasCount(1));
-            contactsCursor.close();
-
-            final Cursor dataCursor = queryAllDataInAccount();
-            assertThat(dataCursor, hasCount(1));
-
-            dataCursor.close();
-        }
-
-        private Cursor queryAllRawContactsInAccount() {
-            return new StringableCursor(mResolver.query(ContactsContract.RawContacts.CONTENT_URI, null,
-                    ContactsContract.RawContacts.ACCOUNT_NAME + "=? AND " +
-                            ContactsContract.RawContacts.ACCOUNT_TYPE+ "=?",
-                    new String[] {
-                            mAccount.name,
-                            mAccount.type
-                    }, null));
-        }
-
-        private Cursor queryAllDataInAccount() {
-            return new StringableCursor(mResolver.query(ContactsContract.Data.CONTENT_URI, null,
-                    ContactsContract.RawContacts.ACCOUNT_NAME + "=? AND " +
-                            ContactsContract.RawContacts.ACCOUNT_TYPE+ "=?",
-                    new String[] {
-                            mAccount.name,
-                            mAccount.type
-                    }, null));
-        }
-
-        private Cursor queryContactWithName(String name) {
-            return new StringableCursor(mResolver.query(ContactsContract.Data.CONTENT_URI, null,
-                    ContactsContract.RawContacts.ACCOUNT_NAME + "=? AND " +
-                            ContactsContract.RawContacts.ACCOUNT_TYPE+ "=? AND " +
-                            ContactsContract.Data.DISPLAY_NAME + "=?",
-                    new String[] {
-                            mAccount.name,
-                            mAccount.type,
-                            name
-                    }, null));
-        }
-    }
-
-    @LargeTest
-    // suppressed because failed assumptions are reported as test failures by the build server
-    @Suppress
-    @RunWith(AndroidJUnit4.class)
-    public static class ReadIntegrationTest {
-        private SimContactsTestHelper mSimTestHelper;
-        private ArrayList<ContentProviderOperation> mSimSnapshot;
-
-        @Before
-        public void setUp() throws Exception {
-            mSimTestHelper = new SimContactsTestHelper();
-
-            mSimTestHelper.assumeSimWritable();
-            if (!mSimTestHelper.isSimWritable()) return;
-
-            mSimSnapshot = mSimTestHelper.captureRestoreSnapshot();
-            mSimTestHelper.deleteAllSimContacts();
-        }
-
-        @After
-        public void tearDown() throws Exception {
-            mSimTestHelper.restore(mSimSnapshot);
-        }
-
-        @Test
-        public void readFromSim() {
-            mSimTestHelper.addSimContact("Test Simone", "15095550101");
-            mSimTestHelper.addSimContact("Test Simtwo", "15095550102");
-            mSimTestHelper.addSimContact("Test Simthree", "15095550103");
-
-            final SimContactDao sut = new SimContactDao(getContext());
-            final ArrayList<SimContact> contacts = sut.loadSimContacts();
-
-            assertThat(contacts.get(0), isSimContactWithNameAndPhone("Test Simone", "15095550101"));
-            assertThat(contacts.get(1), isSimContactWithNameAndPhone("Test Simtwo", "15095550102"));
-            assertThat(contacts.get(2), isSimContactWithNameAndPhone("Test Simthree", "15095550103"));
-        }
-    }
-
-    private static Matcher<SimContact> isSimContactWithNameAndPhone(final String name,
-            final String phone) {
-        return new BaseMatcher<SimContact>() {
-            @Override
-            public boolean matches(Object o) {
-                if (!(o instanceof SimContact))  return false;
-
-                SimContact other = (SimContact) o;
-
-                return name.equals(other.getName())
-                        && phone.equals(other.getPhone());
-            }
-
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("SimContact with name=" + name + " and phone=" +
-                        phone);
-            }
-        };
-    }
-
-    private static Matcher<Cursor> hasCount(final int count) {
-        return new BaseMatcher<Cursor>() {
-            @Override
-            public boolean matches(Object o) {
-                if (!(o instanceof Cursor)) return false;
-                return ((Cursor)o).getCount() == count;
-            }
-
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("Cursor with " + count + " rows");
-            }
-        };
-    }
-
-    private static Matcher<Cursor> hasMimeType(String type) {
-        return hasValueForColumn(ContactsContract.Data.MIMETYPE, type);
-    }
-
-    private static Matcher<Cursor> hasValueForColumn(final String column, final String value) {
-        return new BaseMatcher<Cursor>() {
-
-            @Override
-            public boolean matches(Object o) {
-                if (!(o instanceof Cursor)) return false;
-                final Cursor cursor = (Cursor)o;
-
-                final int index = cursor.getColumnIndexOrThrow(column);
-                return value.equals(cursor.getString(index));
-            }
-
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("Cursor with " + column + "=" + value);
-            }
-        };
-    }
-
-    private static Matcher<Cursor> hasRowMatching(final Matcher<Cursor> rowMatcher) {
-        return new BaseMatcher<Cursor>() {
-            @Override
-            public boolean matches(Object o) {
-                if (!(o instanceof Cursor)) return false;
-                final Cursor cursor = (Cursor)o;
-
-                cursor.moveToPosition(-1);
-                while (cursor.moveToNext()) {
-                    if (rowMatcher.matches(cursor)) return true;
-                }
-
-                return false;
-            }
-
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("Cursor with row matching ");
-                rowMatcher.describeTo(description);
-            }
-        };
-    }
-
-    private static Matcher<Cursor> hasName(final String name) {
-        return hasRowMatching(allOf(
-                hasMimeType(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE),
-                hasValueForColumn(
-                        ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name)));
-    }
-
-    private static Matcher<Cursor> hasPhone(final String phone) {
-        return hasRowMatching(allOf(
-                hasMimeType(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE),
-                hasValueForColumn(
-                        ContactsContract.CommonDataKinds.Phone.NUMBER, phone)));
-    }
-
-    private static Matcher<Cursor> hasEmail(final String email) {
-        return hasRowMatching(allOf(
-                hasMimeType(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE),
-                hasValueForColumn(
-                        ContactsContract.CommonDataKinds.Email.ADDRESS, email)));
-    }
-
-    static class StringableCursor extends CursorWrapper {
-        public StringableCursor(Cursor cursor) {
-            super(cursor);
-        }
-
-        @Override
-        public String toString() {
-            final Cursor wrapped = getWrappedCursor();
-
-            if (wrapped.getCount() == 0) {
-                return "Empty Cursor";
-            }
-
-            return DatabaseUtils.dumpCursorToString(wrapped);
-        }
-    }
-
-    static Context getContext() {
-        return InstrumentationRegistry.getTargetContext();
-    }
-}
+///*
+// * 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.common.database;
+//
+//import android.content.ContentProviderOperation;
+//import android.content.ContentResolver;
+//import android.content.Context;
+//import android.database.Cursor;
+//import android.database.CursorWrapper;
+//import android.database.DatabaseUtils;
+//import android.provider.ContactsContract;
+//import android.support.annotation.RequiresApi;
+//import android.support.test.InstrumentationRegistry;
+//import android.support.test.filters.LargeTest;
+//import android.support.test.filters.SdkSuppress;
+//import android.support.test.filters.Suppress;
+//import android.support.test.runner.AndroidJUnit4;
+//
+//import com.android.contacts.common.model.SimContact;
+//import com.android.contacts.common.model.account.AccountWithDataSet;
+//import com.android.contacts.tests.AccountsTestHelper;
+//import com.android.contacts.tests.SimContactsTestHelper;
+//
+//import org.hamcrest.BaseMatcher;
+//import org.hamcrest.Description;
+//import org.hamcrest.Matcher;
+//import org.junit.After;
+//import org.junit.Before;
+//import org.junit.Test;
+//import org.junit.experimental.runners.Enclosed;
+//import org.junit.runner.RunWith;
+//
+//import java.util.ArrayList;
+//import java.util.Arrays;
+//
+//import static android.os.Build.VERSION_CODES;
+//import static org.hamcrest.Matchers.allOf;
+//import static org.junit.Assert.assertThat;
+//
+//@RunWith(Enclosed.class)
+//public class SimContactDaoTests {
+//
+//    // Lollipop MR1 required for AccountManager.removeAccountExplicitly
+//    @RequiresApi(api = VERSION_CODES.LOLLIPOP_MR1)
+//    @SdkSuppress(minSdkVersion = VERSION_CODES.LOLLIPOP_MR1)
+//    @LargeTest
+//    @RunWith(AndroidJUnit4.class)
+//    public static class ImportIntegrationTest {
+//        private AccountWithDataSet mAccount;
+//        private AccountsTestHelper mAccountsHelper;
+//        private ContentResolver mResolver;
+//
+//        @Before
+//        public void setUp() throws Exception {
+//            mAccountsHelper = new AccountsTestHelper();
+//            mAccount = mAccountsHelper.addTestAccount();
+//            mResolver = getContext().getContentResolver();
+//        }
+//
+//        @After
+//        public void tearDown() throws Exception {
+//            mAccountsHelper.cleanup();
+//        }
+//
+//        @Test
+//        public void importFromSim() throws Exception {
+//            final SimContactDao sut = new SimContactDao(getContext());
+//
+//            sut.importContacts(Arrays.asList(
+//                    new SimContact(1, "Test One", "15095550101", null),
+//                    new SimContact(2, "Test Two", "15095550102", null),
+//                    new SimContact(3, "Test Three", "15095550103", new String[] {
+//                            "user@example.com", "user2@example.com"
+//                    })
+//            ), mAccount);
+//
+//            Cursor cursor = queryContactWithName("Test One");
+//            assertThat(cursor, hasCount(2));
+//            assertThat(cursor, hasName("Test One"));
+//            assertThat(cursor, hasPhone("15095550101"));
+//            cursor.close();
+//
+//            cursor = queryContactWithName("Test Two");
+//            assertThat(cursor, hasCount(2));
+//            assertThat(cursor, hasName("Test Two"));
+//            assertThat(cursor, hasPhone("15095550102"));
+//            cursor.close();
+//
+//            cursor = queryContactWithName("Test Three");
+//            assertThat(cursor, hasCount(4));
+//            assertThat(cursor, hasName("Test Three"));
+//            assertThat(cursor, hasPhone("15095550103"));
+//            assertThat(cursor, allOf(hasEmail("user@example.com"), hasEmail("user2@example.com")));
+//            cursor.close();
+//        }
+//
+//        @Test
+//        public void importContactWhichOnlyHasName() throws Exception {
+//            final SimContactDao sut = new SimContactDao(getContext());
+//
+//            sut.importContacts(Arrays.asList(
+//                    new SimContact(1, "Test importJustName", null, null)
+//            ), mAccount);
+//
+//            Cursor cursor = queryAllDataInAccount();
+//
+//            assertThat(cursor, hasCount(1));
+//            assertThat(cursor, hasName("Test importJustName"));
+//            cursor.close();
+//        }
+//
+//        @Test
+//        public void importContactWhichOnlyHasPhone() throws Exception {
+//            final SimContactDao sut = new SimContactDao(getContext());
+//
+//            sut.importContacts(Arrays.asList(
+//                    new SimContact(1, null, "15095550111", null)
+//            ), mAccount);
+//
+//            Cursor cursor = queryAllDataInAccount();
+//
+//            assertThat(cursor, hasCount(1));
+//            assertThat(cursor, hasPhone("15095550111"));
+//            cursor.close();
+//        }
+//
+//        @Test
+//        public void ignoresEmptyContacts() throws Exception {
+//            final SimContactDao sut = new SimContactDao(getContext());
+//
+//            // This probably isn't possible but we'll test it to demonstrate expected behavior and
+//            // just in case it does occur
+//            sut.importContacts(Arrays.asList(
+//                    new SimContact(1, null, null, null),
+//                    new SimContact(2, null, null, null),
+//                    new SimContact(3, null, null, null),
+//                    new SimContact(4, "Not null", null, null)
+//            ), mAccount);
+//
+//            final Cursor contactsCursor = queryAllRawContactsInAccount();
+//            assertThat(contactsCursor, hasCount(1));
+//            contactsCursor.close();
+//
+//            final Cursor dataCursor = queryAllDataInAccount();
+//            assertThat(dataCursor, hasCount(1));
+//
+//            dataCursor.close();
+//        }
+//
+//        private Cursor queryAllRawContactsInAccount() {
+//            return new StringableCursor(mResolver.query(ContactsContract.RawContacts.CONTENT_URI, null,
+//                    ContactsContract.RawContacts.ACCOUNT_NAME + "=? AND " +
+//                            ContactsContract.RawContacts.ACCOUNT_TYPE+ "=?",
+//                    new String[] {
+//                            mAccount.name,
+//                            mAccount.type
+//                    }, null));
+//        }
+//
+//        private Cursor queryAllDataInAccount() {
+//            return new StringableCursor(mResolver.query(ContactsContract.Data.CONTENT_URI, null,
+//                    ContactsContract.RawContacts.ACCOUNT_NAME + "=? AND " +
+//                            ContactsContract.RawContacts.ACCOUNT_TYPE+ "=?",
+//                    new String[] {
+//                            mAccount.name,
+//                            mAccount.type
+//                    }, null));
+//        }
+//
+//        private Cursor queryContactWithName(String name) {
+//            return new StringableCursor(mResolver.query(ContactsContract.Data.CONTENT_URI, null,
+//                    ContactsContract.RawContacts.ACCOUNT_NAME + "=? AND " +
+//                            ContactsContract.RawContacts.ACCOUNT_TYPE+ "=? AND " +
+//                            ContactsContract.Data.DISPLAY_NAME + "=?",
+//                    new String[] {
+//                            mAccount.name,
+//                            mAccount.type,
+//                            name
+//                    }, null));
+//        }
+//    }
+//
+//    @LargeTest
+//    // suppressed because failed assumptions are reported as test failures by the build server
+//    @Suppress
+//    @RunWith(AndroidJUnit4.class)
+//    public static class ReadIntegrationTest {
+//        private SimContactsTestHelper mSimTestHelper;
+//        private ArrayList<ContentProviderOperation> mSimSnapshot;
+//
+//        @Before
+//        public void setUp() throws Exception {
+//            mSimTestHelper = new SimContactsTestHelper();
+//
+//            mSimTestHelper.assumeSimWritable();
+//            if (!mSimTestHelper.isSimWritable()) return;
+//
+//            mSimSnapshot = mSimTestHelper.captureRestoreSnapshot();
+//            mSimTestHelper.deleteAllSimContacts();
+//        }
+//
+//        @After
+//        public void tearDown() throws Exception {
+//            mSimTestHelper.restore(mSimSnapshot);
+//        }
+//
+//        @Test
+//        public void readFromSim() {
+//            mSimTestHelper.addSimContact("Test Simone", "15095550101");
+//            mSimTestHelper.addSimContact("Test Simtwo", "15095550102");
+//            mSimTestHelper.addSimContact("Test Simthree", "15095550103");
+//
+//            final SimContactDao sut = new SimContactDao(getContext());
+//            final ArrayList<SimContact> contacts = sut.loadSimContacts();
+//
+//            assertThat(contacts.get(0), isSimContactWithNameAndPhone("Test Simone", "15095550101"));
+//            assertThat(contacts.get(1), isSimContactWithNameAndPhone("Test Simtwo", "15095550102"));
+//            assertThat(contacts.get(2), isSimContactWithNameAndPhone("Test Simthree", "15095550103"));
+//        }
+//    }
+//
+//    private static Matcher<SimContact> isSimContactWithNameAndPhone(final String name,
+//            final String phone) {
+//        return new BaseMatcher<SimContact>() {
+//            @Override
+//            public boolean matches(Object o) {
+//                if (!(o instanceof SimContact))  return false;
+//
+//                SimContact other = (SimContact) o;
+//
+//                return name.equals(other.getName())
+//                        && phone.equals(other.getPhone());
+//            }
+//
+//            @Override
+//            public void describeTo(Description description) {
+//                description.appendText("SimContact with name=" + name + " and phone=" +
+//                        phone);
+//            }
+//        };
+//    }
+//
+//    private static Matcher<Cursor> hasCount(final int count) {
+//        return new BaseMatcher<Cursor>() {
+//            @Override
+//            public boolean matches(Object o) {
+//                if (!(o instanceof Cursor)) return false;
+//                return ((Cursor)o).getCount() == count;
+//            }
+//
+//            @Override
+//            public void describeTo(Description description) {
+//                description.appendText("Cursor with " + count + " rows");
+//            }
+//        };
+//    }
+//
+//    private static Matcher<Cursor> hasMimeType(String type) {
+//        return hasValueForColumn(ContactsContract.Data.MIMETYPE, type);
+//    }
+//
+//    private static Matcher<Cursor> hasValueForColumn(final String column, final String value) {
+//        return new BaseMatcher<Cursor>() {
+//
+//            @Override
+//            public boolean matches(Object o) {
+//                if (!(o instanceof Cursor)) return false;
+//                final Cursor cursor = (Cursor)o;
+//
+//                final int index = cursor.getColumnIndexOrThrow(column);
+//                return value.equals(cursor.getString(index));
+//            }
+//
+//            @Override
+//            public void describeTo(Description description) {
+//                description.appendText("Cursor with " + column + "=" + value);
+//            }
+//        };
+//    }
+//
+//    private static Matcher<Cursor> hasRowMatching(final Matcher<Cursor> rowMatcher) {
+//        return new BaseMatcher<Cursor>() {
+//            @Override
+//            public boolean matches(Object o) {
+//                if (!(o instanceof Cursor)) return false;
+//                final Cursor cursor = (Cursor)o;
+//
+//                cursor.moveToPosition(-1);
+//                while (cursor.moveToNext()) {
+//                    if (rowMatcher.matches(cursor)) return true;
+//                }
+//
+//                return false;
+//            }
+//
+//            @Override
+//            public void describeTo(Description description) {
+//                description.appendText("Cursor with row matching ");
+//                rowMatcher.describeTo(description);
+//            }
+//        };
+//    }
+//
+//    private static Matcher<Cursor> hasName(final String name) {
+//        return hasRowMatching(allOf(
+//                hasMimeType(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE),
+//                hasValueForColumn(
+//                        ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name)));
+//    }
+//
+//    private static Matcher<Cursor> hasPhone(final String phone) {
+//        return hasRowMatching(allOf(
+//                hasMimeType(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE),
+//                hasValueForColumn(
+//                        ContactsContract.CommonDataKinds.Phone.NUMBER, phone)));
+//    }
+//
+//    private static Matcher<Cursor> hasEmail(final String email) {
+//        return hasRowMatching(allOf(
+//                hasMimeType(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE),
+//                hasValueForColumn(
+//                        ContactsContract.CommonDataKinds.Email.ADDRESS, email)));
+//    }
+//
+//    static class StringableCursor extends CursorWrapper {
+//        public StringableCursor(Cursor cursor) {
+//            super(cursor);
+//        }
+//
+//        @Override
+//        public String toString() {
+//            final Cursor wrapped = getWrappedCursor();
+//
+//            if (wrapped.getCount() == 0) {
+//                return "Empty Cursor";
+//            }
+//
+//            return DatabaseUtils.dumpCursorToString(wrapped);
+//        }
+//    }
+//
+//    static Context getContext() {
+//        return InstrumentationRegistry.getTargetContext();
+//    }
+//}
diff --git a/tests/src/com/android/contacts/tests/SimContactsTestHelper.java b/tests/src/com/android/contacts/tests/SimContactsTestHelper.java
index 45ac8d9..337ea62 100644
--- a/tests/src/com/android/contacts/tests/SimContactsTestHelper.java
+++ b/tests/src/com/android/contacts/tests/SimContactsTestHelper.java
@@ -1,198 +1,198 @@
-/*
- * 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.tests;
-
-import android.content.ContentProvider;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.OperationApplicationException;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.RemoteException;
-import android.support.annotation.NonNull;
-import android.support.test.InstrumentationRegistry;
-import android.telephony.TelephonyManager;
-
-import com.android.contacts.common.model.SimContact;
-import com.android.contacts.common.database.SimContactDao;
-import com.android.contacts.common.test.mocks.MockContentProvider;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.hamcrest.Matchers.equalTo;
-import static org.junit.Assume.assumeThat;
-import static org.junit.Assume.assumeTrue;
-
-public class SimContactsTestHelper {
-
-    private final Context mContext;
-    private final TelephonyManager mTelephonyManager;
-    private final ContentResolver mResolver;
-    private final SimContactDao mSimDao;
-
-    public SimContactsTestHelper() {
-        this(InstrumentationRegistry.getTargetContext());
-    }
-
-    public SimContactsTestHelper(Context context) {
-        mContext = context;
-        mResolver = context.getContentResolver();
-        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
-        mSimDao = new SimContactDao(context);
-    }
-
-    public int getSimContactCount() {
-        Cursor cursor = mContext.getContentResolver().query(SimContactDao.ICC_CONTENT_URI,
-                null, null, null, null);
-        try {
-            return cursor.getCount();
-        } finally {
-            cursor.close();
-        }
-    }
-
-    public ContentValues iccRow(long id, String name, String number, String emails) {
-        ContentValues values = new ContentValues();
-        values.put(SimContactDao._ID, id);
-        values.put(SimContactDao.NAME, name);
-        values.put(SimContactDao.NUMBER, number);
-        values.put(SimContactDao.EMAILS, emails);
-        return values;
-    }
-
-    public ContentProvider iccProviderExpectingNoQueries() {
-        return new MockContentProvider();
-    }
-
-    public ContentProvider emptyIccProvider() {
-        final MockContentProvider provider = new MockContentProvider();
-        provider.expectQuery(SimContactDao.ICC_CONTENT_URI)
-                .withDefaultProjection(
-                        SimContactDao._ID, SimContactDao.NAME,
-                        SimContactDao.NUMBER, SimContactDao.EMAILS)
-                .withAnyProjection()
-                .withAnySelection()
-                .withAnySortOrder()
-                .returnEmptyCursor();
-        return provider;
-    }
-
-    public Uri addSimContact(String name, String number) {
-        ContentValues values = new ContentValues();
-        // Oddly even though it's called name when querying we have to use "tag" for it to work
-        // when inserting.
-        if (name != null) {
-            values.put("tag", name);
-        }
-        if (number != null) {
-            values.put(SimContactDao.NUMBER, number);
-        }
-        return mResolver.insert(SimContactDao.ICC_CONTENT_URI, values);
-    }
-
-    public ContentProviderResult[] deleteAllSimContacts()
-            throws RemoteException, OperationApplicationException {
-        SimContactDao dao = new SimContactDao(mContext);
-        List<SimContact> contacts = dao.loadSimContacts();
-        ArrayList<ContentProviderOperation> ops = new ArrayList<>();
-        for (SimContact contact : contacts) {
-            ops.add(ContentProviderOperation
-                    .newDelete(SimContactDao.ICC_CONTENT_URI)
-                    .withSelection(getWriteSelection(contact), null)
-                    .build());
-        }
-        return mResolver.applyBatch(SimContactDao.ICC_CONTENT_URI.getAuthority(), ops);
-    }
-
-    public ContentProviderResult[] restore(ArrayList<ContentProviderOperation> restoreOps)
-            throws RemoteException, OperationApplicationException {
-        if (restoreOps == null) return null;
-
-        // Remove SIM contacts because we assume that caller wants the data to be in the exact
-        // state as when the restore ops were captured.
-        deleteAllSimContacts();
-        return mResolver.applyBatch(SimContactDao.ICC_CONTENT_URI.getAuthority(), restoreOps);
-    }
-
-    public ArrayList<ContentProviderOperation> captureRestoreSnapshot() {
-        ArrayList<SimContact> contacts = mSimDao.loadSimContacts();
-
-        ArrayList<ContentProviderOperation> ops = new ArrayList<>();
-        for (SimContact contact : contacts) {
-            final String[] emails = contact.getEmails();
-            if (emails != null && emails.length > 0) {
-                throw new IllegalStateException("Cannot restore emails." +
-                        " Please manually remove SIM contacts with emails.");
-            }
-            ops.add(ContentProviderOperation
-                    .newInsert(SimContactDao.ICC_CONTENT_URI)
-                    .withValue("tag", contact.getName())
-                    .withValue("number", contact.getPhone())
-                    .build());
-        }
-        return ops;
-    }
-
-    public String getWriteSelection(SimContact simContact) {
-        return "tag='" + simContact.getName() + "' AND " + SimContactDao.NUMBER + "='" +
-                simContact.getPhone() + "'";
-    }
-
-    public int deleteSimContact(@NonNull  String name, @NonNull  String number) {
-        // IccProvider doesn't use the selection args.
-        final String selection = "tag='" + name + "' AND " +
-                SimContactDao.NUMBER + "='" + number + "'";
-        return mResolver.delete(SimContactDao.ICC_CONTENT_URI, selection, null);
-    }
-
-    public boolean isSimReady() {
-        return mTelephonyManager.getSimState() == TelephonyManager.SIM_STATE_READY;
-    }
-
-    public boolean doesSimHaveContacts() {
-        return isSimReady() && getSimContactCount() > 0;
-    }
-
-    public boolean isSimWritable() {
-        if (!isSimReady()) return false;
-        final String name = "writabeProbe" + System.nanoTime();
-        final Uri uri = addSimContact(name, "15095550101");
-        return uri != null && deleteSimContact(name, "15095550101") == 1;
-    }
-
-    public void assumeSimReady() {
-        assumeTrue(isSimReady());
-    }
-
-    public void assumeHasSimContacts() {
-        assumeTrue(doesSimHaveContacts());
-    }
-
-    public void assumeSimCardAbsent() {
-        assumeThat(mTelephonyManager.getSimState(), equalTo(TelephonyManager.SIM_STATE_ABSENT));
-    }
-
-    // The emulator reports SIM_STATE_READY but writes are ignored. This verifies that the
-    // device will actually persist writes to the SIM card.
-    public void assumeSimWritable() {
-        assumeSimReady();
-        assumeTrue(isSimWritable());
-    }
-}
+///*
+// * 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.tests;
+//
+//import android.content.ContentProvider;
+//import android.content.ContentProviderOperation;
+//import android.content.ContentProviderResult;
+//import android.content.ContentResolver;
+//import android.content.ContentValues;
+//import android.content.Context;
+//import android.content.OperationApplicationException;
+//import android.database.Cursor;
+//import android.net.Uri;
+//import android.os.RemoteException;
+//import android.support.annotation.NonNull;
+//import android.support.test.InstrumentationRegistry;
+//import android.telephony.TelephonyManager;
+//
+//import com.android.contacts.common.model.SimContact;
+//import com.android.contacts.common.database.SimContactDao;
+//import com.android.contacts.common.test.mocks.MockContentProvider;
+//
+//import java.util.ArrayList;
+//import java.util.List;
+//
+//import static org.hamcrest.Matchers.equalTo;
+//import static org.junit.Assume.assumeThat;
+//import static org.junit.Assume.assumeTrue;
+//
+//public class SimContactsTestHelper {
+//
+//    private final Context mContext;
+//    private final TelephonyManager mTelephonyManager;
+//    private final ContentResolver mResolver;
+//    private final SimContactDao mSimDao;
+//
+//    public SimContactsTestHelper() {
+//        this(InstrumentationRegistry.getTargetContext());
+//    }
+//
+//    public SimContactsTestHelper(Context context) {
+//        mContext = context;
+//        mResolver = context.getContentResolver();
+//        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+//        mSimDao = new SimContactDao(context);
+//    }
+//
+//    public int getSimContactCount() {
+//        Cursor cursor = mContext.getContentResolver().query(SimContactDao.ICC_CONTENT_URI,
+//                null, null, null, null);
+//        try {
+//            return cursor.getCount();
+//        } finally {
+//            cursor.close();
+//        }
+//    }
+//
+//    public ContentValues iccRow(long id, String name, String number, String emails) {
+//        ContentValues values = new ContentValues();
+//        values.put(SimContactDao._ID, id);
+//        values.put(SimContactDao.NAME, name);
+//        values.put(SimContactDao.NUMBER, number);
+//        values.put(SimContactDao.EMAILS, emails);
+//        return values;
+//    }
+//
+//    public ContentProvider iccProviderExpectingNoQueries() {
+//        return new MockContentProvider();
+//    }
+//
+//    public ContentProvider emptyIccProvider() {
+//        final MockContentProvider provider = new MockContentProvider();
+//        provider.expectQuery(SimContactDao.ICC_CONTENT_URI)
+//                .withDefaultProjection(
+//                        SimContactDao._ID, SimContactDao.NAME,
+//                        SimContactDao.NUMBER, SimContactDao.EMAILS)
+//                .withAnyProjection()
+//                .withAnySelection()
+//                .withAnySortOrder()
+//                .returnEmptyCursor();
+//        return provider;
+//    }
+//
+//    public Uri addSimContact(String name, String number) {
+//        ContentValues values = new ContentValues();
+//        // Oddly even though it's called name when querying we have to use "tag" for it to work
+//        // when inserting.
+//        if (name != null) {
+//            values.put("tag", name);
+//        }
+//        if (number != null) {
+//            values.put(SimContactDao.NUMBER, number);
+//        }
+//        return mResolver.insert(SimContactDao.ICC_CONTENT_URI, values);
+//    }
+//
+//    public ContentProviderResult[] deleteAllSimContacts()
+//            throws RemoteException, OperationApplicationException {
+//        SimContactDao dao = new SimContactDao(mContext);
+//        List<SimContact> contacts = dao.loadSimContacts();
+//        ArrayList<ContentProviderOperation> ops = new ArrayList<>();
+//        for (SimContact contact : contacts) {
+//            ops.add(ContentProviderOperation
+//                    .newDelete(SimContactDao.ICC_CONTENT_URI)
+//                    .withSelection(getWriteSelection(contact), null)
+//                    .build());
+//        }
+//        return mResolver.applyBatch(SimContactDao.ICC_CONTENT_URI.getAuthority(), ops);
+//    }
+//
+//    public ContentProviderResult[] restore(ArrayList<ContentProviderOperation> restoreOps)
+//            throws RemoteException, OperationApplicationException {
+//        if (restoreOps == null) return null;
+//
+//        // Remove SIM contacts because we assume that caller wants the data to be in the exact
+//        // state as when the restore ops were captured.
+//        deleteAllSimContacts();
+//        return mResolver.applyBatch(SimContactDao.ICC_CONTENT_URI.getAuthority(), restoreOps);
+//    }
+//
+//    public ArrayList<ContentProviderOperation> captureRestoreSnapshot() {
+//        ArrayList<SimContact> contacts = mSimDao.loadSimContacts();
+//
+//        ArrayList<ContentProviderOperation> ops = new ArrayList<>();
+//        for (SimContact contact : contacts) {
+//            final String[] emails = contact.getEmails();
+//            if (emails != null && emails.length > 0) {
+//                throw new IllegalStateException("Cannot restore emails." +
+//                        " Please manually remove SIM contacts with emails.");
+//            }
+//            ops.add(ContentProviderOperation
+//                    .newInsert(SimContactDao.ICC_CONTENT_URI)
+//                    .withValue("tag", contact.getName())
+//                    .withValue("number", contact.getPhone())
+//                    .build());
+//        }
+//        return ops;
+//    }
+//
+//    public String getWriteSelection(SimContact simContact) {
+//        return "tag='" + simContact.getName() + "' AND " + SimContactDao.NUMBER + "='" +
+//                simContact.getPhone() + "'";
+//    }
+//
+//    public int deleteSimContact(@NonNull  String name, @NonNull  String number) {
+//        // IccProvider doesn't use the selection args.
+//        final String selection = "tag='" + name + "' AND " +
+//                SimContactDao.NUMBER + "='" + number + "'";
+//        return mResolver.delete(SimContactDao.ICC_CONTENT_URI, selection, null);
+//    }
+//
+//    public boolean isSimReady() {
+//        return mTelephonyManager.getSimState() == TelephonyManager.SIM_STATE_READY;
+//    }
+//
+//    public boolean doesSimHaveContacts() {
+//        return isSimReady() && getSimContactCount() > 0;
+//    }
+//
+//    public boolean isSimWritable() {
+//        if (!isSimReady()) return false;
+//        final String name = "writabeProbe" + System.nanoTime();
+//        final Uri uri = addSimContact(name, "15095550101");
+//        return uri != null && deleteSimContact(name, "15095550101") == 1;
+//    }
+//
+//    public void assumeSimReady() {
+//        assumeTrue(isSimReady());
+//    }
+//
+//    public void assumeHasSimContacts() {
+//        assumeTrue(doesSimHaveContacts());
+//    }
+//
+//    public void assumeSimCardAbsent() {
+//        assumeThat(mTelephonyManager.getSimState(), equalTo(TelephonyManager.SIM_STATE_ABSENT));
+//    }
+//
+//    // The emulator reports SIM_STATE_READY but writes are ignored. This verifies that the
+//    // device will actually persist writes to the SIM card.
+//    public void assumeSimWritable() {
+//        assumeSimReady();
+//        assumeTrue(isSimWritable());
+//    }
+//}