Fix CallDetailActivity tests.

+ Reset the AsyncTaskExecutor's instance between calls in tests.
I don't know why this is necessary, but it fixes a class of problems
which were happening.

+ Don't try to release a media player if it has not been prepared.

+ Handle possible race conditions since MediaPlayer's async prepare
may be buffering or finished when a test assert is executed.

+ Add asset file no longer provided by variablespeed library.

- Cleanup some stream copy code.

Change-Id: I0ae5fde00514c6dcdb1e9c063435a13eed6e8528
diff --git a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
index 20e213c..aa186eb 100644
--- a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
+++ b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
@@ -34,6 +34,8 @@
 import com.android.dialer.util.AsyncTaskExecutors;
 import com.android.dialer.util.TelecomUtil;
 
+import com.google.common.annotations.VisibleForTesting;
+
 public class CallLogAsyncTaskUtil {
     private static String TAG = CallLogAsyncTaskUtil.class.getSimpleName();
 
@@ -297,4 +299,9 @@
                     }
                 });
     }
+
+    @VisibleForTesting
+    public static void resetForTest() {
+        sAsyncTaskExecutor = null;
+    }
 }
diff --git a/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java b/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java
index 1ab87fd..1ee3765 100644
--- a/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java
+++ b/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java
@@ -43,6 +43,7 @@
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 
+import java.io.IOException;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.RejectedExecutionException;
@@ -124,6 +125,7 @@
 
     private Uri mVoicemailUri;
     private int mPosition;
+    private boolean mIsPrepared;
     private boolean mIsPlaying;
     private boolean mShouldResumePlaybackAfterSeeking;
 
@@ -172,6 +174,7 @@
 
         mView.setPresenter(this);
 
+        mIsPrepared = false;
         checkForContent();
     }
 
@@ -184,6 +187,11 @@
     }
 
     public void onDestroy() {
+        if (mIsPrepared) {
+            mMediaPlayer.release();
+            mIsPrepared = false;
+        }
+
         if (mScheduledExecutorService != null) {
             mScheduledExecutorService.shutdown();
             mScheduledExecutorService = null;
@@ -350,7 +358,7 @@
             mMediaPlayer.setDataSource(mContext, mVoicemailUri);
             mMediaPlayer.setAudioStreamType(PLAYBACK_STREAM);
             mMediaPlayer.prepareAsync();
-        } catch (Exception e) {
+        } catch (IOException e) {
             handleError(e);
         }
     }
@@ -360,6 +368,8 @@
      */
     @Override
     public void onPrepared(MediaPlayer mp) {
+        mIsPrepared = true;
+
         mView.enableUiElements();
 
         if (mIsPlaying) {
@@ -380,7 +390,11 @@
     }
 
     private void handleError(Exception e) {
-        mMediaPlayer.release();
+        if (mIsPrepared) {
+            mMediaPlayer.release();
+            mIsPrepared = false;
+        }
+
         mView.onPlaybackError(e);
         setPosition(0, false);
     }
diff --git a/tests/assets/README.txt b/tests/assets/README.txt
new file mode 100644
index 0000000..6cea058
--- /dev/null
+++ b/tests/assets/README.txt
@@ -0,0 +1,3 @@
+quick_test_recording.mp3 is copyright 2011 by Hugo Hudson and is licensed under a
+Creative Commons Attribution 3.0 Unported License:
+  http://creativecommons.org/licenses/by/3.0/
diff --git a/tests/assets/quick_test_recording.mp3 b/tests/assets/quick_test_recording.mp3
new file mode 100644
index 0000000..ad7cb9c
--- /dev/null
+++ b/tests/assets/quick_test_recording.mp3
Binary files differ
diff --git a/tests/src/com/android/dialer/CallDetailActivityTest.java b/tests/src/com/android/dialer/CallDetailActivityTest.java
index 4dc9ebb..97b1b09 100644
--- a/tests/src/com/android/dialer/CallDetailActivityTest.java
+++ b/tests/src/com/android/dialer/CallDetailActivityTest.java
@@ -33,12 +33,12 @@
 import android.view.Menu;
 import android.widget.TextView;
 
+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 com.google.common.io.Closeables;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -90,27 +90,29 @@
         cleanUpUri();
         mTestUtils = null;
         AsyncTaskExecutors.setFactoryForTest(null);
+        CallLogAsyncTaskUtil.resetForTest();
         super.tearDown();
     }
 
     public void testInitialActivityStartsWithFetchingVoicemail() throws Throwable {
-        setActivityIntentForTestVoicemailEntry();
+        setActivityIntentForRealFileVoicemailEntry();
         startActivityUnderTest();
-        // When the activity first starts, we will show "Fetching voicemail" on the screen.
+        // When the activity first starts, we will show "Loading voicemail" on the screen.
         // The duration should not be visible.
-        assertHasOneTextViewContaining("Fetching voicemail");
+        assertHasOneTextViewContaining("Loading voicemail");
         assertZeroTextViewsContaining("00:00");
     }
 
