Camera service: Minimally functional preview for camera 2 devices.

- Camera app starts up
- Basic preview operation with defaults
- Shutdown sequence is very minimal

Bug: 6243944

Change-Id: I67673b7c1fc08956d218d99f9171e74a7a82bf07
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index d0a84a5..9825af7 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -57,7 +57,10 @@
         int clientPid):
         Client(cameraService, cameraClient,
                 cameraId, cameraFacing, clientPid),
-        mParams(NULL)
+        mState(NOT_INITIALIZED),
+        mParams(NULL),
+        mPreviewStreamId(NO_PREVIEW_STREAM),
+        mPreviewRequest(NULL)
 {
     ALOG1_ENTRY;
 
@@ -90,6 +93,8 @@
         mParams->dump();
     }
 
+    mState = STOPPED;
+
     ALOG1_EXIT;
     return OK;
 }
@@ -118,7 +123,12 @@
 
     if (mDevice == 0) return;
 
-    mDevice->setStreamingRequest(NULL);
+    stopPreview();
+
+    if (mPreviewStreamId != NO_PREVIEW_STREAM) {
+        mDevice->deleteStream(mPreviewStreamId);
+        mPreviewStreamId = NO_PREVIEW_STREAM;
+    }
 
     CameraService::Client::disconnect();
 }
@@ -135,12 +145,67 @@
     return BAD_VALUE;
 }
 
-status_t Camera2Client::setPreviewDisplay(const sp<Surface>& surface) {
-    return BAD_VALUE;
+status_t Camera2Client::setPreviewDisplay(
+        const sp<Surface>& surface) {
+    ALOG1_ENTRY;
+    if (mState == PREVIEW) return INVALID_OPERATION;
+
+    sp<IBinder> binder;
+    sp<ANativeWindow> window;
+    if (surface != 0) {
+        binder = surface->asBinder();
+        window = surface;
+    }
+
+    return setPreviewWindow(binder,window);
 }
 
-status_t Camera2Client::setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture) {
-    return BAD_VALUE;
+status_t Camera2Client::setPreviewTexture(
+        const sp<ISurfaceTexture>& surfaceTexture) {
+    ALOG1_ENTRY;
+    if (mState == PREVIEW) return INVALID_OPERATION;
+
+    sp<IBinder> binder;
+    sp<ANativeWindow> window;
+    if (surfaceTexture != 0) {
+        binder = surfaceTexture->asBinder();
+        window = new SurfaceTextureClient(surfaceTexture);
+    }
+    return setPreviewWindow(binder, window);
+}
+
+status_t Camera2Client::setPreviewWindow(const sp<IBinder>& binder,
+        const sp<ANativeWindow>& window) {
+    ALOG1_ENTRY;
+    status_t res;
+
+    if (binder == mPreviewSurface) {
+        return NO_ERROR;
+    }
+
+    if (mPreviewStreamId != NO_PREVIEW_STREAM) {
+        res = mDevice->deleteStream(mPreviewStreamId);
+        if (res != OK) {
+            return res;
+        }
+    }
+
+    int previewWidth, previewHeight;
+    mParams->getPreviewSize(&previewWidth, &previewHeight);
+
+    res = mDevice->createStream(window,
+            previewWidth, previewHeight, CAMERA2_HAL_PIXEL_FORMAT_OPAQUE,
+            &mPreviewStreamId);
+    if (res != OK) {
+        return res;
+    }
+
+    if (mState == WAITING_FOR_PREVIEW_WINDOW) {
+        return startPreview();
+    }
+
+    ALOG1_EXIT;
+    return OK;
 }
 
 void Camera2Client::setPreviewCallbackFlag(int flag) {
@@ -148,15 +213,63 @@
 }
 
 status_t Camera2Client::startPreview() {
-    return BAD_VALUE;
+    ALOG1_ENTRY;
+    status_t res;
+    if (mState == PREVIEW) return INVALID_OPERATION;
+
+    if (mPreviewStreamId == NO_PREVIEW_STREAM) {
+        mState = WAITING_FOR_PREVIEW_WINDOW;
+        return OK;
+    }
+
+    if (mPreviewRequest == NULL) {
+        updatePreviewRequest();
+    }
+
+    uint8_t outputStream = mPreviewStreamId;
+
+    camera_metadata_entry_t outputStreams;
+    res = find_camera_metadata_entry(mPreviewRequest,
+            ANDROID_REQUEST_OUTPUT_STREAMS,
+            &outputStreams);
+    if (res == NAME_NOT_FOUND) {
+        res = add_camera_metadata_entry(mPreviewRequest,
+                ANDROID_REQUEST_OUTPUT_STREAMS,
+                &outputStream, 1);
+    } else if (res == OK) {
+        res = update_camera_metadata_entry(mPreviewRequest,
+                outputStreams.index, &outputStream, 1, NULL);
+    }
+
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to set up preview request: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        mState = STOPPED;
+        return res;
+    }
+
+    res = mDevice->setStreamingRequest(mPreviewRequest);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to set preview request to start preview: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        mState = STOPPED;
+        return res;
+    }
+    mState = PREVIEW;
+
+    return OK;
 }
 
 void Camera2Client::stopPreview() {
+    ALOG1_ENTRY;
+    if (mState != PREVIEW) return;
 
+    mDevice->setStreamingRequest(NULL);
+    mState = STOPPED;
 }
 
 bool Camera2Client::previewEnabled() {
-    return false;
+    return mState == PREVIEW;
 }
 
 status_t Camera2Client::storeMetaDataInBuffers(bool enabled) {
@@ -179,11 +292,11 @@
 }
 
 status_t Camera2Client::autoFocus() {
-    return BAD_VALUE;
+    return OK;
 }
 
 status_t Camera2Client::cancelAutoFocus() {
-    return BAD_VALUE;
+    return OK;
 }
 
 status_t Camera2Client::takePicture(int msgType) {
@@ -191,7 +304,7 @@
 }
 
 status_t Camera2Client::setParameters(const String8& params) {
-    return BAD_VALUE;
+    return OK;
 }
 
 String8 Camera2Client::getParameters() const {
@@ -199,7 +312,7 @@
 }
 
 status_t Camera2Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
