Camera: ProCamera - add createStream stub and unit test for it

Change-Id: Ic05130e63f4f2c0c3278ba348b192992169f105f
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index 8164188..26e4de9 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -261,4 +261,72 @@
     return c->cancelStream(streamId);
 }
 
+status_t ProCamera::createStream(int width, int height, int format,
+                          const sp<ANativeWindow>& window,
+                          /*out*/
+                          int* streamId)
+{
+    *streamId = -1;
+
+    ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
+                                                                       format);
+
+    if (window == 0) {
+        return BAD_VALUE;
+    }
+
+    // TODO: actually implement this in IProCamera
+    return INVALID_OPERATION;
+}
+
+status_t ProCamera::createStream(int width, int height, int format,
+                          const sp<IGraphicBufferProducer>& bufferProducer,
+                          /*out*/
+                          int* streamId) {
+
+    ALOGV("%s: createStreamT %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
+                                                                       format);
+
+    sp<IBinder> binder;
+    sp<ANativeWindow> window;
+
+    if (bufferProducer != 0) {
+        binder = bufferProducer->asBinder();
+        window = new Surface(bufferProducer);
+
+        status_t stat = createStream(width, height, format, window, streamId);
+
+        ALOGV("%s: createStreamT END (%d), StreamID = %d", __FUNCTION__, stat,
+                                                                    *streamId);
+    }
+    else {
+        *streamId = -1;
+        return BAD_VALUE;
+    }
+
+    return BAD_VALUE;
+}
+
+int ProCamera::getNumberOfCameras() {
+    ALOGE("%s: not implemented yet", __FUNCTION__);
+    return 1;
+}
+
+camera_metadata* ProCamera::getCameraInfo(int cameraId) {
+    ALOGE("%s: not implemented yet", __FUNCTION__);
+
+    ALOGV("%s: cameraId = %d", __FUNCTION__, cameraId);
+    return NULL;
+}
+
+status_t ProCamera::createDefaultRequest(int templateId,
+                                             camera_metadata** request) const {
+    ALOGE("%s: not implemented yet", __FUNCTION__);
+
+    ALOGV("%s: templateId = %d", __FUNCTION__, templateId);
+
+    *request = NULL;
+    return INVALID_OPERATION;
+}
+
 }; // namespace android
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index adc3c75..d632b7e 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -26,6 +26,12 @@
 #include <utils/Mutex.h>
 #include <utils/Condition.h>
 
