Turn screen on when activity is on resume.

Also try getting the to-be-rendered surface a few times and allow it to
fail instead of waiting for timeout if no surface is available after all retries.

Bug:29636897, 31219737
Change-Id: I5d2896bf0bd98e7228e1dab66e9c9cd80d7130b7
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
index 0a3165b..7b74ba7 100644
--- a/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
@@ -20,6 +20,7 @@
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.util.Log;
 import android.view.View;
 
 @TargetApi(24)
@@ -32,6 +33,20 @@
     private static final int ALLOWED_GREATEST_PIXEL_DIFFERENCE = 90;
     private static final int OFFSET = 10;
 
+    private View videoView;
+    private VideoViewFactory videoViewFactory;
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (videoView != null) {
+            getHelper().cleanUpView(videoView);
+        }
+        if (videoViewFactory != null) {
+            videoViewFactory.release();
+        }
+        super.tearDown();
+    }
+
     /* <------------- Tests Using H264 -------------> */
     public void testH264GLViewVideoDecode() throws Exception {
         runH264DecodeAccuracyTest(
@@ -136,24 +151,33 @@
 
     private void runDecodeAccuracyTest(
             VideoViewFactory videoViewFactory, VideoFormat videoFormat, int goldenResId) {
-        checkNotNull(videoViewFactory);
         checkNotNull(videoFormat);
-        View videoView = videoViewFactory.createView(getHelper().getContext());
-        // If view is intended and available to display.
-        if (videoView != null) {
-            getHelper().generateView(videoView);
+        this.videoViewFactory = checkNotNull(videoViewFactory);
+        this.videoView = videoViewFactory.createView(getHelper().getContext());
+        final int maxRetries = 3;
+        for (int retry = 1; retry <= maxRetries; retry++) {
+            // If view is intended and available to display.
+            if (videoView != null) {
+                getHelper().generateView(videoView);
+            }
+            try {
+                videoViewFactory.waitForViewIsAvailable();
+                break;
+            } catch (Exception exception) {
+                Log.e(TAG, exception.getMessage());
+                if (retry == maxRetries) {
+                    fail("Timeout waiting for a valid surface.");
+                } else {
+                    Log.w(TAG, "Try again...");
+                    bringActivityToFront();
+                }
+            }
         }
-        videoViewFactory.waitForViewIsAvailable();
         // In the case of SurfaceView, VideoViewSnapshot can only capture incoming frames,
         // so it needs to be created before start decoding.
         final VideoViewSnapshot videoViewSnapshot = videoViewFactory.getVideoViewSnapshot();
         decodeVideo(videoFormat, videoViewFactory);
         validateResult(videoFormat, videoViewSnapshot, goldenResId);
-
-        if (videoView != null) {
-            getHelper().cleanUpView(videoView);
-        }
-        videoViewFactory.release();
     }
 
     private void decodeVideo(VideoFormat videoFormat, VideoViewFactory videoViewFactory) {
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestActivity.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestActivity.java
index da06844..8994c78 100644
--- a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestActivity.java
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestActivity.java
@@ -27,7 +27,13 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.test_runner_activity);
+    }
+
+    @Override
+    protected void onResume() {
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        super.onResume();
     }
 
 }
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
index 47029d6b..fae1bb4 100644
--- a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
@@ -20,6 +20,7 @@
 import android.annotation.TargetApi;
 import android.app.Activity;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -101,6 +102,12 @@
         super.tearDown();
     }
 
+    protected void bringActivityToFront() {
+        Intent intent = new Intent(mContext, DecodeAccuracyTestActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+        mActivity.startActivity(intent);
+    }
+
     protected TestHelper getHelper() {
         return testHelper;
     }
@@ -165,6 +172,7 @@
          * This must be called before decodeFramesAndDisplay.
          */
         private boolean prepare(Surface surface, VideoFormat videoFormat) {
+            Log.i(TAG, "Preparing to decode the media file.");
             if (!setExtractorDataSource(videoFormat)) {
                 return false;
             }
@@ -181,6 +189,7 @@
         /* The function decode video frames and display in a surface. */
         private PlayerResult decodeFramesAndDisplay(
                 Surface surface, int numOfTotalFrames, long timeOutMs) {
+            Log.i(TAG, "Starting decoding.");
             checkNotNull(decoder);
             int numOfDecodedFrames = 0;
             long decodeStart = 0;
@@ -219,11 +228,12 @@
                         numOfDecodedFrames++;
                     }
                 } catch (IllegalStateException exception) {
-                    Log.e(TAG, "IllegalStateException in decodeFramesAndDisplay " + exception);
+                    Log.e(TAG, "IllegalStateException in decodeFramesAndDisplay", exception);
                     break;
                 }
             }
             long totalTime = SystemClock.elapsedRealtime() - decodeStart;
+            Log.i(TAG, "Finishing decoding.");
             return new PlayerResult(true, true, numOfTotalFrames == numOfDecodedFrames, totalTime);
         }
 
@@ -290,12 +300,12 @@
                 decoder.stop();
             } catch (IllegalStateException exception) {
                 // IllegalStateException happens when decoder fail to start.
-                Log.e(TAG, "IllegalStateException in decoder stop" + exception);
+                Log.e(TAG, "IllegalStateException in decoder stop", exception);
             } finally {
                 try {
                     decoder.release();
                 } catch (IllegalStateException exception) {
-                    Log.e(TAG, "IllegalStateException in decoder release" + exception);
+                    Log.e(TAG, "IllegalStateException in decoder release", exception);
                 }
             }
             decoder = null;
@@ -308,7 +318,7 @@
             try {
                 extractor.release();
             } catch (IllegalStateException exception) {
-                Log.e(TAG, "IllegalStateException in extractor release" + exception);
+                Log.e(TAG, "IllegalStateException in extractor release", exception);
             }
         }
 
@@ -521,7 +531,8 @@
 /* Factory for manipulating a {@link View}. */
 abstract class VideoViewFactory {
 
-    public final long VIEW_AVAILABLE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(1);
+    public static final long VIEW_WAITTIME_MS = TimeUnit.SECONDS.toMillis(1);
+    public static final long DEFAULT_VIEW_AVAILABLE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(3);
     public static final int VIEW_WIDTH = 480;
     public static final int VIEW_HEIGHT = 360;
 
@@ -533,12 +544,20 @@
 
     public abstract View createView(Context context);
 
-    public abstract void waitForViewIsAvailable();
+    public void waitForViewIsAvailable() throws Exception {
+        waitForViewIsAvailable(DEFAULT_VIEW_AVAILABLE_TIMEOUT_MS);
+    };
+
+    public abstract void waitForViewIsAvailable(long timeOutMs) throws Exception;
 
     public abstract Surface getSurface();
 
     public abstract VideoViewSnapshot getVideoViewSnapshot();
 
+    public boolean hasLooper() {
+        return Looper.myLooper() != null;
+    }
+
 }
 
 /* Factory for building a {@link TextureView}. */
@@ -555,6 +574,7 @@
 
     @Override
     public TextureView createView(Context context) {
+        Log.i(TAG, "Creating a " + NAME);
         textureView = DecodeAccuracyTestBase.checkNotNull(new TextureView(context));
         textureView.setSurfaceTextureListener(this);
         return textureView;
@@ -581,16 +601,22 @@
     }
 
     @Override
