Merge \"CameraIts: Use wait and notify for callback counter\" into marshmallow-cts-dev
am: 9fcf2d17e5

Change-Id: I002b093f6435f12a2b1fb976a72aac390b89b15c
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index 1234b20..9a1b89e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -97,9 +97,6 @@
     private static final int TIMEOUT_CALLBACK = 10;
     private static final int TIMEOUT_3A = 10;
 
-    // Timeout for doCapture command polling
-    private static final int TIMEOUT_POLL_MS = 500;
-
     // Time given for background requests to warm up pipeline
     private static final long PIPELINE_WARMUP_TIME_MS = 2000;
 
@@ -1176,6 +1173,29 @@
         prepareImageReaders(outputSizes, outputFormats, inputSize, inputFormat, maxInputBuffers);
     }
 
+    /**
+     * Wait until mCountCallbacksRemaining is 0 or a specified amount of time has elapsed between
+     * each callback.
+     */
+    private void waitForCallbacks(long timeoutMs) throws ItsException {
+        synchronized(mCountCallbacksRemaining) {
+            int currentCount = mCountCallbacksRemaining.get();
+            while (currentCount > 0) {
+                try {
+                    mCountCallbacksRemaining.wait(timeoutMs);
+                } catch (InterruptedException e) {
+                    throw new ItsException("Waiting for callbacks was interrupted.", e);
+                }
+
+                int newCount = mCountCallbacksRemaining.get();
+                if (newCount == currentCount) {
+                    throw new ItsException("No callback received within timeout");
+                }
+                currentCount = newCount;
+            }
+        }
+    }
+
     private void doCapture(JSONObject params) throws ItsException {
         try {
             // Parse the JSON to get the list of capture requests.
@@ -1275,24 +1295,7 @@
             }
             // Make sure all callbacks have been hit (wait until captures are done).
             // If no timeouts are received after a timeout, then fail.
-            int currentCount = mCountCallbacksRemaining.get();
-            long totalSleep = 0;
-            while (currentCount > 0) {
-                try {
-                    Thread.sleep(TIMEOUT_POLL_MS);
-                } catch (InterruptedException e) {
-                    throw new ItsException("Timeout failure", e);
-                }
-                totalSleep += TIMEOUT_POLL_MS;
-                int newCount = mCountCallbacksRemaining.get();
-                if (newCount == currentCount && totalSleep > timeout) {
-                    throw new ItsException(
-                            "No callback received within timeout");
-                } else if (newCount < currentCount) {
-                    totalSleep = 0;
-                }
-                currentCount = newCount;
-            }
+            waitForCallbacks(timeout);
 
             // Close session and wait until session is fully closed
             mSession.close();
@@ -1431,6 +1434,12 @@
                         mSaveHandlers[i]);
             }
 
+            // Plan for how many callbacks need to be received throughout the duration of this
+            // sequence of capture requests. There is one callback per image surface, and one
+            // callback for the CaptureResult, for each capture.
+            int numCaptures = reprocessOutputRequests.size();
+            mCountCallbacksRemaining.set(numCaptures * (numOutputSurfaces + 1));
+
             // Initiate the captures.
             for (int i = 0; i < reprocessOutputRequests.size(); i++) {
                 CaptureRequest.Builder req = reprocessOutputRequests.get(i);
@@ -1446,28 +1455,9 @@
                 mSession.capture(req.build(), mCaptureResultListener, mResultHandler);
             }
 
-            // Plan for how many callbacks need to be received throughout the duration of this
-            // sequence of capture requests. There is one callback per image surface, and one
-            // callback for the CaptureResult, for each capture.
-            int numCaptures = reprocessOutputRequests.size();
-            mCountCallbacksRemaining.set(numCaptures * (numOutputSurfaces + 1));
-
             // Make sure all callbacks have been hit (wait until captures are done).
             // If no timeouts are received after a timeout, then fail.
-            int currentCount = mCountCallbacksRemaining.get();
-            while (currentCount > 0) {
-                try {
-                    Thread.sleep(TIMEOUT_CALLBACK*1000);
-                } catch (InterruptedException e) {
-                    throw new ItsException("Timeout failure", e);
-                }
-                int newCount = mCountCallbacksRemaining.get();
-                if (newCount == currentCount) {
-                    throw new ItsException(
-                            "No callback received within timeout");
-                }
-                currentCount = newCount;
-            }
+            waitForCallbacks(TIMEOUT_CALLBACK * 1000);
         } catch (android.hardware.camera2.CameraAccessException e) {
             throw new ItsException("Access error: ", e);
         } finally {
@@ -1593,7 +1583,11 @@
                 } else {
                     throw new ItsException("Unsupported image format: " + format);
                 }
-                mCountCallbacksRemaining.decrementAndGet();
+
+                synchronized(mCountCallbacksRemaining) {
+                    mCountCallbacksRemaining.decrementAndGet();
+                    mCountCallbacksRemaining.notify();
+                }
             } catch (IOException e) {
                 Logt.e(TAG, "Script error: ", e);
             } catch (InterruptedException e) {
@@ -1764,7 +1758,10 @@
                     mCaptureResults[count] = result;
                     mSocketRunnableObj.sendResponseCaptureResult(mCameraCharacteristics,
                             request, result, mOutputImageReaders);
-                    mCountCallbacksRemaining.decrementAndGet();
+                    synchronized(mCountCallbacksRemaining) {
+                        mCountCallbacksRemaining.decrementAndGet();
+                        mCountCallbacksRemaining.notify();
+                    }
                 }
             } catch (ItsException e) {
                 Logt.e(TAG, "Script error: ", e);