Loading core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl +4 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ interface ICameraDeviceCallbacks * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h */ oneway void notifyCallback(int msgType, int ext1, int ext2); oneway void onResultReceived(int frameId, in CameraMetadataNative result); oneway void onCameraError(int errorCode); oneway void onCameraIdle(); oneway void onCaptureStarted(int requestId, long timestamp); oneway void onResultReceived(int requestId, in CameraMetadataNative result); } core/java/android/hardware/camera2/impl/CameraDevice.java +120 −13 Original line number Diff line number Diff line Loading @@ -183,13 +183,8 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { // Need a valid handler, or current thread needs to have a looper, if // listener is valid if (handler == null && listener != null) { Looper looper = Looper.myLooper(); if (looper == null) { throw new IllegalArgumentException( "No handler given, and current thread has no looper!"); } handler = new Handler(looper); if (listener != null) { handler = checkHandler(handler); } synchronized (mLock) { Loading Loading @@ -277,6 +272,10 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { @Override public void setDeviceListener(StateListener listener, Handler handler) { synchronized (mLock) { if (listener != null) { handler = checkHandler(handler); } mDeviceListener = listener; mDeviceHandler = handler; } Loading Loading @@ -365,21 +364,113 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } // TODO: unit tests public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub { // // Constants below need to be kept up-to-date with // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h // // // Error codes for onCameraError // /** * Camera has been disconnected */ static final int ERROR_CAMERA_DISCONNECTED = 0; /** * Camera has encountered a device-level error * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE */ static final int ERROR_CAMERA_DEVICE = 1; /** * Camera has encountered a service-level error * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE */ static final int ERROR_CAMERA_SERVICE = 2; @Override public IBinder asBinder() { return this; } // TODO: consider rename to onMessageReceived @Override public void notifyCallback(int msgType, int ext1, int ext2) throws RemoteException { public void onCameraError(final int errorCode) { synchronized (mLock) { if (CameraDevice.this.mDeviceListener == null) return; final StateListener listener = CameraDevice.this.mDeviceListener; Runnable r = null; switch (errorCode) { case ERROR_CAMERA_DISCONNECTED: r = new Runnable() { public void run() { listener.onDisconnected(CameraDevice.this); } }; break; case ERROR_CAMERA_DEVICE: case ERROR_CAMERA_SERVICE: r = new Runnable() { public void run() { listener.onError(CameraDevice.this, errorCode); } }; break; default: Log.e(TAG, "Unknown error from camera device: " + errorCode); } if (r != null) { CameraDevice.this.mDeviceHandler.post(r); } } } @Override public void onCameraIdle() { if (DEBUG) { Log.d(TAG, "Camera now idle"); } synchronized (mLock) { if (CameraDevice.this.mDeviceListener == null) return; final StateListener listener = CameraDevice.this.mDeviceListener; Runnable r = new Runnable() { public void run() { listener.onIdle(CameraDevice.this); } }; CameraDevice.this.mDeviceHandler.post(r); } } @Override public void onCaptureStarted(int requestId, final long timestamp) { if (DEBUG) { Log.d(TAG, "Got message " + msgType + " ext1: " + ext1 + " , ext2: " + ext2); Log.d(TAG, "Capture started for id " + requestId); } final CaptureListenerHolder holder; // Get the listener for this frame ID, if there is one synchronized (mLock) { holder = CameraDevice.this.mCaptureListenerMap.get(requestId); } if (holder == null) { return; } // Dispatch capture start notice holder.getHandler().post( new Runnable() { public void run() { holder.getListener().onCaptureStarted( CameraDevice.this, holder.getRequest(), timestamp); } // TODO implement rest }); } @Override Loading Loading @@ -429,6 +520,22 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } /** * Default handler management. If handler is null, get the current thread's * Looper to create a Handler with. If no looper exists, throw exception. */ private Handler checkHandler(Handler handler) { if (handler == null) { Looper looper = Looper.myLooper(); if (looper == null) { throw new IllegalArgumentException( "No handler given, and current thread has no looper!"); } handler = new Handler(looper); } return handler; } private void checkIfCameraClosed() { if (mRemoteDevice == null) { throw new IllegalStateException("CameraDevice was already closed"); Loading core/java/android/hardware/camera2/impl/CameraMetadataNative.java +0 −1 Original line number Diff line number Diff line Loading @@ -652,7 +652,6 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { * We use a class initializer to allow the native code to cache some field offsets */ static { System.loadLibrary("media_jni"); nativeClassInit(); Log.v(TAG, "Shall register metadata marshalers"); Loading media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java +11 −2 Original line number Diff line number Diff line Loading @@ -152,11 +152,20 @@ public class CameraBinderTest extends AndroidTestCase { static class DummyCameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub { @Override public void notifyCallback(int msgType, int ext1, int ext2) throws RemoteException { public void onCameraError(int errorCode) { } @Override public void onResultReceived(int frameId, CameraMetadataNative result) throws RemoteException { public void onCameraIdle() { } @Override public void onCaptureStarted(int requestId, long timestamp) { } @Override public void onResultReceived(int frameId, CameraMetadataNative result) throws RemoteException { } } Loading media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java +88 −4 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.media.ImageReader; import android.os.Handler; import android.os.HandlerThread; import android.os.RemoteException; import android.os.SystemClock; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; Loading @@ -40,6 +41,7 @@ import static android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW; import com.android.mediaframeworktest.MediaFrameworkIntegrationTestRunner; import org.mockito.ArgumentMatcher; import org.mockito.ArgumentCaptor; import static org.mockito.Mockito.*; public class CameraDeviceBinderTest extends AndroidTestCase { Loading @@ -48,6 +50,12 @@ public class CameraDeviceBinderTest extends AndroidTestCase { private static int NUM_CALLBACKS_CHECKED = 10; // Wait for capture result timeout value: 1500ms private final static int WAIT_FOR_COMPLETE_TIMEOUT_MS = 1500; // Wait for flush timeout value: 1000ms private final static int WAIT_FOR_FLUSH_TIMEOUT_MS = 1000; // Wait for idle timeout value: 2000ms private final static int WAIT_FOR_IDLE_TIMEOUT_MS = 2000; // Wait while camera device starts working on requests private final static int WAIT_FOR_WORK_MS = 300; // Default size is VGA, which is mandatory camera supported image size by CDD. private static final int DEFAULT_IMAGE_WIDTH = 640; private static final int DEFAULT_IMAGE_HEIGHT = 480; Loading Loading @@ -77,11 +85,19 @@ public class CameraDeviceBinderTest extends AndroidTestCase { public class DummyCameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub { @Override public void notifyCallback(int msgType, int ext1, int ext2) throws RemoteException { public void onCameraError(int errorCode) { } @Override public void onResultReceived(int frameId, CameraMetadataNative result) throws RemoteException { public void onCameraIdle() { } @Override public void onCaptureStarted(int requestId, long timestamp) { } @Override public void onResultReceived(int frameId, CameraMetadataNative result) { } } Loading Loading @@ -345,6 +361,60 @@ public class CameraDeviceBinderTest extends AndroidTestCase { argThat(matcher)); } @SmallTest public void testCaptureStartedCallbacks() throws Exception { CaptureRequest request = createDefaultBuilder(/* needStream */true).build(); ArgumentCaptor<Long> timestamps = ArgumentCaptor.forClass(Long.class); // Test both single request and streaming request. int requestId1 = submitCameraRequest(request, /* streaming */false); verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).times(1)).onCaptureStarted( eq(requestId1), anyLong()); int streamingId = submitCameraRequest(request, /* streaming */true); verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).atLeast(NUM_CALLBACKS_CHECKED)) .onCaptureStarted( eq(streamingId), timestamps.capture()); long timestamp = 0; // All timestamps should be larger than 0. for (Long nextTimestamp : timestamps.getAllValues()) { Log.v(TAG, "next t: " + nextTimestamp + " current t: " + timestamp); assertTrue("Captures are out of order", timestamp < nextTimestamp); timestamp = nextTimestamp; } } @SmallTest public void testIdleCallback() throws Exception { int status; CaptureRequest request = createDefaultBuilder(/* needStream */true).build(); // Try streaming int streamingId = submitCameraRequest(request, /* streaming */true); // Wait a bit to fill up the queue SystemClock.sleep(WAIT_FOR_WORK_MS); // Cancel and make sure we eventually quiesce status = mCameraUser.cancelRequest(streamingId); verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(1)).onCameraIdle(); // Submit a few capture requests int requestId1 = submitCameraRequest(request, /* streaming */false); int requestId2 = submitCameraRequest(request, /* streaming */false); int requestId3 = submitCameraRequest(request, /* streaming */false); int requestId4 = submitCameraRequest(request, /* streaming */false); int requestId5 = submitCameraRequest(request, /* streaming */false); // And wait for more idle verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(2)).onCameraIdle(); } @SmallTest public void testFlush() throws Exception { int status; Loading @@ -367,10 +437,24 @@ public class CameraDeviceBinderTest extends AndroidTestCase { int requestId4 = submitCameraRequest(request, /* streaming */false); int requestId5 = submitCameraRequest(request, /* streaming */false); // Then flush // Then flush and wait for idle status = mCameraUser.flush(); assertEquals(CameraBinderTestUtils.NO_ERROR, status); verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(1)).onCameraIdle(); // Now a streaming request int streamingId = submitCameraRequest(request, /* streaming */true); // Wait a bit to fill up the queue SystemClock.sleep(WAIT_FOR_WORK_MS); // Then flush and wait for the idle callback status = mCameraUser.flush(); assertEquals(CameraBinderTestUtils.NO_ERROR, status); verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(2)).onCameraIdle(); // TODO: When errors are hooked up, count that errors + successful // requests equal to 5. } Loading Loading
core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl +4 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ interface ICameraDeviceCallbacks * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h */ oneway void notifyCallback(int msgType, int ext1, int ext2); oneway void onResultReceived(int frameId, in CameraMetadataNative result); oneway void onCameraError(int errorCode); oneway void onCameraIdle(); oneway void onCaptureStarted(int requestId, long timestamp); oneway void onResultReceived(int requestId, in CameraMetadataNative result); }
core/java/android/hardware/camera2/impl/CameraDevice.java +120 −13 Original line number Diff line number Diff line Loading @@ -183,13 +183,8 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { // Need a valid handler, or current thread needs to have a looper, if // listener is valid if (handler == null && listener != null) { Looper looper = Looper.myLooper(); if (looper == null) { throw new IllegalArgumentException( "No handler given, and current thread has no looper!"); } handler = new Handler(looper); if (listener != null) { handler = checkHandler(handler); } synchronized (mLock) { Loading Loading @@ -277,6 +272,10 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { @Override public void setDeviceListener(StateListener listener, Handler handler) { synchronized (mLock) { if (listener != null) { handler = checkHandler(handler); } mDeviceListener = listener; mDeviceHandler = handler; } Loading Loading @@ -365,21 +364,113 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } // TODO: unit tests public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub { // // Constants below need to be kept up-to-date with // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h // // // Error codes for onCameraError // /** * Camera has been disconnected */ static final int ERROR_CAMERA_DISCONNECTED = 0; /** * Camera has encountered a device-level error * Matches CameraDevice.StateListener#ERROR_CAMERA_DEVICE */ static final int ERROR_CAMERA_DEVICE = 1; /** * Camera has encountered a service-level error * Matches CameraDevice.StateListener#ERROR_CAMERA_SERVICE */ static final int ERROR_CAMERA_SERVICE = 2; @Override public IBinder asBinder() { return this; } // TODO: consider rename to onMessageReceived @Override public void notifyCallback(int msgType, int ext1, int ext2) throws RemoteException { public void onCameraError(final int errorCode) { synchronized (mLock) { if (CameraDevice.this.mDeviceListener == null) return; final StateListener listener = CameraDevice.this.mDeviceListener; Runnable r = null; switch (errorCode) { case ERROR_CAMERA_DISCONNECTED: r = new Runnable() { public void run() { listener.onDisconnected(CameraDevice.this); } }; break; case ERROR_CAMERA_DEVICE: case ERROR_CAMERA_SERVICE: r = new Runnable() { public void run() { listener.onError(CameraDevice.this, errorCode); } }; break; default: Log.e(TAG, "Unknown error from camera device: " + errorCode); } if (r != null) { CameraDevice.this.mDeviceHandler.post(r); } } } @Override public void onCameraIdle() { if (DEBUG) { Log.d(TAG, "Camera now idle"); } synchronized (mLock) { if (CameraDevice.this.mDeviceListener == null) return; final StateListener listener = CameraDevice.this.mDeviceListener; Runnable r = new Runnable() { public void run() { listener.onIdle(CameraDevice.this); } }; CameraDevice.this.mDeviceHandler.post(r); } } @Override public void onCaptureStarted(int requestId, final long timestamp) { if (DEBUG) { Log.d(TAG, "Got message " + msgType + " ext1: " + ext1 + " , ext2: " + ext2); Log.d(TAG, "Capture started for id " + requestId); } final CaptureListenerHolder holder; // Get the listener for this frame ID, if there is one synchronized (mLock) { holder = CameraDevice.this.mCaptureListenerMap.get(requestId); } if (holder == null) { return; } // Dispatch capture start notice holder.getHandler().post( new Runnable() { public void run() { holder.getListener().onCaptureStarted( CameraDevice.this, holder.getRequest(), timestamp); } // TODO implement rest }); } @Override Loading Loading @@ -429,6 +520,22 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } /** * Default handler management. If handler is null, get the current thread's * Looper to create a Handler with. If no looper exists, throw exception. */ private Handler checkHandler(Handler handler) { if (handler == null) { Looper looper = Looper.myLooper(); if (looper == null) { throw new IllegalArgumentException( "No handler given, and current thread has no looper!"); } handler = new Handler(looper); } return handler; } private void checkIfCameraClosed() { if (mRemoteDevice == null) { throw new IllegalStateException("CameraDevice was already closed"); Loading
core/java/android/hardware/camera2/impl/CameraMetadataNative.java +0 −1 Original line number Diff line number Diff line Loading @@ -652,7 +652,6 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { * We use a class initializer to allow the native code to cache some field offsets */ static { System.loadLibrary("media_jni"); nativeClassInit(); Log.v(TAG, "Shall register metadata marshalers"); Loading
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java +11 −2 Original line number Diff line number Diff line Loading @@ -152,11 +152,20 @@ public class CameraBinderTest extends AndroidTestCase { static class DummyCameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub { @Override public void notifyCallback(int msgType, int ext1, int ext2) throws RemoteException { public void onCameraError(int errorCode) { } @Override public void onResultReceived(int frameId, CameraMetadataNative result) throws RemoteException { public void onCameraIdle() { } @Override public void onCaptureStarted(int requestId, long timestamp) { } @Override public void onResultReceived(int frameId, CameraMetadataNative result) throws RemoteException { } } Loading
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java +88 −4 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.media.ImageReader; import android.os.Handler; import android.os.HandlerThread; import android.os.RemoteException; import android.os.SystemClock; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; Loading @@ -40,6 +41,7 @@ import static android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW; import com.android.mediaframeworktest.MediaFrameworkIntegrationTestRunner; import org.mockito.ArgumentMatcher; import org.mockito.ArgumentCaptor; import static org.mockito.Mockito.*; public class CameraDeviceBinderTest extends AndroidTestCase { Loading @@ -48,6 +50,12 @@ public class CameraDeviceBinderTest extends AndroidTestCase { private static int NUM_CALLBACKS_CHECKED = 10; // Wait for capture result timeout value: 1500ms private final static int WAIT_FOR_COMPLETE_TIMEOUT_MS = 1500; // Wait for flush timeout value: 1000ms private final static int WAIT_FOR_FLUSH_TIMEOUT_MS = 1000; // Wait for idle timeout value: 2000ms private final static int WAIT_FOR_IDLE_TIMEOUT_MS = 2000; // Wait while camera device starts working on requests private final static int WAIT_FOR_WORK_MS = 300; // Default size is VGA, which is mandatory camera supported image size by CDD. private static final int DEFAULT_IMAGE_WIDTH = 640; private static final int DEFAULT_IMAGE_HEIGHT = 480; Loading Loading @@ -77,11 +85,19 @@ public class CameraDeviceBinderTest extends AndroidTestCase { public class DummyCameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub { @Override public void notifyCallback(int msgType, int ext1, int ext2) throws RemoteException { public void onCameraError(int errorCode) { } @Override public void onResultReceived(int frameId, CameraMetadataNative result) throws RemoteException { public void onCameraIdle() { } @Override public void onCaptureStarted(int requestId, long timestamp) { } @Override public void onResultReceived(int frameId, CameraMetadataNative result) { } } Loading Loading @@ -345,6 +361,60 @@ public class CameraDeviceBinderTest extends AndroidTestCase { argThat(matcher)); } @SmallTest public void testCaptureStartedCallbacks() throws Exception { CaptureRequest request = createDefaultBuilder(/* needStream */true).build(); ArgumentCaptor<Long> timestamps = ArgumentCaptor.forClass(Long.class); // Test both single request and streaming request. int requestId1 = submitCameraRequest(request, /* streaming */false); verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).times(1)).onCaptureStarted( eq(requestId1), anyLong()); int streamingId = submitCameraRequest(request, /* streaming */true); verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).atLeast(NUM_CALLBACKS_CHECKED)) .onCaptureStarted( eq(streamingId), timestamps.capture()); long timestamp = 0; // All timestamps should be larger than 0. for (Long nextTimestamp : timestamps.getAllValues()) { Log.v(TAG, "next t: " + nextTimestamp + " current t: " + timestamp); assertTrue("Captures are out of order", timestamp < nextTimestamp); timestamp = nextTimestamp; } } @SmallTest public void testIdleCallback() throws Exception { int status; CaptureRequest request = createDefaultBuilder(/* needStream */true).build(); // Try streaming int streamingId = submitCameraRequest(request, /* streaming */true); // Wait a bit to fill up the queue SystemClock.sleep(WAIT_FOR_WORK_MS); // Cancel and make sure we eventually quiesce status = mCameraUser.cancelRequest(streamingId); verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(1)).onCameraIdle(); // Submit a few capture requests int requestId1 = submitCameraRequest(request, /* streaming */false); int requestId2 = submitCameraRequest(request, /* streaming */false); int requestId3 = submitCameraRequest(request, /* streaming */false); int requestId4 = submitCameraRequest(request, /* streaming */false); int requestId5 = submitCameraRequest(request, /* streaming */false); // And wait for more idle verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(2)).onCameraIdle(); } @SmallTest public void testFlush() throws Exception { int status; Loading @@ -367,10 +437,24 @@ public class CameraDeviceBinderTest extends AndroidTestCase { int requestId4 = submitCameraRequest(request, /* streaming */false); int requestId5 = submitCameraRequest(request, /* streaming */false); // Then flush // Then flush and wait for idle status = mCameraUser.flush(); assertEquals(CameraBinderTestUtils.NO_ERROR, status); verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(1)).onCameraIdle(); // Now a streaming request int streamingId = submitCameraRequest(request, /* streaming */true); // Wait a bit to fill up the queue SystemClock.sleep(WAIT_FOR_WORK_MS); // Then flush and wait for the idle callback status = mCameraUser.flush(); assertEquals(CameraBinderTestUtils.NO_ERROR, status); verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(2)).onCameraIdle(); // TODO: When errors are hooked up, count that errors + successful // requests equal to 5. } Loading