Add a randomized testcase for MediaPlayer.java API methods

Change-Id: I99cac3cbb30110a1393f196b70cd6a066c2f5cc5
diff --git a/tests/tests/media/src/android/media/cts/MediaRandomTest.java b/tests/tests/media/src/android/media/cts/MediaRandomTest.java
index f1e3e8e..adee09d 100644
--- a/tests/tests/media/src/android/media/cts/MediaRandomTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRandomTest.java
@@ -16,15 +16,30 @@
 package android.media.cts;
 
 
+import com.android.cts.media.R;
+
 import android.media.MediaRecorder;
 import android.media.MediaPlayer;
 import android.view.SurfaceHolder;
 import android.test.ActivityInstrumentationTestCase2;
 import android.os.Environment;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.Resources;
 import android.util.Log;
 
 import java.util.Random;
 
+/**
+ * Tests for the MediaPlayer.java and MediaRecorder.java APIs
+ *
+ * These testcases make randomized calls to the public APIs available, and
+ * the focus is on whether the randomized calls can lead to crash in
+ * mediaserver process and/or ANRs.
+ *
+ * The files in res/raw used by testLocalVideo* are (c) copyright 2008,
+ * Blender Foundation / www.bigbuckbunny.org, and are licensed under the Creative Commons
+ * Attribution 3.0 License at http://creativecommons.org/licenses/by/3.0/us/.
+ */
 public class MediaRandomTest extends ActivityInstrumentationTestCase2<MediaStubActivity> {
     private static final String TAG = "MediaRandomTest";
 
@@ -32,9 +47,15 @@
                 Environment.getExternalStorageDirectory().toString() + "/record.3gp";
 
     private static final int NUMBER_OF_RECORDER_RANDOM_ACTIONS = 100000;
+    private static final int NUMBER_OF_PLAYER_RANDOM_ACTIONS   = 100000;
 
     private MediaRecorder mRecorder;
-    private volatile boolean mMediaServerDied = false;
+    private MediaPlayer mPlayer;
+    private SurfaceHolder mSurfaceHolder;
+    private Resources mResources;
+
+    // Modified across multiple threads
+    private volatile boolean mMediaServerDied;
     private volatile int mAction;
     private volatile int mParam;
 
@@ -42,12 +63,16 @@
     protected void setUp() throws Exception {
         super.setUp();
         getInstrumentation().waitForIdleSync();
+        mMediaServerDied = false;
+        mSurfaceHolder = getActivity().getSurfaceHolder();
+        mResources = getInstrumentation().getTargetContext().getResources();
         try {
             // Running this on UI thread make sure that
             // onError callback can be received.
             runTestOnUiThread(new Runnable() {
                 public void run() {
                     mRecorder = new MediaRecorder();
+                    mPlayer = new MediaPlayer();
                 }
             });
         } catch (Throwable e) {
@@ -62,6 +87,10 @@
             mRecorder.release();
             mRecorder = null;
         }
+        if (mPlayer != null) {
+            mPlayer.release();
+            mPlayer = null;
+        }
         super.tearDown();
     }
 
@@ -132,7 +161,101 @@
         super("com.android.cts.media", MediaStubActivity.class);
     }
 
-    public void testmRecorderRandomAction() throws Exception {
+    private void loadSource(int resid) throws Exception {
+        AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
+        try {
+            mPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(),
+                    afd.getLength());
+        } finally {
+            afd.close();
+        }
+    }
+
+    public void testPlayerRandomAction() throws Exception {
+        try {
+            mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+                @Override
+                public boolean onError(MediaPlayer mp, int what, int extra) {
+                    if (mPlayer == mp &&
+                        what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
+                        Log.e(TAG, "mediaserver process died");
+                        mMediaServerDied = true;
+                    }
+                    return true;
+                }
+            });
+            loadSource(R.raw.video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz);
+            mPlayer.setDisplay(mSurfaceHolder);
+            mPlayer.prepare();
+            mPlayer.start();
+
+            long seed = System.currentTimeMillis();
+            Log.v(TAG, "seed = " + seed);
+            Random r = new Random(seed);
+
+            Watchdog watchdog = new Watchdog(5000);
+            watchdog.start();
+            for (int i = 0; i < NUMBER_OF_PLAYER_RANDOM_ACTIONS; i++){
+                watchdog.ping();
+                assertTrue(!mMediaServerDied);
+
+                mAction = (int)(r.nextInt() % 12);
+                mParam = (int)(r.nextInt() % 1000000);
+                try {
+                    switch (mAction) {
+                    case 0:
+                        mPlayer.getCurrentPosition();
+                        break;
+                    case 1:
+                        mPlayer.getDuration();
+                        break;
+                    case 2:
+                        mPlayer.getVideoHeight();
+                        break;
+                    case 3:
+                        mPlayer.getVideoWidth();
+                       break;
+                    case 4:
+                        mPlayer.isPlaying();
+                        break;
+                    case 5:
+                        mPlayer.pause();
+                        break;
+                    case 6:
+                        // Don't add mPlayer.prepare() call here for two reasons:
+                        // 1. calling prepare() is a bad idea since it is a blocking call, and
+                        // 2. when prepare() is in progress, mediaserver died message will not be sent to apps
+                        mPlayer.prepareAsync();
+                        break;
+                    case 7:
+                        mPlayer.seekTo((int)(mParam));
+                        break;
+                    case 8:
+                        mPlayer.setLooping(mParam % 2 == 0);
+                        break;
+                    case 9:
+                        mPlayer.setVolume((mParam % 1000) / 500.0f,
+                                     (mParam / 1000) / 500.0f);
+                        break;
+                    case 10:
+                        mPlayer.start();
+                        break;
+                    case 11:
+                        Thread.sleep(mParam % 20);
+                        break;
+                    }
+                } catch (Exception e) {
+                }
+            }
+            mPlayer.stop();
+            watchdog.end();
+            watchdog.join();
+        } catch (Exception e) {
+            Log.v(TAG, e.toString());
+        }
+    }
+
+    public void testRecorderRandomAction() throws Exception {
         try {
             long seed = System.currentTimeMillis();
             Log.v(TAG, "seed = " + seed);
@@ -142,11 +265,8 @@
             mRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {
                 @Override
                 public void onError(MediaRecorder recorder, int what, int extra) {
-                    // FIXME:
-                    // replace the constant with MediaRecorder.MEDIA_RECORDER_ERROR_SERVER_DIED,
-                    // if it becomes public.
                     if (mRecorder == recorder &&
-                        what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
+                        what == MediaRecorder.MEDIA_ERROR_SERVER_DIED) {
                         Log.e(TAG, "mediaserver process died");
                         mMediaServerDied = true;
                     }
@@ -155,7 +275,6 @@
 
             final int[] width  = {176, 352, 320, 640, 1280, 1920};
             final int[] height = {144, 288, 240, 480,  720, 1080};
-            final SurfaceHolder surfaceHolder = getActivity().getSurfaceHolder();
 
             Watchdog watchdog = new Watchdog(5000);
             watchdog.start();
@@ -186,7 +305,7 @@
                         mRecorder.setVideoEncoder(mParam % 5);
                         break;
                     case 5:
-                        mRecorder.setPreviewDisplay(surfaceHolder.getSurface());
+                        mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
                         break;
                     case 6:
                         int index = mParam % width.length;