-    public void testWhenCheckForContentCompletes_UiShowsBuffering() throws Throwable {
-        setActivityIntentForTestVoicemailEntry();
+    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, we should
-        // be showing "Buffering".
+        // Once that task completes, we shouldn't be showing the fetching message.
         mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
-        assertHasOneTextViewContaining("Buffering");
-        assertZeroTextViewsContaining("Fetching voicemail");
+
+        // 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 {
@@ -126,7 +128,7 @@
     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.
-        setActivityIntentForTestVoicemailEntry();
+        setActivityIntentForRealFileVoicemailEntry();
         startActivityUnderTest();
         mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
         getInstrumentation().runOnMainSync(new Runnable() {
@@ -138,7 +140,7 @@
                 getInstrumentation().callActivityOnResume(mActivityUnderTest);
             }
         });
-        assertHasOneTextViewContaining("Buffering");
+        assertHasOneTextViewContaining("Buffering", "00:00");
     }
 
     /**
@@ -215,6 +217,7 @@
         values.put(VoicemailContract.Voicemails.HAS_CONTENT, 1);
         values.put(VoicemailContract.Voicemails._DATA, VOICEMAIL_FILE_LOCATION);
         mVoicemailUri = contentResolver.insert(VoicemailContract.Voicemails.CONTENT_URI, values);
+
         Uri callLogUri = ContentUris.withAppendedId(CallLog.Calls.CONTENT_URI_WITH_VOICEMAIL,
                 ContentUris.parseId(mVoicemailUri));
         Intent intent = new Intent(Intent.ACTION_VIEW, callLogUri);
@@ -233,15 +236,9 @@
         mVoicemailUri = getContentResolver().insert(
                 VoicemailContract.Voicemails.buildSourceUri(packageName), values);
         AssetManager assets = getAssets();
-        OutputStream outputStream = null;
-        InputStream inputStream = null;
-        try {
-            inputStream = assets.open(TEST_ASSET_NAME);
-            outputStream = getContentResolver().openOutputStream(mVoicemailUri);
+        try (InputStream inputStream = assets.open(TEST_ASSET_NAME);
+             OutputStream outputStream = getContentResolver().openOutputStream(mVoicemailUri)) {
             copyBetweenStreams(inputStream, outputStream);
-        } finally {
-            Closeables.closeQuietly(outputStream);
-            Closeables.closeQuietly(inputStream);
         }
         Uri callLogUri = ContentUris.withAppendedId(CallLog.Calls.CONTENT_URI_WITH_VOICEMAIL,
                 ContentUris.parseId(mVoicemailUri));
@@ -253,9 +250,7 @@
     public void copyBetweenStreams(InputStream in, OutputStream out) throws IOException {
         byte[] buffer = new byte[1024];
         int bytesRead;
-        int total = 0;
-        while ((bytesRead = in.read(buffer)) != -1) {
-            total += bytesRead;
+        while ((bytesRead = in.read(buffer)) > 0) {
             out.write(buffer, 0, bytesRead);
         }
     }
@@ -285,6 +280,14 @@
         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);
@@ -300,6 +303,7 @@
         // 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() {