Fixing ContactBrowserActivityTest

Change-Id: Ie492eae15c7163d0f8a3577e73ae14b786709a35
diff --git a/src/com/android/contacts/ContactsActivity.java b/src/com/android/contacts/ContactsActivity.java
index 913bc4c..90a975f 100644
--- a/src/com/android/contacts/ContactsActivity.java
+++ b/src/com/android/contacts/ContactsActivity.java
@@ -16,13 +16,32 @@
 
 package com.android.contacts;
 
+import com.android.contacts.test.InjectedServices;
+
 import android.app.Activity;
+import android.content.ContentResolver;
 
 /**
  * A common superclass for Contacts activities that handles application-wide services.
  */
 public abstract class ContactsActivity extends Activity {
 
+    private ContentResolver mContentResolver;
+
+    @Override
+    public ContentResolver getContentResolver() {
+        if (mContentResolver == null) {
+            InjectedServices services = ContactsApplication.getInjectedServices();
+            if (services != null) {
+                mContentResolver = services.getContentResolver();
+            }
+            if (mContentResolver == null) {
+                mContentResolver = super.getContentResolver();
+            }
+        }
+        return mContentResolver;
+    }
+
     @Override
     public Object getSystemService(String name) {
         Object service = super.getSystemService(name);
diff --git a/src/com/android/contacts/ContactsApplication.java b/src/com/android/contacts/ContactsApplication.java
index 268aa2f..288a3d7 100644
--- a/src/com/android/contacts/ContactsApplication.java
+++ b/src/com/android/contacts/ContactsApplication.java
@@ -37,6 +37,10 @@
         sInjectedServices = services;
     }
 
+    public static InjectedServices getInjectedServices() {
+        return sInjectedServices;
+    }
+
     @Override
     public ContentResolver getContentResolver() {
         if (sInjectedServices != null) {
diff --git a/src/com/android/contacts/activities/ActionBarAdapter.java b/src/com/android/contacts/activities/ActionBarAdapter.java
index f7ab405..8bdf405 100644
--- a/src/com/android/contacts/activities/ActionBarAdapter.java
+++ b/src/com/android/contacts/activities/ActionBarAdapter.java
@@ -24,7 +24,6 @@
 
 import android.app.ActionBar;
 import android.app.ActionBar.LayoutParams;
-import android.app.ActionBar.OnNavigationListener;
 import android.content.Context;
 import android.os.Bundle;
 import android.text.TextUtils;
@@ -78,12 +77,17 @@
             mQueryString = request.getQueryString();
         }
 
-        actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM);
+        if (actionBar != null) {
+            actionBar.setDisplayOptions(
+                    ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM);
+        }
 
         mNavigationBar = LayoutInflater.from(mContext).inflate(R.layout.navigation_bar, null);
         LayoutParams layoutParams = new LayoutParams(
                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-        actionBar.setCustomView(mNavigationBar, layoutParams);
+        if (actionBar != null) {
+            actionBar.setCustomView(mNavigationBar, layoutParams);
+        }
 
         mFilterView = (ContactListFilterView) mNavigationBar.findViewById(R.id.filter_view);
         mSearchLabel = (TextView) mNavigationBar.findViewById(R.id.search_label);
diff --git a/tests/src/com/android/contacts/EntityModifierTests.java b/tests/src/com/android/contacts/EntityModifierTests.java
index 35e8e8d..4acaa92 100644
--- a/tests/src/com/android/contacts/EntityModifierTests.java
+++ b/tests/src/com/android/contacts/EntityModifierTests.java
@@ -21,30 +21,30 @@
 import static android.content.ContentProviderOperation.TYPE_UPDATE;
 
 import com.android.contacts.model.AccountType;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityModifier;
-import com.android.contacts.model.EntityDeltaList;
-import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.model.AccountType.DataKind;
 import com.android.contacts.model.AccountType.EditType;
+import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.EntityDeltaList;
+import com.android.contacts.model.EntityModifier;
+import com.android.contacts.tests.mocks.MockAccountTypeManager;
 import com.google.android.collect.Lists;
 
-import android.accounts.Account;
 import android.content.ContentProviderOperation;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Entity;
 import android.os.Bundle;
-import android.provider.ContactsContract.Intents.Insert;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Im;
 import android.provider.ContactsContract.CommonDataKinds.Organization;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Intents.Insert;
+import android.provider.ContactsContract.RawContacts;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 
@@ -71,31 +71,6 @@
     private static final String TEST_ACCOUNT_NAME = "unittest@example.com";
     private static final String TEST_ACCOUNT_TYPE = "com.example.unittest";
 
-    private static class TestAccountTypeManager extends AccountTypeManager {
-
-        private final AccountType[] mTypes;
-
-        public TestAccountTypeManager(AccountType[] types) {
-            this.mTypes = types;
-        }
-
-        @Override
-        public AccountType getAccountType(String accountType) {
-            for (AccountType type : mTypes) {
-                if (accountType.equals(type.accountType)) {
-                    return type;
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public ArrayList<Account> getAccounts(boolean writableOnly) {
-            return null;
-        }
-
-    }
-
     @Override
     public void setUp() {
         mContext = getContext();
@@ -170,7 +145,7 @@
      * Build {@link AccountTypeManager} instance.
      */
     protected AccountTypeManager getAccountTypes(AccountType... types) {
-        return new TestAccountTypeManager(types);
+        return new MockAccountTypeManager(types, null);
     }
 
     /**
diff --git a/tests/src/com/android/contacts/activities/ContactBrowserActivityTest.java b/tests/src/com/android/contacts/activities/ContactBrowserActivityTest.java
index d06f910..a0c768d 100644
--- a/tests/src/com/android/contacts/activities/ContactBrowserActivityTest.java
+++ b/tests/src/com/android/contacts/activities/ContactBrowserActivityTest.java
@@ -16,14 +16,27 @@
 
 package com.android.contacts.activities;
 
+import com.android.contacts.ContactsApplication;
 import com.android.contacts.R;
+import com.android.contacts.model.AccountType;
+import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.FallbackAccountType;
+import com.android.contacts.test.InjectedServices;
 import com.android.contacts.tests.mocks.ContactsMockContext;
+import com.android.contacts.tests.mocks.MockAccountTypeManager;
 import com.android.contacts.tests.mocks.MockContentProvider;
 
+import android.accounts.Account;
 import android.content.Intent;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.ContactCounts;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Directory;
 import android.provider.ContactsContract.Groups;
 import android.provider.ContactsContract.ProviderStatus;
-import android.test.ActivityUnitTestCase;
+import android.provider.Settings;
+import android.test.ActivityInstrumentationTestCase2;
 
 /**
  * Tests for {@link ContactBrowserActivity}.
@@ -36,10 +49,11 @@
  *     -w com.android.contacts.tests/android.test.InstrumentationTestRunner
  */
 public class ContactBrowserActivityTest
-        extends ActivityUnitTestCase<ContactBrowserActivity>
+        extends ActivityInstrumentationTestCase2<ContactBrowserActivity>
 {
     private ContactsMockContext mContext;
     private MockContentProvider mContactsProvider;
+    private MockContentProvider mSettingsProvider;
 
     public ContactBrowserActivityTest() {
         super(ContactBrowserActivity.class);
@@ -49,22 +63,32 @@
     public void setUp() {
         mContext = new ContactsMockContext(getInstrumentation().getTargetContext());
         mContactsProvider = mContext.getContactsProvider();
-        setActivityContext(mContext);
+        mSettingsProvider = mContext.getSettingsProvider();
+        InjectedServices services = new InjectedServices();
+        services.setContentResolver(mContext.getContentResolver());
+
+        FallbackAccountType accountType = new FallbackAccountType();
+        accountType.accountType = "testAccountType";
+
+        Account account = new Account("testAccount", "testAccountType");
+
+        services.setSystemService(AccountTypeManager.ACCOUNT_TYPE_SERVICE,
+                new MockAccountTypeManager(
+                        new AccountType[] { accountType }, new Account[] { account }));
+        ContactsApplication.injectServices(services);
     }
 
     public void testSingleAccountNoGroups() {
-
-        // TODO: actually simulate a single account
-
+        expectSettingsQueriesAndReturnDefault();
         expectProviderStatusQueryAndReturnNormal();
         expectGroupsQueryAndReturnEmpty();
+        expectContactListAndReturnEmpty();
 
-        Intent intent = new Intent(Intent.ACTION_DEFAULT);
+        setActivityIntent(new Intent(Intent.ACTION_DEFAULT));
 
-        ContactBrowserActivity activity = startActivity(intent, null, null);
+        ContactBrowserActivity activity = getActivity();
 
-        getInstrumentation().callActivityOnResume(activity);
-        getInstrumentation().callActivityOnStart(activity);
+        getInstrumentation().waitForIdleSync();
 
         mContext.waitForLoaders(activity.getLoaderManager(), R.id.contact_list_filter_loader);
 
@@ -73,11 +97,29 @@
         mContext.verify();
     }
 
+    private void expectSettingsQueriesAndReturnDefault() {
+        mSettingsProvider
+                .expectQuery(Settings.System.CONTENT_URI)
+                .withProjection(Settings.System.VALUE)
+                .withSelection(Settings.System.NAME + "=?",
+                        ContactsContract.Preferences.DISPLAY_ORDER)
+                .returnRow(ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY)
+                .anyNumberOfTimes();
+        mSettingsProvider
+                .expectQuery(Settings.System.CONTENT_URI)
+                .withProjection(Settings.System.VALUE)
+                .withSelection(Settings.System.NAME + "=?",
+                        ContactsContract.Preferences.SORT_ORDER)
+                .returnRow(ContactsContract.Preferences.SORT_ORDER_PRIMARY)
+                .anyNumberOfTimes();
+    }
+
     private void expectProviderStatusQueryAndReturnNormal() {
         mContactsProvider
                 .expectQuery(ProviderStatus.CONTENT_URI)
                 .withProjection(ProviderStatus.STATUS, ProviderStatus.DATA1)
-                .returnRow(ProviderStatus.STATUS_NORMAL, null);
+                .returnRow(ProviderStatus.STATUS_NORMAL, null)
+                .anyNumberOfTimes();
     }
 
     private void expectGroupsQueryAndReturnEmpty() {
@@ -85,6 +127,22 @@
                 .expectQuery(Groups.CONTENT_URI)
                 .withAnyProjection()
                 .withAnySelection()
+                .returnEmptyCursor()
+                .anyNumberOfTimes();
+    }
+
+    private void expectContactListAndReturnEmpty() {
+        Uri uri = Contacts.CONTENT_URI.buildUpon()
+                .appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true")
+                .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                        String.valueOf(Directory.DEFAULT))
+                .build();
+
+        mContactsProvider
+                .expectQuery(uri)
+                .withAnyProjection()
+                .withAnySelection()
+                .withAnySortOrder()
                 .returnEmptyCursor();
     }
 }
diff --git a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
index f63577b..eba60a9 100644
--- a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
+++ b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
@@ -18,7 +18,9 @@
 
 import com.android.contacts.ContactsApplication;
 import com.android.contacts.R;
+import com.android.contacts.model.AccountType;
 import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.FallbackAccountType;
 import com.android.contacts.test.FragmentTestActivity;
 import com.android.contacts.test.InjectedServices;
 import com.android.contacts.tests.mocks.ContactsMockContext;
@@ -57,6 +59,9 @@
     private static final Uri ENTITY_URI = Uri.withAppendedPath(
             CONTACT_URI, Entity.CONTENT_DIRECTORY);
 
+    public static final String WRITABLE_ACCOUNT_TYPE = "writable";
+    public static final String READONLY_ACCOUNT_TYPE = "readonly";
+
     private ContactsMockContext mContext;
     private MockContentProvider mContactsProvider;
     private ContactDeletionInteraction mFragment;
@@ -71,8 +76,17 @@
         mContext = new ContactsMockContext(getInstrumentation().getTargetContext());
         InjectedServices services = new InjectedServices();
         services.setContentResolver(mContext.getContentResolver());
+
+        FallbackAccountType readOnlyAccountType = new FallbackAccountType();
+        readOnlyAccountType.accountType = READONLY_ACCOUNT_TYPE;
+        readOnlyAccountType.readOnly = true;
+
+        FallbackAccountType writableAccountType = new FallbackAccountType();
+        writableAccountType.accountType = WRITABLE_ACCOUNT_TYPE;
+
         services.setSystemService(AccountTypeManager.ACCOUNT_TYPE_SERVICE,
-                new MockAccountTypeManager());
+                new MockAccountTypeManager(
+                        new AccountType[] { writableAccountType, readOnlyAccountType }, null));
         ContactsApplication.injectServices(services);
         mContactsProvider = mContext.getContactsProvider();
     }
@@ -84,26 +98,26 @@
     }
 
     public void testSingleWritableRawContact() {
-        expectQuery().returnRow(1, MockAccountTypeManager.WRITABLE_ACCOUNT_TYPE, 13, "foo");
+        expectQuery().returnRow(1, WRITABLE_ACCOUNT_TYPE, 13, "foo");
         assertWithMessageId(R.string.deleteConfirmation);
     }
 
     public void testReadOnlyRawContacts() {
-        expectQuery().returnRow(1, MockAccountTypeManager.READONLY_ACCOUNT_TYPE, 13, "foo");
+        expectQuery().returnRow(1, READONLY_ACCOUNT_TYPE, 13, "foo");
         assertWithMessageId(R.string.readOnlyContactWarning);
     }
 
     public void testMixOfWritableAndReadOnlyRawContacts() {
         expectQuery()
-                .returnRow(1, MockAccountTypeManager.WRITABLE_ACCOUNT_TYPE, 13, "foo")
-                .returnRow(2, MockAccountTypeManager.READONLY_ACCOUNT_TYPE, 13, "foo");
+                .returnRow(1, WRITABLE_ACCOUNT_TYPE, 13, "foo")
+                .returnRow(2, READONLY_ACCOUNT_TYPE, 13, "foo");
         assertWithMessageId(R.string.readOnlyContactDeleteConfirmation);
     }
 
     public void testMultipleWritableRawContacts() {
         expectQuery()
-                .returnRow(1, MockAccountTypeManager.WRITABLE_ACCOUNT_TYPE, 13, "foo")
-                .returnRow(2, MockAccountTypeManager.WRITABLE_ACCOUNT_TYPE, 13, "foo");
+                .returnRow(1, WRITABLE_ACCOUNT_TYPE, 13, "foo")
+                .returnRow(2, WRITABLE_ACCOUNT_TYPE, 13, "foo");
         assertWithMessageId(R.string.multipleContactDeleteConfirmation);
     }
 
diff --git a/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java b/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java
index d15610b..2635a09 100644
--- a/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java
+++ b/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java
@@ -17,39 +17,37 @@
 
 import com.android.contacts.model.AccountType;
 import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.FallbackAccountType;
 
 import android.accounts.Account;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 
 /**
  * A mock {@link AccountTypeManager} class.
  */
 public class MockAccountTypeManager extends AccountTypeManager {
 
-    public static final String WRITABLE_ACCOUNT_TYPE = "writable";
-    public static final String READONLY_ACCOUNT_TYPE = "readonly";
+    private final AccountType[] mTypes;
+    private Account[] mAccounts;
+
+    public MockAccountTypeManager(AccountType[] types, Account[] accounts) {
+        this.mTypes = types;
+        this.mAccounts = accounts;
+    }
 
     @Override
     public AccountType getAccountType(String accountType) {
-        if (accountType.equals(WRITABLE_ACCOUNT_TYPE)) {
-            AccountType source = new FallbackAccountType();
-            source.readOnly = false;
-            return source;
+        for (AccountType type : mTypes) {
+            if (accountType.equals(type.accountType)) {
+                return type;
+            }
         }
-
-        if (accountType.equals(READONLY_ACCOUNT_TYPE)) {
-            AccountType source = new FallbackAccountType();
-            source.readOnly = true;
-            return source;
-        }
-
         return null;
     }
 
     @Override
     public ArrayList<Account> getAccounts(boolean writableOnly) {
-        throw new UnsupportedOperationException();
+        return new ArrayList<Account>(Arrays.asList(mAccounts));
     }
 }
diff --git a/tests/src/com/android/contacts/tests/mocks/MockContentProvider.java b/tests/src/com/android/contacts/tests/mocks/MockContentProvider.java
index 3acb52d..73414e5 100644
--- a/tests/src/com/android/contacts/tests/mocks/MockContentProvider.java
+++ b/tests/src/com/android/contacts/tests/mocks/MockContentProvider.java
@@ -16,6 +16,9 @@
 
 package com.android.contacts.tests.mocks;
 
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
 import android.content.ContentProvider;
 import android.content.ContentValues;
 import android.database.Cursor;
@@ -25,7 +28,8 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.LinkedList;
+import java.util.HashMap;
+import java.util.Iterator;
 
 import junit.framework.Assert;
 
@@ -47,6 +51,9 @@
         private boolean mAnyProjection;
         private boolean mAnySelection;
         private boolean mAnySortOrder;
+        private boolean mAnyNumberOfTimes;
+
+        private boolean mExecuted;
 
         public Query(Uri uri) {
             mUri = uri;
@@ -103,6 +110,11 @@
             return this;
         }
 
+        public Query anyNumberOfTimes() {
+            mAnyNumberOfTimes = true;
+            return this;
+        }
+
         public boolean equals(Uri uri, String[] projection, String selection,
                 String[] selectionArgs, String sortOrder) {
             if (!uri.equals(mUri)) {
@@ -199,8 +211,8 @@
         }
     }
 
-    private LinkedList<Query> mExpectedQueries = new LinkedList<Query>();
-    private LinkedList<TypeQuery> mExpectedTypeQueries = new LinkedList<TypeQuery>();
+    private ArrayList<Query> mExpectedQueries = new ArrayList<Query>();
+    private HashMap<Uri, String> mExpectedTypeQueries = Maps.newHashMap();
 
     @Override
     public boolean onCreate() {
@@ -209,30 +221,42 @@
 
     public Query expectQuery(Uri contentUri) {
         Query query = new Query(contentUri);
-        mExpectedQueries.offer(query);
+        mExpectedQueries.add(query);
         return query;
     }
 
     public void expectTypeQuery(Uri uri, String type) {
-        TypeQuery result = new TypeQuery(uri, type);
-        mExpectedTypeQueries.offer(result);
+        mExpectedTypeQueries.put(uri, type);
     }
 
     @Override
     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
             String sortOrder) {
+
+        for (Iterator<Query> iterator = mExpectedQueries.iterator(); iterator.hasNext();) {
+            Query query = iterator.next();
+            if (query.equals(uri, projection, selection, selectionArgs, sortOrder)) {
+                query.mExecuted = true;
+                if (!query.mAnyNumberOfTimes) {
+                    iterator.remove();
+                }
+                return query.getResult();
+            }
+        }
+
         if (mExpectedQueries.isEmpty()) {
             Assert.fail("Unexpected query: "
                     + queryToString(uri, projection, selection, selectionArgs, sortOrder));
-        }
-
-        Query query = mExpectedQueries.remove();
-        if (!query.equals(uri, projection, selection, selectionArgs, sortOrder)) {
-            Assert.fail("Incorrect query.\n    Expected: " + query + "\n      Actual: " +
+        } else {
+            StringBuilder sb = new StringBuilder();
+            sb.append(mExpectedQueries.get(0));
+            for (int i = 1; i < mExpectedQueries.size(); i++) {
+                sb.append("\n              ").append(mExpectedQueries.get(i));
+            }
+            Assert.fail("Incorrect query.\n    Expected: " + sb + "\n      Actual: " +
                     queryToString(uri, projection, selection, selectionArgs, sortOrder));
         }
-
-        return query.getResult();
+        return null;
     }
 
     @Override
@@ -246,12 +270,13 @@
             Assert.fail("Unexpected getType query: " + uri);
         }
 
-        TypeQuery query = mExpectedTypeQueries.remove();
-        if (!query.equals(uri)) {
-            Assert.fail("Incorrect query.\n    Expected: " + query + "\n      Actual: " + uri);
+        String mimeType = mExpectedTypeQueries.get(uri);
+        if (mimeType != null) {
+            return mimeType;
         }
 
-        return query.getType();
+        Assert.fail("Unknown mime type for: " + uri);
+        return null;
     }
 
     @Override
@@ -288,9 +313,13 @@
     }
 
     public void verify() {
+        ArrayList<Query> mMissedQueries = Lists.newArrayList();
+        for (Query query : mExpectedQueries) {
+            if (!query.mExecuted) {
+                mMissedQueries.add(query);
+            }
+        }
         Assert.assertTrue("Not all expected queries have been called: " +
-                mExpectedQueries, mExpectedQueries.isEmpty());
-        Assert.assertTrue("Not all expected getType-queries have been called: " +
-                mExpectedQueries, mExpectedTypeQueries.isEmpty());
+                mMissedQueries, mMissedQueries.isEmpty());
     }
 }