-    public void waitForViewIsAvailable() {
-        while (!textureView.isAvailable()) {
+    public void waitForViewIsAvailable(long timeOutMs) throws Exception {
+        final long start = SystemClock.elapsedRealtime();
+        while (SystemClock.elapsedRealtime() - start < timeOutMs && !textureView.isAvailable()) {
             synchronized (syncToken) {
                 try {
-                    syncToken.wait(VIEW_AVAILABLE_TIMEOUT_MS);
-                } catch (InterruptedException exception) {
-                    Log.e(TAG, "Taking too long to attach a TextureView to a window.", exception);
+                    syncToken.wait(VIEW_WAITTIME_MS);
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "Exception occurred when attaching a TextureView to a window.", e);
+                    throw new InterruptedException(e.getMessage());
                 }
             }
         }
+        if (!textureView.isAvailable()) {
+            throw new InterruptedException("Taking too long to attach a TextureView to a window.");
+        }
+        Log.i(TAG, NAME + " is available.");
     }
 
     @Override
@@ -646,7 +672,10 @@
 
     @Override
     public View createView(Context context) {
-        Looper.prepare();
+        Log.i(TAG, "Creating a " + NAME);
+        if (!super.hasLooper()) {
+            Looper.prepare();
+        }
         surfaceView = new SurfaceView(context);
         surfaceHolder = surfaceView.getHolder();
         surfaceHolder.addCallback(this);
@@ -654,16 +683,22 @@
     }
 
     @Override
-    public void waitForViewIsAvailable() {
-        while (!getSurface().isValid()) {
+    public void waitForViewIsAvailable(long timeOutMs) throws Exception {
+        final long start = SystemClock.elapsedRealtime();
+        while (SystemClock.elapsedRealtime() - start < timeOutMs && !getSurface().isValid()) {
             synchronized (syncToken) {
                 try {
-                    syncToken.wait(VIEW_AVAILABLE_TIMEOUT_MS);
-                } catch (InterruptedException exception) {
-                    Log.e(TAG, "Taking too long to attach a SurfaceView to a window.", exception);
+                    syncToken.wait(VIEW_WAITTIME_MS);
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "Exception occurred when attaching a SurfaceView to a window.", e);
+                    throw new InterruptedException(e.getMessage());
                 }
             }
         }
+        if (!getSurface().isValid()) {
+            throw new InterruptedException("Taking too long to attach a SurfaceView to a window.");
+        }
+        Log.i(TAG, NAME + " is available.");
     }
 
     @Override
@@ -722,6 +757,7 @@
 
     @Override
     public View createView(Context context) {
+        Log.i(TAG, "Creating a " + NAME);
         // Do all GL rendering in the GL thread.
         glSurfaceViewThread = new GLSurfaceViewThread();
         glSurfaceViewThread.start();
@@ -730,16 +766,25 @@
     }
 
     @Override
-    public void waitForViewIsAvailable() {
-        while (glSurfaceViewThread.getSurface() == null) {
+    public void waitForViewIsAvailable(long timeOutMs) throws Exception {
+        final long start = SystemClock.elapsedRealtime();
+        while (SystemClock.elapsedRealtime() - start < timeOutMs
+                && glSurfaceViewThread.getSurface() == null) {
             synchronized (surfaceSyncToken) {
                 try {
-                    surfaceSyncToken.wait(VIEW_AVAILABLE_TIMEOUT_MS);
-                } catch (InterruptedException exception) {
-                    Log.e(TAG, "Taking too long for the surface to become available.", exception);
+                    surfaceSyncToken.wait(VIEW_WAITTIME_MS);
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "Exception occurred when waiting for the surface from"
+                            + " GLSurfaceView to become available.", e);
+                    throw new InterruptedException(e.getMessage());
                 }
             }
         }
+        if (glSurfaceViewThread.getSurface() == null) {
+            throw new InterruptedException("Taking too long for the surface from"
+                    + " GLSurfaceView to become available.");
+        }
+        Log.i(TAG, NAME + " is available.");
     }
 
     @Override
@@ -1144,8 +1189,8 @@
                         }
                         Thread.sleep(PIXELCOPY_REQUEST_SLEEP_MS);
                     }
-                } catch (InterruptedException ex) {
-                    Log.w(TAG, "Pixel Copy is stopped/interrupted before it finishes", ex);
+                } catch (InterruptedException e) {
+                    Log.w(TAG, "Pixel Copy is stopped/interrupted before it finishes.", e);
                 }
                 copyHelper.release();
             }
@@ -1191,8 +1236,13 @@
 
         public int request(SurfaceView source, Bitmap dest) {
             synchronized (this) {
-                PixelCopy.request(source, dest, this, handler);
-                return getResultLocked();
+                try {
+                    PixelCopy.request(source, dest, this, handler);
+                    return getResultLocked();
+                } catch (Exception e) {
+                    Log.e(TAG, "Exception occurred when copying a SurfaceView.", e);
+                    return -1;
+                }
             }
         }
 
@@ -1243,8 +1293,8 @@
     public synchronized void run() {
         try {
             waitForByteBuffer();
-        } catch (InterruptedException exception) {
-            Log.w(TAG, exception.getMessage());
+        } catch (InterruptedException e) {
+            Log.w(TAG, e.getMessage());
             Log.w(TAG, "ByteBuffer may contain incorrect pixels.");
         }
         // Get ByteBuffer anyway. Let the test fail if ByteBuffer contains incorrect pixels.