blob: 379fad5e5bbf72682e6e8e79756d90d9beb5edf2 [file] [log] [blame]
/*
* Copyright (C) 2018 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 android.hardware.cts;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.ErrorCallback;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.PreviewCallback;
import android.os.Looper;
import android.util.Log;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class CameraPerformanceTestHelper {
private static final String TAG = "CameraTestCase";
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
public static final int NO_ERROR = -1;
public static final long WAIT_FOR_COMMAND_TO_COMPLETE_NS = 5000000000L;
public static final long WAIT_FOR_FOCUS_TO_COMPLETE_NS = 5000000000L;
public static final long WAIT_FOR_SNAPSHOT_TO_COMPLETE_NS = 5000000000L;
private Looper mLooper = null;
private int mCameraErrorCode;
private Camera mCamera;
/**
* Initializes the message looper so that the Camera object can
* receive the callback messages.
*/
public void initializeMessageLooper(final int cameraId) throws InterruptedException {
Lock startLock = new ReentrantLock();
Condition startDone = startLock.newCondition();
mCameraErrorCode = NO_ERROR;
new Thread() {
@Override
public void run() {
// Set up a looper to be used by camera.
Looper.prepare();
// Save the looper so that we can terminate this thread
// after we are done with it.
mLooper = Looper.myLooper();
try {
mCamera = Camera.open(cameraId);
mCamera.setErrorCallback(new ErrorCallback() {
@Override
public void onError(int error, Camera camera) {
mCameraErrorCode = error;
}
});
} catch (RuntimeException e) {
Log.e(TAG, "Fail to open camera." + e);
}
startLock.lock();
startDone.signal();
startLock.unlock();
Looper.loop(); // Blocks forever until Looper.quit() is called.
if (VERBOSE) Log.v(TAG, "initializeMessageLooper: quit.");
}
}.start();
startLock.lock();
try {
assertTrue(
"initializeMessageLooper: start timeout",
startDone.awaitNanos(WAIT_FOR_COMMAND_TO_COMPLETE_NS) > 0L);
} finally {
startLock.unlock();
}
assertNotNull("Fail to open camera.", mCamera);
}
/**
* Terminates the message looper thread, optionally allowing evict error
*/
public void terminateMessageLooper() throws Exception {
mLooper.quit();
// Looper.quit() is asynchronous. The looper may still has some
// preview callbacks in the queue after quit is called. The preview
// callback still uses the camera object (setHasPreviewCallback).
// After camera is released, RuntimeException will be thrown from
// the method. So we need to join the looper thread here.
mLooper.getThread().join();
mCamera.release();
mCamera = null;
assertEquals("Got camera error callback.", NO_ERROR, mCameraErrorCode);
}
/**
* Start preview and wait for the first preview callback, which indicates the
* preview becomes active.
*/
public void startPreview() throws InterruptedException {
Lock previewLock = new ReentrantLock();
Condition previewDone = previewLock.newCondition();
mCamera.setPreviewCallback(new PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, android.hardware.Camera camera) {
previewLock.lock();
previewDone.signal();
previewLock.unlock();
}
});
mCamera.startPreview();
previewLock.lock();
try {
assertTrue(
"Preview done timeout",
previewDone.awaitNanos(WAIT_FOR_COMMAND_TO_COMPLETE_NS) > 0L);
} finally {
previewLock.unlock();
}
mCamera.setPreviewCallback(null);
}
/**
* Trigger and wait for autofocus to complete.
*/
public void autoFocus() throws InterruptedException {
Lock focusLock = new ReentrantLock();
Condition focusDone = focusLock.newCondition();
mCamera.autoFocus(new AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
focusLock.lock();
focusDone.signal();
focusLock.unlock();
}
});
focusLock.lock();
try {
assertTrue(
"Autofocus timeout",
focusDone.awaitNanos(WAIT_FOR_FOCUS_TO_COMPLETE_NS) > 0L);
} finally {
focusLock.unlock();
}
}
/**
* Trigger and wait for snapshot to finish.
*/
public void takePicture() throws InterruptedException {
Lock snapshotLock = new ReentrantLock();
Condition snapshotDone = snapshotLock.newCondition();
mCamera.takePicture(/*shutterCallback*/ null, /*rawPictureCallback*/ null,
new PictureCallback() {
@Override
public void onPictureTaken(byte[] rawData, Camera camera) {
snapshotLock.lock();
try {
assertNotNull("Empty jpeg data", rawData);
snapshotDone.signal();
} finally {
snapshotLock.unlock();
}
}
});
snapshotLock.lock();
try {
assertTrue(
"TakePicture timeout",
snapshotDone.awaitNanos(WAIT_FOR_SNAPSHOT_TO_COMPLETE_NS) > 0L);
} finally {
snapshotLock.unlock();
}
}
public Camera getCamera() {
return mCamera;
}
}