Fix some more unit tests...

+ Pull out voicemail playback tests into their own test class.
+ Fix CallDetailActivity unit tests.
+ Some minor tweaks to functional code to facilitate.

Bug: 21471763
Change-Id: I0f1747ab7ad6eba7dd2a7f6f8cfd060b409771bc
diff --git a/src/com/android/dialer/calllog/CallLogFragment.java b/src/com/android/dialer/calllog/CallLogFragment.java
index 845f911..d57d87a 100644
--- a/src/com/android/dialer/calllog/CallLogFragment.java
+++ b/src/com/android/dialer/calllog/CallLogFragment.java
@@ -191,6 +191,7 @@
         setHasOptionsMenu(true);
 
         mVoicemailPlaybackPresenter = new VoicemailPlaybackPresenter(activity, state);
+        activity.setVolumeControlStream(VoicemailPlaybackPresenter.PLAYBACK_STREAM);
     }
 
     /** Called by the CallLogQueryHandler when the list of calls has been fetched or updated. */
diff --git a/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java b/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java
index f068401..da2a29c 100644
--- a/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java
+++ b/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java
@@ -98,7 +98,7 @@
         VoicemailContract.Voicemails.HAS_CONTENT,
     };
 
-    private static final int PLAYBACK_STREAM = AudioManager.STREAM_VOICE_CALL;
+    public static final int PLAYBACK_STREAM = AudioManager.STREAM_VOICE_CALL;
     private static final int NUMBER_OF_THREADS_IN_POOL = 2;
     // Time to wait for content to be fetched before timing out.
     private static final long FETCH_CONTENT_TIMEOUT_MS = 20000;
@@ -145,8 +145,8 @@
     private PowerManager.WakeLock mProximityWakeLock;
     private AudioManager mAudioManager;
 
-    public VoicemailPlaybackPresenter(Activity activity, Bundle savedInstanceState) {
-        mContext = activity;
+    public VoicemailPlaybackPresenter(Context context, Bundle savedInstanceState) {
+        mContext = context;
         mAsyncTaskExecutor = AsyncTaskExecutors.createAsyncTaskExecutor();
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
 
@@ -174,8 +174,6 @@
         mMediaPlayer.setOnPreparedListener(this);
         mMediaPlayer.setOnErrorListener(this);
         mMediaPlayer.setOnCompletionListener(this);
-
-        activity.setVolumeControlStream(PLAYBACK_STREAM);
     }
 
     /**
@@ -574,4 +572,8 @@
         return mScheduledExecutorService;
     }
 
+    @VisibleForTesting
+    public boolean isPlaying() {
+        return mIsPlaying;
+    }
 }
diff --git a/tests/src/com/android/dialer/CallDetailActivityTest.java b/tests/src/com/android/dialer/CallDetailActivityTest.java
index 97b1b09..3b6b611 100644
--- a/tests/src/com/android/dialer/CallDetailActivityTest.java
+++ b/tests/src/com/android/dialer/CallDetailActivityTest.java
@@ -17,13 +17,11 @@
 package com.android.dialer;
 
 import static com.android.dialer.calllog.CallLogAsyncTaskUtil.Tasks.GET_CALL_DETAILS;
-import static com.android.dialer.voicemail.VoicemailPlaybackPresenter.Tasks.CHECK_FOR_CONTENT;
 
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Intent;
-import android.content.res.AssetManager;
 import android.net.Uri;
 import android.provider.CallLog;
 import android.provider.VoicemailContract;
@@ -36,31 +34,19 @@
 import com.android.dialer.calllog.CallLogAsyncTaskUtil;
 import com.android.dialer.util.AsyncTaskExecutors;
 import com.android.dialer.util.FakeAsyncTaskExecutor;
-import com.android.contacts.common.test.IntegrationTestUtils;
-import com.android.dialer.util.LocaleTestUtils;
 import com.android.internal.view.menu.ContextMenuBuilder;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.List;
-import java.util.Locale;
-
 /**
  * Unit tests for the {@link CallDetailActivity}. NOTE: The screen needs to be on for the
  * UI-related tests to pass.
  */
 @LargeTest
 public class CallDetailActivityTest extends ActivityInstrumentationTestCase2<CallDetailActivity> {
-    private static final String TEST_ASSET_NAME = "quick_test_recording.mp3";
-    private static final String MIME_TYPE = "audio/mp3";
     private static final String CONTACT_NUMBER = "+1412555555";
     private static final String VOICEMAIL_FILE_LOCATION = "/sdcard/sadlfj893w4j23o9sfu.mp3";
 
     private Uri mCallLogUri;
     private Uri mVoicemailUri;
-    private IntegrationTestUtils mTestUtils;
-    private LocaleTestUtils mLocaleTestUtils;
     private FakeAsyncTaskExecutor mFakeAsyncTaskExecutor;
     private CallDetailActivity mActivityUnderTest;
 
@@ -71,91 +57,25 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+
         mFakeAsyncTaskExecutor = new FakeAsyncTaskExecutor(getInstrumentation());
         AsyncTaskExecutors.setFactoryForTest(mFakeAsyncTaskExecutor.getFactory());
+
         // I don't like the default of focus-mode for tests, the green focus border makes the
         // screenshots look weak.
         setActivityInitialTouchMode(true);
-        mTestUtils = new IntegrationTestUtils(getInstrumentation());
-        // Some of the tests rely on the text that appears on screen - safest to force a
-        // specific locale.
-        mLocaleTestUtils = new LocaleTestUtils(getInstrumentation().getTargetContext());
-        mLocaleTestUtils.setLocale(Locale.US);
     }
 
     @Override
     protected void tearDown() throws Exception {
-        mLocaleTestUtils.restoreLocale();
-        mLocaleTestUtils = null;
         cleanUpUri();
-        mTestUtils = null;
+
         AsyncTaskExecutors.setFactoryForTest(null);
         CallLogAsyncTaskUtil.resetForTest();
+
         super.tearDown();
     }
 
-    public void testInitialActivityStartsWithFetchingVoicemail() throws Throwable {
-        setActivityIntentForRealFileVoicemailEntry();
-        startActivityUnderTest();
-        // When the activity first starts, we will show "Loading voicemail" on the screen.
-        // The duration should not be visible.
-        assertHasOneTextViewContaining("Loading voicemail");
-        assertZeroTextViewsContaining("00:00");
-    }
-
-    public void testWhenCheckForContentCompletes() throws Throwable {
-        setActivityIntentForRealFileVoicemailEntry();
-        startActivityUnderTest();
-        // There is a background check that is testing to see if we have the content available.
-        // Once that task completes, we shouldn't be showing the fetching message.
-        mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
-
-        // The voicemail async call may or may not return before we check the asserts.
-        assertHasOneTextViewContaining("Buffering", "00:00");
-        assertZeroTextViewsContaining("Loading voicemail");
-    }
-
-    public void testInvalidVoicemailShowsErrorMessage() throws Throwable {
-        setActivityIntentForTestVoicemailEntry();
-        startActivityUnderTest();
-        mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
-        // The media player will have thrown an IOException since the file doesn't exist.
-        // This should have put a failed to play message on screen, buffering is gone.
-        assertHasOneTextViewContaining("Couldn't play voicemail");
-        assertZeroTextViewsContaining("Buffering");
-    }
-
-    public void testOnResumeDoesNotCreateManyFragments() throws Throwable {
-        // There was a bug where every time the activity was resumed, a new fragment was created.
-        // Before the fix, this was failing reproducibly with at least 3 "Buffering" views.
-        setActivityIntentForRealFileVoicemailEntry();
-        startActivityUnderTest();
-        mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                getInstrumentation().callActivityOnPause(mActivityUnderTest);
-                getInstrumentation().callActivityOnResume(mActivityUnderTest);
-                getInstrumentation().callActivityOnPause(mActivityUnderTest);
-                getInstrumentation().callActivityOnResume(mActivityUnderTest);
-            }
-        });
-        assertHasOneTextViewContaining("Buffering", "00:00");
-    }
-
-    /**
-     * Test for bug where increase rate button with invalid voicemail causes a crash.
-     * <p>
-     * The repro steps for this crash were to open a voicemail that does not have an attachment,
-     * then click the play button (which just reported an error), then after that try to adjust the
-     * rate.  See http://b/5047879.
-     */
-    public void testClickIncreaseRateButtonWithInvalidVoicemailDoesNotCrash() throws Throwable {
-        setActivityIntentForTestVoicemailEntry();
-        startActivityUnderTest();
-        mTestUtils.clickButton(mActivityUnderTest, R.id.playback_start_stop);
-    }
-
     /** Test for bug where missing Extras on intent used to start Activity causes NPE. */
     public void testCallLogUriWithMissingExtrasShouldNotCauseNPE() throws Throwable {
         setActivityIntentForTestCallEntry();
@@ -170,35 +90,32 @@
     public void testVoicemailDoesNotHaveRemoveFromCallLog() throws Throwable {
         setActivityIntentForTestVoicemailEntry();
         startActivityUnderTest();
+        mFakeAsyncTaskExecutor.runTask(GET_CALL_DETAILS);
+
         Menu menu = new ContextMenuBuilder(mActivityUnderTest);
         mActivityUnderTest.onCreateOptionsMenu(menu);
         mActivityUnderTest.onPrepareOptionsMenu(menu);
         assertFalse(menu.findItem(R.id.menu_remove_from_call_log).isVisible());
+        assertTrue(menu.findItem(R.id.menu_trash).isVisible());
     }
 
-    /** Test to check that I haven't broken the remove-from-call-log entry from regular calls. */
+    /**
+     * Test to check that I haven't broken the remove-from-call-log entry from regular calls.
+     */
     public void testRegularCallDoesHaveRemoveFromCallLog() throws Throwable {
         setActivityIntentForTestCallEntry();
         startActivityUnderTest();
+        mFakeAsyncTaskExecutor.runTask(GET_CALL_DETAILS);
+
         Menu menu = new ContextMenuBuilder(mActivityUnderTest);
         mActivityUnderTest.onCreateOptionsMenu(menu);
         mActivityUnderTest.onPrepareOptionsMenu(menu);
         assertTrue(menu.findItem(R.id.menu_remove_from_call_log).isVisible());
-    }
-
-    @Suppress
-    public void testClickingCallStopsPlayback() throws Throwable {
-        setActivityIntentForRealFileVoicemailEntry();
-        startActivityUnderTest();
-        mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
-        mTestUtils.clickButton(mActivityUnderTest, R.id.playback_speakerphone);
-        mTestUtils.clickButton(mActivityUnderTest, R.id.playback_start_stop);
-        Thread.sleep(2000);
-        // TODO: Suppressed the test for now, because I'm looking for an easy way to say "the audio
-        // is not playing at this point", and I can't find it without doing dirty things.
+        assertFalse(menu.findItem(R.id.menu_trash).isVisible());
     }
 
     private void setActivityIntentForTestCallEntry() {
+        assertNull(mVoicemailUri);
         assertNull(mCallLogUri);
         ContentResolver contentResolver = getContentResolver();
         ContentValues values = new ContentValues();
@@ -225,36 +142,6 @@
         setActivityIntent(intent);
     }
 
-    private void setActivityIntentForRealFileVoicemailEntry() throws IOException {
-        assertNull(mVoicemailUri);
-        ContentValues values = new ContentValues();
-        values.put(VoicemailContract.Voicemails.DATE, String.valueOf(System.currentTimeMillis()));
-        values.put(VoicemailContract.Voicemails.NUMBER, CONTACT_NUMBER);
-        values.put(VoicemailContract.Voicemails.MIME_TYPE, MIME_TYPE);
-        values.put(VoicemailContract.Voicemails.HAS_CONTENT, 1);
-        String packageName = getInstrumentation().getTargetContext().getPackageName();
-        mVoicemailUri = getContentResolver().insert(
-                VoicemailContract.Voicemails.buildSourceUri(packageName), values);
-        AssetManager assets = getAssets();
-        try (InputStream inputStream = assets.open(TEST_ASSET_NAME);
-             OutputStream outputStream = getContentResolver().openOutputStream(mVoicemailUri)) {
-            copyBetweenStreams(inputStream, outputStream);
-        }
-        Uri callLogUri = ContentUris.withAppendedId(CallLog.Calls.CONTENT_URI_WITH_VOICEMAIL,
-                ContentUris.parseId(mVoicemailUri));
-        Intent intent = new Intent(Intent.ACTION_VIEW, callLogUri);
-        intent.putExtra(CallDetailActivity.EXTRA_VOICEMAIL_URI, mVoicemailUri);
-        setActivityIntent(intent);
-    }
-
-    public void copyBetweenStreams(InputStream in, OutputStream out) throws IOException {
-        byte[] buffer = new byte[1024];
-        int bytesRead;
-        while ((bytesRead = in.read(buffer)) > 0) {
-            out.write(buffer, 0, bytesRead);
-        }
-    }
-
     private void cleanUpUri() {
         if (mVoicemailUri != null) {
             getContentResolver().delete(VoicemailContract.Voicemails.CONTENT_URI,
@@ -272,41 +159,9 @@
         return getInstrumentation().getTargetContext().getContentResolver();
     }
 
-    private TextView assertHasOneTextViewContaining(String text) throws Throwable {
-        assertNotNull(mActivityUnderTest);
-        List<TextView> views = mTestUtils.getTextViewsWithString(mActivityUnderTest, text);
-        assertEquals("There should have been one TextView with text '" + text + "' but found "
-                + views, 1, views.size());
-        return views.get(0);
-    }
-
-    private void assertHasOneTextViewContaining(String text1, String text2) throws Throwable {
-        assertNotNull(mActivityUnderTest);
-        List<TextView> view1s = mTestUtils.getTextViewsWithString(mActivityUnderTest, text1);
-        List<TextView> view2s = mTestUtils.getTextViewsWithString(mActivityUnderTest, text2);
-        assertEquals("There should have been one TextView with text '" + text1 + "' or text '"
-                + text2  + "' but found " + view1s + view2s, 1, view1s.size() + view2s.size());
-    }
-
-    private void assertZeroTextViewsContaining(String text) throws Throwable {
-        assertNotNull(mActivityUnderTest);
-        List<TextView> views = mTestUtils.getTextViewsWithString(mActivityUnderTest, text);
-        assertEquals("There should have been no TextViews with text '" + text + "' but found "
-                + views, 0,  views.size());
-    }
-
     private void startActivityUnderTest() throws Throwable {
         assertNull(mActivityUnderTest);
         mActivityUnderTest = getActivity();
         assertNotNull("activity should not be null", mActivityUnderTest);
-        // We have to run all tasks, not just one.
-        // This is because it seems that we can have onResume, onPause, onResume during the course
-        // of a single unit test.
-        mFakeAsyncTaskExecutor.runAllTasks(GET_CALL_DETAILS);
-        CallLogAsyncTaskUtil.resetForTest();
-    }
-
-    private AssetManager getAssets() {
-        return getInstrumentation().getContext().getAssets();
     }
 }
diff --git a/tests/src/com/android/dialer/voicemail/VoicemailPlaybackTest.java b/tests/src/com/android/dialer/voicemail/VoicemailPlaybackTest.java
new file mode 100644
index 0000000..dd86b0d
--- /dev/null
+++ b/tests/src/com/android/dialer/voicemail/VoicemailPlaybackTest.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2015 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.dialer.voicemail;
+
+import static com.android.dialer.voicemail.VoicemailPlaybackPresenter.Tasks.CHECK_FOR_CONTENT;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.net.Uri;
+import android.provider.VoicemailContract;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.contacts.common.test.IntegrationTestUtils;
+import com.android.dialer.R;
+import com.android.dialer.util.AsyncTaskExecutors;
+import com.android.dialer.util.FakeAsyncTaskExecutor;
+import com.android.dialer.util.LocaleTestUtils;
+import com.android.dialer.voicemail.VoicemailPlaybackLayout;
+import com.android.dialer.voicemail.VoicemailPlaybackPresenter;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Unit tests for the {@link VoicemailPlaybackPresenter} and {@link VoicemailPlaybackLayout}.
+ */
+@LargeTest
+public class VoicemailPlaybackTest extends InstrumentationTestCase {
+    private static final String TEST_ASSET_NAME = "quick_test_recording.mp3";
+    private static final String MIME_TYPE = "audio/mp3";
+    private static final String CONTACT_NUMBER = "+1412555555";
+    private static final String VOICEMAIL_FILE_LOCATION = "/sdcard/sadlfj893w4j23o9sfu.mp3";
+
+    private Context mContext;
+    private VoicemailPlaybackPresenter mPresenter;
+    private VoicemailPlaybackLayout mLayout;
+
+    private Uri mVoicemailUri;
+    private IntegrationTestUtils mTestUtils;
+    private LocaleTestUtils mLocaleTestUtils;
+    private FakeAsyncTaskExecutor mFakeAsyncTaskExecutor;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mFakeAsyncTaskExecutor = new FakeAsyncTaskExecutor(getInstrumentation());
+        AsyncTaskExecutors.setFactoryForTest(mFakeAsyncTaskExecutor.getFactory());
+        mTestUtils = new IntegrationTestUtils(getInstrumentation());
+
+        // Some of the tests rely on the text - safest to force a specific locale.
+        mLocaleTestUtils = new LocaleTestUtils(getInstrumentation().getTargetContext());
+        mLocaleTestUtils.setLocale(Locale.US);
+
+        mContext = getInstrumentation().getTargetContext();
+        mLayout = new VoicemailPlaybackLayout(mContext);
+        mLayout.onFinishInflate();
+        mPresenter = new VoicemailPlaybackPresenter(mContext, null);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        cleanUpVoicemailUri();
+
+        mLocaleTestUtils.restoreLocale();
+        mLocaleTestUtils = null;
+
+        mLayout = null;
+        mPresenter = null;
+        mTestUtils = null;
+        AsyncTaskExecutors.setFactoryForTest(null);
+
+        super.tearDown();
+    }
+
+    public void testFetchingVoicemail() throws Throwable {
+        setUriForRealFileVoicemailEntry();
+        setPlaybackViewForPresenter();
+        assertHasOneTextViewContaining("Loading voicemail");
+    }
+
+    public void testWhenCheckForContentCompletes() throws Throwable {
+        setUriForRealFileVoicemailEntry();
+        setPlaybackViewForPresenter();
+
+        // There is a background check that is testing to see if we have the content available.
+        // Once that task completes, we shouldn't be showing the fetching message.
+        mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
+
+        assertHasOneTextViewContaining("Buffering");
+        assertHasZeroTextViewsContaining("Loading voicemail");
+    }
+
+    public void testInvalidVoicemailShowsErrorMessage() throws Throwable {
+        setUriForInvalidVoicemailEntry();
+        setPlaybackViewForPresenter();
+
+        mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
+
+        // The media player will have thrown an IOException since the file doesn't exist.
+        // This should have put a failed to play message on screen, buffering is gone.
+        assertHasOneTextViewContaining("Couldn't play voicemail");
+        assertHasZeroTextViewsContaining("Buffering");
+    }
+
+    public void testClickingSpeakerphoneButton() throws Throwable {
+        setUriForRealFileVoicemailEntry();
+        setPlaybackViewForPresenter();
+
+        // Wait for check for content to complete.
+        mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
+        getInstrumentation().waitForIdleSync();
+
+        // Force the speakerphone to false to start.
+        mPresenter.setSpeakerphoneOn(false);
+        assertFalse(mPresenter.isSpeakerphoneOn());
+
+        View speakerphoneButton = mLayout.findViewById(R.id.playback_speakerphone);
+        speakerphoneButton.performClick();
+        assertTrue(mPresenter.isSpeakerphoneOn());
+    }
+
+    private void cleanUpVoicemailUri() {
+        if (mVoicemailUri != null) {
+            getContentResolver().delete(VoicemailContract.Voicemails.CONTENT_URI,
+                    "_ID = ?", new String[] { String.valueOf(ContentUris.parseId(mVoicemailUri)) });
+            mVoicemailUri = null;
+        }
+    }
+
+    private void setUriForRealFileVoicemailEntry() throws IOException {
+        assertNull(mVoicemailUri);
+        ContentValues values = new ContentValues();
+        values.put(VoicemailContract.Voicemails.DATE, String.valueOf(System.currentTimeMillis()));
+        values.put(VoicemailContract.Voicemails.NUMBER, CONTACT_NUMBER);
+        values.put(VoicemailContract.Voicemails.MIME_TYPE, MIME_TYPE);
+        values.put(VoicemailContract.Voicemails.HAS_CONTENT, 1);
+        String packageName = getInstrumentation().getTargetContext().getPackageName();
+        mVoicemailUri = getContentResolver().insert(
+                VoicemailContract.Voicemails.buildSourceUri(packageName), values);
+        AssetManager assets = getAssets();
+        try (InputStream inputStream = assets.open(TEST_ASSET_NAME);
+             OutputStream outputStream = getContentResolver().openOutputStream(mVoicemailUri)) {
+            copyBetweenStreams(inputStream, outputStream);
+        }
+    }
+
+    private void setUriForInvalidVoicemailEntry() {
+        assertNull(mVoicemailUri);
+        ContentResolver contentResolver = getContentResolver();
+        ContentValues values = new ContentValues();
+        values.put(VoicemailContract.Voicemails.NUMBER, CONTACT_NUMBER);
+        values.put(VoicemailContract.Voicemails.HAS_CONTENT, 1);
+        values.put(VoicemailContract.Voicemails._DATA, VOICEMAIL_FILE_LOCATION);
+        mVoicemailUri = contentResolver.insert(VoicemailContract.Voicemails.CONTENT_URI, values);
+    }
+
+    private void setPlaybackViewForPresenter() {
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mPresenter.setPlaybackView(mLayout, mVoicemailUri, false);
+            }
+        });
+    }
+
+    public void copyBetweenStreams(InputStream in, OutputStream out) throws IOException {
+        byte[] buffer = new byte[1024];
+        int bytesRead;
+        while ((bytesRead = in.read(buffer)) > 0) {
+            out.write(buffer, 0, bytesRead);
+        }
+    }
+
+    private void assertHasOneTextViewContaining(String text) throws Throwable {
+        assertNotNull(mLayout);
+        List<TextView> views = mTestUtils.getTextViewsWithString(mLayout, text);
+        assertEquals("There should have been one TextView with text '" + text + "' but found "
+                + views, 1, views.size());
+    }
+
+    private void assertHasZeroTextViewsContaining(String text) throws Throwable {
+        assertNotNull(mLayout);
+        List<TextView> views = mTestUtils.getTextViewsWithString(mLayout, text);
+        assertEquals("There should have been no TextViews with text '" + text + "' but found "
+                + views, 0,  views.size());
+    }
+
+    private ContentResolver getContentResolver() {
+        return getInstrumentation().getTargetContext().getContentResolver();
+    }
+
+    private AssetManager getAssets() {
+        return getInstrumentation().getContext().getAssets();
+    }
+}