-    return BAD_VALUE;
+    return OK;
 }
 
 // private methods
@@ -781,7 +894,7 @@
             "(0,0,0,0,0)");
 
     mParams->set(CameraParameters::KEY_ZOOM, 0);
-    mParams->set(CameraParameters::KEY_MAX_ZOOM, kNumZoomSteps - 1);
+    mParams->set(CameraParameters::KEY_MAX_ZOOM, NUM_ZOOM_STEPS - 1);
 
     camera_metadata_entry_t maxDigitalZoom;
     res = find_camera_metadata_entry(mDevice->info(),
@@ -792,9 +905,9 @@
         String8 zoomRatios;
         float zoom = 1.f;
         float zoomIncrement = (maxDigitalZoom.data.f[0] - zoom) /
-                (kNumZoomSteps-1);
+                (NUM_ZOOM_STEPS-1);
         bool addComma = false;
-        for (size_t i=0; i < kNumZoomSteps; i++) {
+        for (size_t i=0; i < NUM_ZOOM_STEPS; i++) {
             if (addComma) zoomRatios += ",";
             addComma = true;
             zoomRatios += String8::format("%d", static_cast<int>(zoom * 100));
@@ -846,4 +959,21 @@
     return OK;
 }
 
+status_t Camera2Client::updatePreviewRequest() {
+    ALOG1_ENTRY
+    status_t res;
+    if (mPreviewRequest == NULL) {
+        res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+                &mPreviewRequest);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to create default preview request: "
+                    "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+    }
+    // TODO: Adjust for mParams changes
+    ALOG1_EXIT
+    return OK;
+}
+
 } // namespace android
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h
index 4f0fcf0..fb701ab 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -36,7 +36,8 @@
     virtual status_t        lock();
     virtual status_t        unlock();
     virtual status_t        setPreviewDisplay(const sp<Surface>& surface);
-    virtual status_t        setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture);
+    virtual status_t        setPreviewTexture(
+        const sp<ISurfaceTexture>& surfaceTexture);
     virtual void            setPreviewCallbackFlag(int flag);
     virtual status_t        startPreview();
     virtual void            stopPreview();
@@ -66,15 +67,35 @@
     virtual status_t dump(int fd, const Vector<String16>& args);
 
 private:
-    CameraParameters *mParams;
+    // Number of zoom steps to simulate
+    static const unsigned int NUM_ZOOM_STEPS = 10;
+    // Used with mPreviewStreamId
+    static const int NO_PREVIEW_STREAM = -1;
+
+    enum {
+        NOT_INITIALIZED,
+        STOPPED,
+        WAITING_FOR_PREVIEW_WINDOW,
+        PREVIEW
+    } mState;
+
     sp<Camera2Device> mDevice;
 
+    CameraParameters *mParams;
+
+    sp<IBinder> mPreviewSurface;
+    int mPreviewStreamId;
+    camera_metadata_t *mPreviewRequest;
+
+    status_t setPreviewWindow(const sp<IBinder>& binder,
+            const sp<ANativeWindow>& window);
+
     // Convert static camera info from a camera2 device to the
     // old API parameter map.
     status_t buildDefaultParameters();
 
-    // Free parameters for mapping from new to old HAL
-    static const unsigned int kNumZoomSteps = 10;
+    // Update preview request based on mParams
+    status_t updatePreviewRequest();
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index 4b0cfc4..bd62fa1 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -26,11 +26,12 @@
         mId(id),
         mDevice(NULL)
 {
-
+    ALOGV("%s: E", __FUNCTION__);
 }
 
 Camera2Device::~Camera2Device()
 {
+    ALOGV("%s: E", __FUNCTION__);
     if (mDevice) {
         status_t res;
         res = mDevice->common.close(&mDevice->common);
@@ -45,6 +46,8 @@
 
 status_t Camera2Device::initialize(camera_module_t *module)
 {
+    ALOGV("%s: E", __FUNCTION__);
+
     status_t res;
     char name[10];
     snprintf(name, sizeof(name), "%d", mId);
@@ -79,26 +82,90 @@
 
     mDeviceInfo = info.static_camera_characteristics;
 
-    res = mDevice->ops->set_request_queue_src_ops(mDevice,
-            mRequestQueue.getToConsumerInterface());
-    if (res != OK) return res;
-
-    res = mDevice->ops->set_frame_queue_dst_ops(mDevice,
-            mFrameQueue.getToProducerInterface());
-    if (res != OK) return res;
+    res = mRequestQueue.setConsumerDevice(mDevice);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to connect request queue to device: %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        return res;
+    }
+    res = mFrameQueue.setProducerDevice(mDevice);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to connect frame queue to device: %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        return res;
+    }
 
     res = mDevice->ops->get_metadata_vendor_tag_ops(mDevice, &mVendorTagOps);
-    if (res != OK ) return res;
+    if (res != OK ) {
+        ALOGE("%s: Camera %d: Unable to retrieve tag ops from device: %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        return res;
+    }
 
     return OK;
 }
 
+camera_metadata_t *Camera2Device::info() {
+    ALOGV("%s: E", __FUNCTION__);
+
+    return mDeviceInfo;
+}
+
 status_t Camera2Device::setStreamingRequest(camera_metadata_t* request)
 {
+    ALOGV("%s: E", __FUNCTION__);
+
     mRequestQueue.setStreamSlot(request);
     return OK;
 }
 
+status_t Camera2Device::createStream(sp<ANativeWindow> consumer,
+        uint32_t width, uint32_t height, int format, int *id) {
+    status_t res;
+    ALOGV("%s: E", __FUNCTION__);
+
+    sp<StreamAdapter> stream = new StreamAdapter(mDevice);
+
+    res = stream->connectToDevice(consumer, width, height, format);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to create stream (%d x %d, format %x):"
+                "%s (%d)",
+                __FUNCTION__, mId, width, height, format, strerror(-res), res);
+        return res;
+    }
+
+    *id = stream->getId();
+
+    mStreams.push_back(stream);
+    return OK;
+}
+
+status_t Camera2Device::deleteStream(int id) {
+    ALOGV("%s: E", __FUNCTION__);
+
+    bool found = false;
+    for (StreamList::iterator streamI = mStreams.begin();
+         streamI != mStreams.end(); streamI++) {
+        if ((*streamI)->getId() == id) {
+            mStreams.erase(streamI);
+            found = true;
+            break;
+        }
+    }
+    if (!found) {
+        ALOGE("%s: Camera %d: Unable to find stream %d to delete",
+                __FUNCTION__, mId, id);
+        return BAD_VALUE;
+    }
+    return OK;
+}
+
+status_t Camera2Device::createDefaultRequest(int templateId,
+        camera_metadata_t **request) {
+    ALOGV("%s: E", __FUNCTION__);
+    return mDevice->ops->construct_default_request(mDevice, templateId, request);
+}
+
 /**
  * Camera2Device::MetadataQueue
  */