+#include <gui/SurfaceComposerClient.h>
+#include <gui/Surface.h>
+
+#include <system/camera_metadata.h>
+#include <hardware/camera2.h> // for CAMERA2_TEMPLATE_PREVIEW only
+
 namespace android {
 namespace camera2 {
 namespace tests {
@@ -34,7 +40,8 @@
 #define CAMERA_ID 0
 #define TEST_DEBUGGING 0
 
-#define TEST_LISTENER_TIMEOUT 2000000000 // 2 second listener timeout
+#define TEST_LISTENER_TIMEOUT 1000000000 // 1 second listener timeout
+#define TEST_FORMAT HAL_PIXEL_FORMAT_RGBA_8888 //TODO: YUY2 instead
 
 #if TEST_DEBUGGING
 #define dout std::cerr
@@ -206,6 +213,40 @@
 
     static sp<Thread> mTestThread;
 
+    int mDisplaySecs;
+    sp<SurfaceComposerClient> mComposerClient;
+    sp<SurfaceControl> mSurfaceControl;
+
+    int getSurfaceWidth() {
+        return 512;
+    }
+    int getSurfaceHeight() {
+        return 512;
+    }
+
+    void createOnScreenSurface(sp<Surface>& surface) {
+        mComposerClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+        mSurfaceControl = mComposerClient->createSurface(
+                String8("ProCameraTest StreamingImage Surface"),
+                getSurfaceWidth(), getSurfaceHeight(),
+                PIXEL_FORMAT_RGB_888, 0);
+
+        ASSERT_TRUE(mSurfaceControl != NULL);
+        ASSERT_TRUE(mSurfaceControl->isValid());
+
+        SurfaceComposerClient::openGlobalTransaction();
+        ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
+        ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
+        SurfaceComposerClient::closeGlobalTransaction();
+
+        sp<ANativeWindow> window = mSurfaceControl->getSurface();
+        surface = mSurfaceControl->getSurface();
+
+        ASSERT_NE((void*)NULL, surface.get());
+    }
+
 };
 
 sp<Thread> ProCameraTest::mTestThread;
@@ -260,6 +301,75 @@
     EXPECT_FALSE(mCamera->hasExclusiveLock());
 }
 
+// Stream directly to the screen.
+TEST_F(ProCameraTest, StreamingImage) {
+    if (HasFatalFailure()) {
+        return;
+    }
+    char* displaySecsEnv = getenv("TEST_DISPLAY_SECS");
+    if (displaySecsEnv != NULL) {
+        mDisplaySecs = atoi(displaySecsEnv);
+        if (mDisplaySecs < 0) {
+            mDisplaySecs = 0;
+        }
+    } else {
+        mDisplaySecs = 0;
+    }
+
+    sp<Surface> surface;
+    sp<ANativeWindow> window;
+    if (mDisplaySecs > 0) {
+        createOnScreenSurface(/*out*/surface);
+        window = surface;
+    }
+    int streamId = -1;
+    EXPECT_OK(mCamera->createStream(/*width*/640, /*height*/480, TEST_FORMAT,
+              window, &streamId));
+    EXPECT_NE(-1, streamId);
+
+    EXPECT_OK(mCamera->exclusiveTryLock());
+    /* iterate in a loop submitting requests every frame.
+     *  what kind of requests doesnt really matter, just whatever.
+     */
+
+    // it would probably be better to use CameraMetadata from camera service.
+    camera_metadata_t *request = NULL;
+    EXPECT_OK(mCamera->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+              /*out*/&request));
+    EXPECT_NE((void*)NULL, request);
+
+    /* FIXME: dont need this later, at which point the above should become an
+       ASSERT_NE*/
+    if(request == NULL) request = allocate_camera_metadata(10, 100);
+
+    // set the output streams to just this stream ID
+
+    // wow what a verbose API.
+    // i would give a loaf of bread for
+    //   metadata->updateOrInsert(keys.request.output.streams, streamId);
+    camera_metadata_entry_t entry;
+    uint32_t tag = static_cast<uint32_t>(ANDROID_REQUEST_OUTPUT_STREAMS);
+    int find = find_camera_metadata_entry(request, tag, &entry);
+    if (find == -ENOENT) {
+        ASSERT_OK(add_camera_metadata_entry(request, tag, &streamId,
+                  /*data_count*/1));
+    } else {
+        ASSERT_OK(update_camera_metadata_entry(request, entry.index, &streamId,
+                  /*data_count*/1, &entry));
+    }
+
+    EXPECT_OK(mCamera->submitRequest(request, /*streaming*/true));
+
+    sleep(mDisplaySecs);
+    //should the window be empty until the buffer is flipped?
+    //  that would certainly make sense
+
+
+    free_camera_metadata(request);
+    EXPECT_OK(mCamera->cancelStream(streamId));
+    EXPECT_OK(mCamera->exclusiveUnlock());
+}
+
 }
 }
 }
diff --git a/include/camera/ProCamera.h b/include/camera/ProCamera.h
index 2dd01e3..7191b07 100644
--- a/include/camera/ProCamera.h
+++ b/include/camera/ProCamera.h
@@ -114,8 +114,49 @@
      * Lock free. Service maintains counter of streams.
      * Errors: BAD_VALUE if unknown stream ID.
      */
+// TODO: remove requestStream, its useless.
+
+// TODO: rename cancelStream to deleteStream
+// can probably do it with a grep/sed
+
+    /**
+      * Ask for a stream to be disabled.
+      * Lock free. Service maintains counter of streams.
+      * Errors: BAD_VALUE if unknown stream ID.
+      */
     status_t cancelStream(int streamId);
 
+    /**
+      * Create a new HW stream, whose sink will be the window.
+      * Lock free. Service maintains counter of streams.
+      * Errors: -EBUSY if too many streams created
+      */
+    status_t createStream(int width, int height, int format,
+                          const sp<ANativeWindow>& window,
+                          /*out*/
+                          int* streamId);
+
+    /**
+      * Create a new HW stream, whose sink will be the SurfaceTexture.
+      * Lock free. Service maintains counter of streams.
+      * Errors: -EBUSY if too many streams created
+      */
+    status_t createStream(int width, int height, int format,
+                          const sp<IGraphicBufferProducer>& bufferProducer,
+                          /*out*/
+                          int* streamId);
+
+    // Create a request object from a template.
+    status_t createDefaultRequest(int templateId,
+                                 /*out*/
+                                  camera_metadata** request) const;
+
+    // Get number of cameras
+    static int getNumberOfCameras();
+
+    // Get static camera metadata
+    static camera_metadata* getCameraInfo(int cameraId);
+
     sp<IProCameraUser>         remote();
 
 protected: