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());
+// }
+//}