@@ -125,39 +192,32 @@
     freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
 }
 
-// Interface to camera2 HAL as consumer (input requests/reprocessing)
-const camera2_request_queue_src_ops_t*
-Camera2Device::MetadataQueue::getToConsumerInterface() {
-    return static_cast<camera2_request_queue_src_ops_t*>(this);
-}
-
-void Camera2Device::MetadataQueue::setFromConsumerInterface(camera2_device_t *d) {
-    Mutex::Autolock l(mMutex);
+// Connect to camera2 HAL as consumer (input requests/reprocessing)
+status_t Camera2Device::MetadataQueue::setConsumerDevice(camera2_device_t *d) {
+    status_t res;
+    res = d->ops->set_request_queue_src_ops(d,
+            this);
+    if (res != OK) return res;
     mDevice = d;
+    return OK;
 }
 
-const camera2_frame_queue_dst_ops_t*
-Camera2Device::MetadataQueue::getToProducerInterface() {
-    return static_cast<camera2_frame_queue_dst_ops_t*>(this);
+status_t Camera2Device::MetadataQueue::setProducerDevice(camera2_device_t *d) {
+    status_t res;
+    res = d->ops->set_frame_queue_dst_ops(d,
+            this);
+    return res;
 }
 
 // Real interfaces
 status_t Camera2Device::MetadataQueue::enqueue(camera_metadata_t *buf) {
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock l(mMutex);
 
     mCount++;
     mEntries.push_back(buf);
-    notEmpty.signal();
 
-    if (mSignalConsumer && mDevice != NULL) {
-        mSignalConsumer = false;
-
-        mMutex.unlock();
-        ALOGV("%s: Signaling consumer", __FUNCTION__);
-        mDevice->ops->notify_request_queue_not_empty(mDevice);
-        mMutex.lock();
-    }
-    return OK;
+    return signalConsumerLocked();
 }
 
 int Camera2Device::MetadataQueue::getBufferCount() {
@@ -171,6 +231,8 @@
 status_t Camera2Device::MetadataQueue::dequeue(camera_metadata_t **buf,
         bool incrementCount)
 {
+    ALOGV("%s: E", __FUNCTION__);
+    status_t res;
     Mutex::Autolock l(mMutex);
 
     if (mCount == 0) {
@@ -201,9 +263,16 @@
     mEntries.erase(mEntries.begin());
 
     if (incrementCount) {
-        add_camera_metadata_entry(b,
+        camera_metadata_entry_t frameCount;
+        res = find_camera_metadata_entry(b,
                 ANDROID_REQUEST_FRAME_COUNT,
-                (void**)&mFrameCount, 1);
+                &frameCount);
+        if (res != OK) {
+            ALOGE("%s: Unable to add frame count: %s (%d)",
+                    __FUNCTION__, strerror(-res), res);
+        } else {
+            *frameCount.data.i32 = mFrameCount;
+        }
         mFrameCount++;
     }
 
@@ -226,6 +295,7 @@
 
 status_t Camera2Device::MetadataQueue::setStreamSlot(camera_metadata_t *buf)
 {
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock l(mMutex);
     if (buf == NULL) {
         freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
@@ -244,20 +314,34 @@
         mStreamSlot.push_front(buf);
         mStreamSlotCount = 1;
     }
-    return OK;
+    return signalConsumerLocked();
 }
 
 status_t Camera2Device::MetadataQueue::setStreamSlot(
         const List<camera_metadata_t*> &bufs)
 {
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock l(mMutex);
     if (mStreamSlotCount > 0) {
         freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
     }
     mStreamSlot = bufs;
     mStreamSlotCount = mStreamSlot.size();
+    return signalConsumerLocked();
+}
 
-    return OK;
+status_t Camera2Device::MetadataQueue::signalConsumerLocked() {
+    status_t res = OK;
+    notEmpty.signal();
+    if (mSignalConsumer && mDevice != NULL) {
+        mSignalConsumer = false;
+
+        mMutex.unlock();
+        ALOGV("%s: Signaling consumer", __FUNCTION__);
+        res = mDevice->ops->notify_request_queue_not_empty(mDevice);
+        mMutex.lock();
+    }
+    return res;
 }
 
 status_t Camera2Device::MetadataQueue::freeBuffers(
@@ -337,5 +421,268 @@
     return queue->enqueue(filled_buffer);
 }
 
+/**
+ * Camera2Device::StreamAdapter
+ */
+
+#ifndef container_of
+#define container_of(ptr, type, member) \
+    (type *)((char*)(ptr) - offsetof(type, member))
+#endif
+
+Camera2Device::StreamAdapter::StreamAdapter(camera2_device_t *d):
+        mState(DISCONNECTED),
+        mDevice(d),
+        mId(-1),
+        mWidth(0), mHeight(0), mFormatRequested(0)
+{
+    camera2_stream_ops::dequeue_buffer = dequeue_buffer;
+    camera2_stream_ops::enqueue_buffer = enqueue_buffer;
+    camera2_stream_ops::cancel_buffer = cancel_buffer;
+    camera2_stream_ops::set_crop = set_crop;
+}
+
+Camera2Device::StreamAdapter::~StreamAdapter() {
+    disconnect();
+}
+
+status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consumer,
+        uint32_t width, uint32_t height, int format) {
+    status_t res;
+
+    if (mState != DISCONNECTED) return INVALID_OPERATION;
+    if (consumer == NULL) {
+        ALOGE("%s: Null consumer passed to stream adapter", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    mConsumerInterface = consumer;
+    mWidth = width;
+    mHeight = height;
+    mFormatRequested = format;
+
+    // Allocate device-side stream interface
+
+    uint32_t id;
+    uint32_t formatActual;
+    uint32_t usage;
+    uint32_t maxBuffers = 2;
+    res = mDevice->ops->allocate_stream(mDevice,
+            mWidth, mHeight, mFormatRequested, getStreamOps(),
+            &id, &formatActual, &usage, &maxBuffers);
+    if (res != OK) {
+        ALOGE("%s: Device stream allocation failed: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return res;
+    }
+
+    mId = id;
+    mFormat = formatActual;
+    mUsage = usage;
+    mMaxProducerBuffers = maxBuffers;
+
+    mState = ALLOCATED;
+
+    // Configure consumer-side ANativeWindow interface
+    res = native_window_api_connect(mConsumerInterface.get(),
+            NATIVE_WINDOW_API_CAMERA);
+    if (res != OK) {
+        ALOGE("%s: Unable to connect to native window for stream %d",
+                __FUNCTION__, mId);
+
+        return res;
+    }
+
+    mState = CONNECTED;
+
+    res = native_window_set_usage(mConsumerInterface.get(), mUsage);
+    if (res != OK) {
+        ALOGE("%s: Unable to configure usage %08x for stream %d",
+                __FUNCTION__, mUsage, mId);
+        return res;
+    }
+
+    res = native_window_set_buffers_geometry(mConsumerInterface.get(),
+            mWidth, mHeight, mFormat);
+    if (res != OK) {
+        ALOGE("%s: Unable to configure buffer geometry"
+                " %d x %d, format 0x%x for stream %d",
+                __FUNCTION__, mWidth, mHeight, mFormat, mId);
+        return res;
+    }
+
+    int maxConsumerBuffers;
+    res = mConsumerInterface->query(mConsumerInterface.get(),
+            NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
+    if (res != OK) {
+        ALOGE("%s: Unable to query consumer undequeued"
+                " buffer count for stream %d", __FUNCTION__, mId);
+        return res;
+    }
+    mMaxConsumerBuffers = maxConsumerBuffers;
+
+    ALOGV("%s: Producer wants %d buffers, consumer wants %d", __FUNCTION__,
+            mMaxProducerBuffers, mMaxConsumerBuffers);
+
+    int totalBuffers = mMaxConsumerBuffers + mMaxProducerBuffers;
+
+    res = native_window_set_buffer_count(mConsumerInterface.get(),
+            totalBuffers);
+    if (res != OK) {
+        ALOGE("%s: Unable to set buffer count for stream %d",
+                __FUNCTION__, mId);
+        return res;
+    }
+
+    // Register allocated buffers with HAL device
+    buffer_handle_t *buffers = new buffer_handle_t[totalBuffers];
+    ANativeWindowBuffer **anwBuffers = new ANativeWindowBuffer*[totalBuffers];
+    int bufferIdx = 0;
+    for (; bufferIdx < totalBuffers; bufferIdx++) {
+        res = mConsumerInterface->dequeueBuffer(mConsumerInterface.get(),
+                &anwBuffers[bufferIdx]);
+        if (res != OK) {
+            ALOGE("%s: Unable to dequeue buffer %d for initial registration for"
+                    "stream %d", __FUNCTION__, bufferIdx, mId);
+            goto cleanUpBuffers;
+        }
+
+        res = mConsumerInterface->lockBuffer(mConsumerInterface.get(),
+                anwBuffers[bufferIdx]);
+        if (res != OK) {
+            ALOGE("%s: Unable to lock buffer %d for initial registration for"
+                    "stream %d", __FUNCTION__, bufferIdx, mId);
+            bufferIdx++;
+            goto cleanUpBuffers;
+        }
+
+        buffers[bufferIdx] = anwBuffers[bufferIdx]->handle;
+    }
+
+    res = mDevice->ops->register_stream_buffers(mDevice,
+            mId,
+            totalBuffers,
+            buffers);
+    if (res != OK) {
+        ALOGE("%s: Unable to register buffers with HAL device for stream %d",
+                __FUNCTION__, mId);
+    } else {
+        mState = ACTIVE;
+    }
+
+cleanUpBuffers:
+    for (int i = 0; i < bufferIdx; i++) {
+        res = mConsumerInterface->cancelBuffer(mConsumerInterface.get(),
+                anwBuffers[i]);
+        if (res != OK) {
+            ALOGE("%s: Unable to cancel buffer %d after registration",
+                    __FUNCTION__, i);
+        }
+    }
+    delete anwBuffers;
+    delete buffers;
+
+    return res;
+}
+
+status_t Camera2Device::StreamAdapter::disconnect() {
+    status_t res;
+    if (mState >= ALLOCATED) {
+        res = mDevice->ops->release_stream(mDevice, mId);
+        if (res != OK) {
+            ALOGE("%s: Unable to release stream %d",
+                    __FUNCTION__, mId);
+            return res;
+        }
+    }
+    if (mState >= CONNECTED) {
+        res = native_window_api_disconnect(mConsumerInterface.get(),
+                NATIVE_WINDOW_API_CAMERA);
+        if (res != OK) {
+            ALOGE("%s: Unable to disconnect stream %d from native window",
+                    __FUNCTION__, mId);
+            return res;
+        }
+    }
+    mId = -1;
+    mState = DISCONNECTED;
+    return OK;
+}
+
+int Camera2Device::StreamAdapter::getId() {
+    return mId;
+}
+
+const camera2_stream_ops *Camera2Device::StreamAdapter::getStreamOps() {
+    return static_cast<camera2_stream_ops *>(this);
+}
+
+ANativeWindow* Camera2Device::StreamAdapter::toANW(
+        const camera2_stream_ops_t *w) {
+    return static_cast<const StreamAdapter*>(w)->mConsumerInterface.get();
+}
+
+int Camera2Device::StreamAdapter::dequeue_buffer(const camera2_stream_ops_t *w,
+        buffer_handle_t** buffer) {
+    int res;
+    int state = static_cast<const StreamAdapter*>(w)->mState;
+    if (state != ACTIVE) {
+        ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
+        return INVALID_OPERATION;
+    }
+
+    ANativeWindow *a = toANW(w);
+    ANativeWindowBuffer* anb;
+    res = a->dequeueBuffer(a, &anb);
+    if (res != OK) return res;
+    res = a->lockBuffer(a, anb);
+    if (res != OK) return res;
+
+    *buffer = &(anb->handle);
+    ALOGV("%s: Buffer %p", __FUNCTION__, *buffer);
+    return res;
+}
+
+int Camera2Device::StreamAdapter::enqueue_buffer(const camera2_stream_ops_t* w,
+        int64_t timestamp,
+        buffer_handle_t* buffer) {
+    ALOGV("%s: Buffer %p captured at %lld ns", __FUNCTION__, buffer, timestamp);
+    int state = static_cast<const StreamAdapter*>(w)->mState;
+    if (state != ACTIVE) {
+        ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
+        return INVALID_OPERATION;
+    }
+    ANativeWindow *a = toANW(w);
+    status_t err;
+    err = native_window_set_buffers_timestamp(a, timestamp);
+    if (err != OK) return err;
+    return a->queueBuffer(a,
+            container_of(buffer, ANativeWindowBuffer, handle));
+}
+
+int Camera2Device::StreamAdapter::cancel_buffer(const camera2_stream_ops_t* w,
+        buffer_handle_t* buffer) {
+    int state = static_cast<const StreamAdapter*>(w)->mState;
+    if (state != ACTIVE) {
+        ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
+        return INVALID_OPERATION;
+    }
+    ANativeWindow *a = toANW(w);
+    return a->cancelBuffer(a,
+            container_of(buffer, ANativeWindowBuffer, handle));
+}
+
+int Camera2Device::StreamAdapter::set_crop(const camera2_stream_ops_t* w,
+        int left, int top, int right, int bottom) {
+    int state = static_cast<const StreamAdapter*>(w)->mState;
+    if (state != ACTIVE) {
+        ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
+        return INVALID_OPERATION;
+    }
+    ANativeWindow *a = toANW(w);
+    android_native_rect_t crop = { left, top, right, bottom };
+    return native_window_set_crop(a, &crop);
+}
+
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/Camera2Device.h b/services/camera/libcameraservice/Camera2Device.h
index 07c5ff7..e8a68d3 100644
--- a/services/camera/libcameraservice/Camera2Device.h
+++ b/services/camera/libcameraservice/Camera2Device.h
@@ -19,6 +19,7 @@
 
 #include <utils/RefBase.h>
 #include <utils/List.h>
+#include <utils/Vector.h>
 #include <utils/Mutex.h>
 #include <utils/Condition.h>
 #include <utils/Errors.h>
@@ -34,11 +35,18 @@
 
     status_t initialize(camera_module_t *module);
 
+    camera_metadata_t* info();
+
     status_t setStreamingRequest(camera_metadata_t* request);
 
-    camera_metadata_t* info() {
-        return mDeviceInfo;
-    }
+    status_t createStream(sp<ANativeWindow> consumer,
+            uint32_t width, uint32_t height, int format,
+            int *id);
+
+    status_t deleteStream(int id);
+
+    status_t createDefaultRequest(int templateId,
+            camera_metadata_t **request);
 
   private:
 
@@ -63,6 +71,11 @@
         const camera2_request_queue_src_ops_t*   getToConsumerInterface();
         void setFromConsumerInterface(camera2_device_t *d);
 
+        // Connect queue consumer endpoint to a camera2 device
+        status_t setConsumerDevice(camera2_device_t *d);
+        // Connect queue producer endpoint to a camera2 device
+        status_t setProducerDevice(camera2_device_t *d);
+
         const camera2_frame_queue_dst_ops_t* getToProducerInterface();
 
         // Real interfaces. On enqueue, queue takes ownership of buffer pointer
@@ -79,6 +92,7 @@
         status_t setStreamSlot(const List<camera_metadata_t*> &bufs);
 
       private:
+        status_t signalConsumerLocked();
         status_t freeBuffers(List<camera_metadata_t*>::iterator start,
                 List<camera_metadata_t*>::iterator end);
 
@@ -125,6 +139,67 @@
     MetadataQueue mRequestQueue;
     MetadataQueue mFrameQueue;
 
+    /**
+     * Adapter from an ANativeWindow interface to camera2 device stream ops.
+     * Also takes care of allocating/deallocating stream in device interface
+     */
+    class StreamAdapter: public camera2_stream_ops, public virtual RefBase {
+      public:
+        StreamAdapter(camera2_device_t *d);
+
+        ~StreamAdapter();
+
+        status_t connectToDevice(sp<ANativeWindow> consumer,
+                uint32_t width, uint32_t height, int format);
+
+        status_t disconnect();
+
+        // Get stream ID. Only valid after a successful connectToDevice call.
+        int      getId();
+
+      private:
+        enum {
+            ERROR = -1,
+            DISCONNECTED = 0,
+            ALLOCATED,
+            CONNECTED,
+            ACTIVE
+        } mState;
+
+        sp<ANativeWindow> mConsumerInterface;
+        camera2_device_t *mDevice;
+
+        uint32_t mId;
+        uint32_t mWidth;
+        uint32_t mHeight;
+        uint32_t mFormat;
+        uint32_t mUsage;
+        uint32_t mMaxProducerBuffers;
+        uint32_t mMaxConsumerBuffers;
+
+        int mFormatRequested;
+
+        const camera2_stream_ops *getStreamOps();
+
+        static ANativeWindow* toANW(const camera2_stream_ops_t *w);
+
+        static int dequeue_buffer(const camera2_stream_ops_t *w,
+                buffer_handle_t** buffer);
+
+        static int enqueue_buffer(const camera2_stream_ops_t* w,
+                int64_t timestamp,
+                buffer_handle_t* buffer);
+
+        static int cancel_buffer(const camera2_stream_ops_t* w,
+                buffer_handle_t* buffer);
+
+        static int set_crop(const camera2_stream_ops_t* w,
+                int left, int top, int right, int bottom);
+    }; // class StreamAdapter
+
+    typedef List<sp<StreamAdapter> > StreamList;
+    StreamList mStreams;
+
 }; // class Camera2Device
 
 }; // namespace android