OSDN Git Service

Initial implementation of android.hardware.photography.CameraDevice (service)
authorIgor Murashkin <iam@google.com>
Wed, 12 Jun 2013 01:10:18 +0000 (18:10 -0700)
committerIgor Murashkin <iam@google.com>
Fri, 21 Jun 2013 03:31:30 +0000 (20:31 -0700)
* Verified preview streaming requests
* Other things *should* work but unverified / unimplemented in client side

Missing:
* CameraService needs to return static camera info metadata

Bug: 9213377
Change-Id: I71568560fcf18d0e2b408ed1c4d0066647314868

20 files changed:
camera/Android.mk
camera/CameraMetadata.cpp
camera/ICameraService.cpp
camera/IProCameraCallbacks.cpp
camera/IProCameraUser.cpp
camera/photography/CaptureRequest.cpp [new file with mode: 0644]
camera/photography/ICameraDeviceCallbacks.cpp [new file with mode: 0644]
camera/photography/ICameraDeviceUser.cpp [new file with mode: 0644]
include/camera/CameraMetadata.h
include/camera/ICameraService.h
include/camera/photography/CaptureRequest.h [new file with mode: 0644]
include/camera/photography/ICameraDeviceCallbacks.h [new file with mode: 0644]
include/camera/photography/ICameraDeviceUser.h [new file with mode: 0644]
services/camera/libcameraservice/Android.mk
services/camera/libcameraservice/Camera2ClientBase.cpp
services/camera/libcameraservice/Camera2ClientBase.h
services/camera/libcameraservice/CameraService.cpp
services/camera/libcameraservice/CameraService.h
services/camera/libcameraservice/photography/CameraDeviceClient.cpp [new file with mode: 0644]
services/camera/libcameraservice/photography/CameraDeviceClient.h [new file with mode: 0644]

index fa518ff..8f58f87 100644 (file)
@@ -16,6 +16,9 @@ LOCAL_SRC_FILES:= \
        ICameraRecordingProxyListener.cpp \
        IProCameraUser.cpp \
        IProCameraCallbacks.cpp \
+       photography/ICameraDeviceUser.cpp \
+       photography/ICameraDeviceCallbacks.cpp \
+       photography/CaptureRequest.cpp \
        ProCamera.cpp \
        CameraBase.cpp \
 
index a8f9eff..f447c5b 100644 (file)
 #include <utils/Errors.h>
 
 #include <camera/CameraMetadata.h>
+#include <binder/Parcel.h>
 
 namespace android {
 
+typedef Parcel::WritableBlob WritableBlob;
+typedef Parcel::ReadableBlob ReadableBlob;
+
 CameraMetadata::CameraMetadata() :
         mBuffer(NULL), mLocked(false) {
 }
@@ -408,4 +412,175 @@ status_t CameraMetadata::resizeIfNeeded(size_t extraEntries, size_t extraData) {
     return OK;
 }
 
+status_t CameraMetadata::readFromParcel(const Parcel& data,
+                                        camera_metadata_t** out) {
+
+    status_t err = OK;
+
+    camera_metadata_t* metadata = NULL;
+
+    if (out) {
+        *out = NULL;
+    }
+
+    // arg0 = metadataSize (int32)
+    int32_t metadataSizeTmp = -1;
+    if ((err = data.readInt32(&metadataSizeTmp)) != OK) {
+        ALOGE("%s: Failed to read metadata size (error %d %s)",
+              __FUNCTION__, err, strerror(-err));
+        return err;
+    }
+    const size_t metadataSize = static_cast<size_t>(metadataSizeTmp);
+
+    if (metadataSize == 0) {
+        ALOGV("%s: Read 0-sized metadata", __FUNCTION__);
+        return OK;
+    }
+
+    // NOTE: this doesn't make sense to me. shouldnt the blob
+    // know how big it is? why do we have to specify the size
+    // to Parcel::readBlob ?
+
+    ReadableBlob blob;
+    // arg1 = metadata (blob)
+    do {
+        if ((err = data.readBlob(metadataSize, &blob)) != OK) {
+            ALOGE("%s: Failed to read metadata blob (sized %d). Possible "
+                  " serialization bug. Error %d %s",
+                  __FUNCTION__, metadataSize, err, strerror(-err));
+            break;
+        }
+        const camera_metadata_t* tmp =
+                       reinterpret_cast<const camera_metadata_t*>(blob.data());
+
+        metadata = allocate_copy_camera_metadata_checked(tmp, metadataSize);
+        if (metadata == NULL) {
+            // We consider that allocation only fails if the validation
+            // also failed, therefore the readFromParcel was a failure.
+            err = BAD_VALUE;
+        }
+    } while(0);
+    blob.release();
+
+    if (out) {
+        ALOGV("%s: Set out metadata to %p", __FUNCTION__, metadata);
+        *out = metadata;
+    } else if (metadata != NULL) {
+        ALOGV("%s: Freed camera metadata at %p", __FUNCTION__, metadata);
+        free_camera_metadata(metadata);
+    }
+
+    return err;
+}
+
+status_t CameraMetadata::writeToParcel(Parcel& data,
+                                       const camera_metadata_t* metadata) {
+    status_t res = OK;
+
+    // arg0 = metadataSize (int32)
+
+    if (metadata == NULL) {
+        return data.writeInt32(0);
+    }
+
+    const size_t metadataSize = get_camera_metadata_compact_size(metadata);
+    res = data.writeInt32(static_cast<int32_t>(metadataSize));
+    if (res != OK) {
+        return res;
+    }
+
+    // arg1 = metadata (blob)
+    WritableBlob blob;
+    do {
+        res = data.writeBlob(metadataSize, &blob);
+        if (res != OK) {
+            break;
+        }
+        copy_camera_metadata(blob.data(), metadataSize, metadata);
+
+        IF_ALOGV() {
+            if (validate_camera_metadata_structure(
+                        (const camera_metadata_t*)blob.data(),
+                        &metadataSize) != OK) {
+                ALOGV("%s: Failed to validate metadata %p after writing blob",
+                       __FUNCTION__, blob.data());
+            } else {
+                ALOGV("%s: Metadata written to blob. Validation success",
+                        __FUNCTION__);
+            }
+        }
+
+        // Not too big of a problem since receiving side does hard validation
+        // Don't check the size since the compact size could be larger
+        if (validate_camera_metadata_structure(metadata, /*size*/NULL) != OK) {
+            ALOGW("%s: Failed to validate metadata %p before writing blob",
+                   __FUNCTION__, metadata);
+        }
+
+    } while(false);
+    blob.release();
+
+    return res;
+}
+
+status_t CameraMetadata::readFromParcel(Parcel *parcel) {
+
+    ALOGV("%s: parcel = %p", __FUNCTION__, parcel);
+
+    status_t res = OK;
+
+    if (parcel == NULL) {
+        ALOGE("%s: parcel is null", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    camera_metadata *buffer = NULL;
+    // TODO: reading should return a status code, in case validation fails
+    res = CameraMetadata::readFromParcel(*parcel, &buffer);
+
+    if (res != NO_ERROR) {
+        ALOGE("%s: Failed to read from parcel. Metadata is unchanged.",
+              __FUNCTION__);
+        return res;
+    }
+
+    clear();
+    mBuffer = buffer;
+
+    return OK;
+}
+
+status_t CameraMetadata::writeToParcel(Parcel *parcel) const {
+
+    ALOGV("%s: parcel = %p", __FUNCTION__, parcel);
+
+    if (parcel == NULL) {
+        ALOGE("%s: parcel is null", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    return CameraMetadata::writeToParcel(*parcel, mBuffer);
+}
+
+void CameraMetadata::swap(CameraMetadata& other) {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return;
+    } else if (other.mLocked) {
+        ALOGE("%s: Other CameraMetadata is locked", __FUNCTION__);
+        return;
+    }
+
+    camera_metadata* thisBuf = mBuffer;
+    camera_metadata* otherBuf = other.mBuffer;
+
+    other.mBuffer = thisBuf;
+    mBuffer = otherBuf;
+}
+
 }; // namespace android
index 819e410..068fb0f 100644 (file)
@@ -31,6 +31,8 @@
 #include <camera/IProCameraCallbacks.h>
 #include <camera/ICamera.h>
 #include <camera/ICameraClient.h>
+#include <camera/photography/ICameraDeviceUser.h>
+#include <camera/photography/ICameraDeviceCallbacks.h>
 
 namespace android {
 
@@ -117,7 +119,7 @@ public:
         return result;
     }
 
-    // connect to camera service
+    // connect to camera service (android.hardware.Camera)
     virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId,
                                 const String16 &clientPackageName, int clientUid)
     {
@@ -149,6 +151,25 @@ public:
         return interface_cast<IProCameraUser>(reply.readStrongBinder());
     }
 
+    // connect to camera service (android.hardware.photography.CameraDevice)
+    virtual sp<ICameraDeviceUser> connect(
+            const sp<ICameraDeviceCallbacks>& cameraCb,
+            int cameraId,
+            const String16& clientPackageName,
+            int clientUid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+        data.writeStrongBinder(cameraCb->asBinder());
+        data.writeInt32(cameraId);
+        data.writeString16(clientPackageName);
+        data.writeInt32(clientUid);
+        remote()->transact(BnCameraService::CONNECT_DEVICE, data, &reply);
+
+        if (readExceptionCode(reply)) return NULL;
+        return interface_cast<ICameraDeviceUser>(reply.readStrongBinder());
+    }
+
     virtual status_t addListener(const sp<ICameraServiceListener>& listener)
     {
         Parcel data, reply;
@@ -226,6 +247,19 @@ status_t BnCameraService::onTransact(
             reply->writeStrongBinder(camera->asBinder());
             return NO_ERROR;
         } break;
+        case CONNECT_DEVICE: {
+            CHECK_INTERFACE(ICameraService, data, reply);
+            sp<ICameraDeviceCallbacks> cameraClient =
+                interface_cast<ICameraDeviceCallbacks>(data.readStrongBinder());
+            int32_t cameraId = data.readInt32();
+            const String16 clientName = data.readString16();
+            int32_t clientUid = data.readInt32();
+            sp<ICameraDeviceUser> camera = connect(cameraClient, cameraId,
+                                                clientName, clientUid);
+            reply->writeNoException();
+            reply->writeStrongBinder(camera->asBinder());
+            return NO_ERROR;
+        } break;
         case ADD_LISTENER: {
             CHECK_INTERFACE(ICameraService, data, reply);
             sp<ICameraServiceListener> listener =
index b9cd14d..0fdb85a 100644 (file)
@@ -28,7 +28,7 @@
 
 #include <camera/IProCameraCallbacks.h>
 
-#include <system/camera_metadata.h>
+#include "camera/CameraMetadata.h"
 
 namespace android {
 
@@ -38,9 +38,6 @@ enum {
     RESULT_RECEIVED,
 };
 
-void readMetadata(const Parcel& data, camera_metadata_t** out);
-void writeMetadata(Parcel& data, camera_metadata_t* metadata);
-
 class BpProCameraCallbacks: public BpInterface<IProCameraCallbacks>
 {
 public:
@@ -75,7 +72,7 @@ public:
         Parcel data, reply;
         data.writeInterfaceToken(IProCameraCallbacks::getInterfaceDescriptor());
         data.writeInt32(frameId);
-        writeMetadata(data, result);
+        CameraMetadata::writeToParcel(data, result);
         remote()->transact(RESULT_RECEIVED, data, &reply, IBinder::FLAG_ONEWAY);
     }
 };
@@ -112,7 +109,7 @@ status_t BnProCameraCallbacks::onTransact(
             CHECK_INTERFACE(IProCameraCallbacks, data, reply);
             int32_t frameId = data.readInt32();
             camera_metadata_t *result = NULL;
-            readMetadata(data, &result);
+            CameraMetadata::readFromParcel(data, &result);
             onResultReceived(frameId, result);
             return NO_ERROR;
             break;
index 015cb5c..8f22124 100644 (file)
@@ -15,7 +15,7 @@
 ** limitations under the License.
 */
 
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 #define LOG_TAG "IProCameraUser"
 #include <utils/Log.h>
 #include <stdint.h>
 #include <camera/IProCameraUser.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/Surface.h>
-#include <system/camera_metadata.h>
+#include "camera/CameraMetadata.h"
 
 namespace android {
 
-typedef Parcel::WritableBlob WritableBlob;
-typedef Parcel::ReadableBlob ReadableBlob;
-
 enum {
     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
     CONNECT,
@@ -46,107 +43,6 @@ enum {
     GET_CAMERA_INFO,
 };
 
-/**
-  * Caller becomes the owner of the new metadata
-  * 'const Parcel' doesnt prevent us from calling the read functions.
-  *  which is interesting since it changes the internal state
-  *
-  * NULL can be returned when no metadata was sent, OR if there was an issue
-  * unpacking the serialized data (i.e. bad parcel or invalid structure).
-  */
-void readMetadata(const Parcel& data, camera_metadata_t** out) {
-
-    status_t err = OK;
-
-    camera_metadata_t* metadata = NULL;
-
-    if (out) {
-        *out = NULL;
-    }
-
-    // arg0 = metadataSize (int32)
-    int32_t metadataSizeTmp = -1;
-    if ((err = data.readInt32(&metadataSizeTmp)) != OK) {
-        ALOGE("%s: Failed to read metadata size (error %d %s)",
-              __FUNCTION__, err, strerror(-err));
-        return;
-    }
-    const size_t metadataSize = static_cast<size_t>(metadataSizeTmp);
-
-    if (metadataSize == 0) {
-        return;
-    }
-
-    // NOTE: this doesn't make sense to me. shouldnt the blob
-    // know how big it is? why do we have to specify the size
-    // to Parcel::readBlob ?
-
-    ReadableBlob blob;
-    // arg1 = metadata (blob)
-    do {
-        if ((err = data.readBlob(metadataSize, &blob)) != OK) {
-            ALOGE("%s: Failed to read metadata blob (sized %d). Possible "
-                  " serialization bug. Error %d %s",
-                  __FUNCTION__, metadataSize, err, strerror(-err));
-            break;
-        }
-        const camera_metadata_t* tmp =
-                       reinterpret_cast<const camera_metadata_t*>(blob.data());
-
-        metadata = allocate_copy_camera_metadata_checked(tmp, metadataSize);
-    } while(0);
-    blob.release();
-
-    if (out) {
-        *out = metadata;
-    } else if (metadata != NULL) {
-        free_camera_metadata(metadata);
-    }
-}
-
-/**
-  * Caller retains ownership of metadata
-  * - Write 2 (int32 + blob) args in the current position
-  */
-void writeMetadata(Parcel& data, camera_metadata_t* metadata) {
-    // arg0 = metadataSize (int32)
-
-    if (metadata == NULL) {
-        data.writeInt32(0);
-        return;
-    }
-
-    const size_t metadataSize = get_camera_metadata_compact_size(metadata);
-    data.writeInt32(static_cast<int32_t>(metadataSize));
-
-    // arg1 = metadata (blob)
-    WritableBlob blob;
-    {
-        data.writeBlob(metadataSize, &blob);
-        copy_camera_metadata(blob.data(), metadataSize, metadata);
-
-        IF_ALOGV() {
-            if (validate_camera_metadata_structure(
-                        (const camera_metadata_t*)blob.data(),
-                        &metadataSize) != OK) {
-                ALOGV("%s: Failed to validate metadata %p after writing blob",
-                       __FUNCTION__, blob.data());
-            } else {
-                ALOGV("%s: Metadata written to blob. Validation success",
-                        __FUNCTION__);
-            }
-        }
-
-        // Not too big of a problem since receiving side does hard validation
-        if (validate_camera_metadata_structure(metadata, &metadataSize) != OK) {
-            ALOGW("%s: Failed to validate metadata %p before writing blob",
-                   __FUNCTION__, metadata);
-        }
-
-    }
-    blob.release();
-}
-
 class BpProCameraUser: public BpInterface<IProCameraUser>
 {
 public:
@@ -214,7 +110,7 @@ public:
         data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor());
 
         // arg0+arg1
-        writeMetadata(data, metadata);
+        CameraMetadata::writeToParcel(data, metadata);
 
         // arg2 = streaming (bool)
         data.writeInt32(streaming);
@@ -275,7 +171,7 @@ public:
         data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor());
         data.writeInt32(templateId);
         remote()->transact(CREATE_DEFAULT_REQUEST, data, &reply);
-        readMetadata(reply, /*out*/request);
+        CameraMetadata::readFromParcel(reply, /*out*/request);
         return reply.readInt32();
     }
 
@@ -286,7 +182,7 @@ public:
         data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor());
         data.writeInt32(cameraId);
         remote()->transact(GET_CAMERA_INFO, data, &reply);
-        readMetadata(reply, /*out*/info);
+        CameraMetadata::readFromParcel(reply, /*out*/info);
         return reply.readInt32();
     }
 
@@ -343,7 +239,7 @@ status_t BnProCameraUser::onTransact(
         case SUBMIT_REQUEST: {
             CHECK_INTERFACE(IProCameraUser, data, reply);
             camera_metadata_t* metadata;
-            readMetadata(data, /*out*/&metadata);
+            CameraMetadata::readFromParcel(data, /*out*/&metadata);
 
             // arg2 = streaming (bool)
             bool streaming = data.readInt32();
@@ -395,7 +291,7 @@ status_t BnProCameraUser::onTransact(
             status_t ret;
             ret = createDefaultRequest(templateId, &request);
 
-            writeMetadata(*reply, request);
+            CameraMetadata::writeToParcel(*reply, request);
             reply->writeInt32(ret);
 
             free_camera_metadata(request);
@@ -411,7 +307,7 @@ status_t BnProCameraUser::onTransact(
             status_t ret;
             ret = getCameraInfo(cameraId, &info);
 
-            writeMetadata(*reply, info);
+            CameraMetadata::writeToParcel(*reply, info);
             reply->writeInt32(ret);
 
             free_camera_metadata(info);
diff --git a/camera/photography/CaptureRequest.cpp b/camera/photography/CaptureRequest.cpp
new file mode 100644 (file)
index 0000000..b822fc9
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+**
+** Copyright 2013, 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.
+*/
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "CameraRequest"
+#include <utils/Log.h>
+
+#include <camera/photography/CaptureRequest.h>
+
+#include <binder/Parcel.h>
+#include <gui/Surface.h>
+
+namespace android {
+
+status_t CaptureRequest::readFromParcel(Parcel* parcel) {
+    if (parcel == NULL) {
+        ALOGE("%s: Null parcel", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    mMetadata.clear();
+    mSurfaceList.clear();
+
+    status_t err;
+
+    if ((err = mMetadata.readFromParcel(parcel)) != OK) {
+        ALOGE("%s: Failed to read metadata from parcel", __FUNCTION__);
+        return err;
+    }
+    ALOGV("%s: Read metadata from parcel", __FUNCTION__);
+
+    int32_t size;
+    if ((err = parcel->readInt32(&size)) != OK) {
+        ALOGE("%s: Failed to read surface list size from parcel", __FUNCTION__);
+        return err;
+    }
+    ALOGV("%s: Read surface list size = %d", __FUNCTION__, size);
+
+    // Do not distinguish null arrays from 0-sized arrays.
+    for (int i = 0; i < size; ++i) {
+        // Parcel.writeParcelableArray
+        size_t len;
+        const char16_t* className = parcel->readString16Inplace(&len);
+        ALOGV("%s: Read surface class = %s", __FUNCTION__,
+              className != NULL ? String8(className).string() : "<null>");
+
+        if (className == NULL) {
+            continue;
+        }
+
+        // Surface.writeToParcel
+        String16 name = parcel->readString16();
+        ALOGV("%s: Read surface name = %s",
+              __FUNCTION__, String8(name).string());
+        sp<IBinder> binder(parcel->readStrongBinder());
+        ALOGV("%s: Read surface binder = %p",
+              __FUNCTION__, binder.get());
+
+        sp<Surface> surface;
+
+        if (binder != NULL) {
+            sp<IGraphicBufferProducer> gbp =
+                    interface_cast<IGraphicBufferProducer>(binder);
+            surface = new Surface(gbp);
+        }
+
+        mSurfaceList.push_back(surface);
+    }
+
+    return OK;
+}
+
+status_t CaptureRequest::writeToParcel(Parcel* parcel) const {
+    if (parcel == NULL) {
+        ALOGE("%s: Null parcel", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    status_t err;
+
+    if ((err = mMetadata.writeToParcel(parcel)) != OK) {
+        return err;
+    }
+
+    int32_t size = static_cast<int32_t>(mSurfaceList.size());
+
+    // Send 0-sized arrays when it's empty. Do not send null arrays.
+    parcel->writeInt32(size);
+
+    for (int32_t i = 0; i < size; ++i) {
+        sp<Surface> surface = mSurfaceList[i];
+
+        sp<IBinder> binder;
+        if (surface != 0) {
+            binder = surface->getIGraphicBufferProducer()->asBinder();
+        }
+
+        // not sure if readParcelableArray does this, hard to tell from source
+        parcel->writeString16(String16("android.view.Surface"));
+
+        // Surface.writeToParcel
+        parcel->writeString16(String16("unknown_name"));
+        // Surface.nativeWriteToParcel
+        parcel->writeStrongBinder(binder);
+    }
+
+    return OK;
+}
+
+}; // namespace android
diff --git a/camera/photography/ICameraDeviceCallbacks.cpp b/camera/photography/ICameraDeviceCallbacks.cpp
new file mode 100644 (file)
index 0000000..19763d7
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+**
+** Copyright 2013, 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.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ICameraDeviceCallbacks"
+#include <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
+#include <utils/Mutex.h>
+
+#include <camera/photography/ICameraDeviceCallbacks.h>
+#include "camera/CameraMetadata.h"
+
+namespace android {
+
+enum {
+    NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
+    RESULT_RECEIVED,
+};
+
+class BpCameraDeviceCallbacks: public BpInterface<ICameraDeviceCallbacks>
+{
+public:
+    BpCameraDeviceCallbacks(const sp<IBinder>& impl)
+        : BpInterface<ICameraDeviceCallbacks>(impl)
+    {
+    }
+
+    // generic callback from camera service to app
+    void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
+    {
+        ALOGV("notifyCallback");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor());
+        data.writeInt32(msgType);
+        data.writeInt32(ext1);
+        data.writeInt32(ext2);
+        remote()->transact(NOTIFY_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+        data.writeNoException();
+    }
+
+    void onResultReceived(int32_t frameId, const CameraMetadata& result) {
+        ALOGV("onResultReceived");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor());
+        data.writeInt32(frameId);
+        result.writeToParcel(&data);
+        remote()->transact(RESULT_RECEIVED, data, &reply, IBinder::FLAG_ONEWAY);
+        data.writeNoException();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(CameraDeviceCallbacks,
+                         "android.hardware.photography.ICameraDeviceCallbacks");
+
+// ----------------------------------------------------------------------
+
+status_t BnCameraDeviceCallbacks::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    ALOGV("onTransact - code = %d", code);
+    switch(code) {
+        case NOTIFY_CALLBACK: {
+            ALOGV("NOTIFY_CALLBACK");
+            CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply);
+            int32_t msgType = data.readInt32();
+            int32_t ext1 = data.readInt32();
+            int32_t ext2 = data.readInt32();
+            notifyCallback(msgType, ext1, ext2);
+            data.readExceptionCode();
+            return NO_ERROR;
+        } break;
+        case RESULT_RECEIVED: {
+            ALOGV("RESULT_RECEIVED");
+            CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply);
+            int32_t frameId = data.readInt32();
+            CameraMetadata result;
+            result.readFromParcel(const_cast<Parcel*>(&data));
+            onResultReceived(frameId, result);
+            data.readExceptionCode();
+            return NO_ERROR;
+            break;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/camera/photography/ICameraDeviceUser.cpp b/camera/photography/ICameraDeviceUser.cpp
new file mode 100644 (file)
index 0000000..0515bd7
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+**
+** Copyright 2013, 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.
+*/
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "ICameraDeviceUser"
+#include <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+#include <camera/photography/ICameraDeviceUser.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
+#include <camera/CameraMetadata.h>
+#include <camera/photography/CaptureRequest.h>
+
+namespace android {
+
+typedef Parcel::WritableBlob WritableBlob;
+typedef Parcel::ReadableBlob ReadableBlob;
+
+enum {
+    DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+    SUBMIT_REQUEST,
+    CANCEL_REQUEST,
+    DELETE_STREAM,
+    CREATE_STREAM,
+    CREATE_DEFAULT_REQUEST,
+    GET_CAMERA_INFO,
+};
+
+class BpCameraDeviceUser : public BpInterface<ICameraDeviceUser>
+{
+public:
+    BpCameraDeviceUser(const sp<IBinder>& impl)
+        : BpInterface<ICameraDeviceUser>(impl)
+    {
+    }
+
+    // disconnect from camera service
+    void disconnect()
+    {
+        ALOGV("disconnect");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        remote()->transact(DISCONNECT, data, &reply);
+        reply.readExceptionCode();
+    }
+
+    virtual int submitRequest(sp<CaptureRequest> request, bool streaming)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+
+        // arg0 = CaptureRequest
+        if (request != 0) {
+            data.writeInt32(1);
+            request->writeToParcel(&data);
+        } else {
+            data.writeInt32(0);
+        }
+
+        // arg1 = streaming (bool)
+        data.writeInt32(streaming);
+
+        remote()->transact(SUBMIT_REQUEST, data, &reply);
+
+        reply.readExceptionCode();
+        return reply.readInt32();
+    }
+
+    virtual status_t cancelRequest(int requestId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        data.writeInt32(requestId);
+
+        remote()->transact(CANCEL_REQUEST, data, &reply);
+
+        reply.readExceptionCode();
+        return reply.readInt32();
+    }
+
+    virtual status_t deleteStream(int streamId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        data.writeInt32(streamId);
+
+        remote()->transact(DELETE_STREAM, data, &reply);
+
+        reply.readExceptionCode();
+        return reply.readInt32();
+    }
+
+    virtual status_t createStream(int width, int height, int format,
+                          const sp<IGraphicBufferProducer>& bufferProducer)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        data.writeInt32(width);
+        data.writeInt32(height);
+        data.writeInt32(format);
+
+        data.writeInt32(1); // marker that bufferProducer is not null
+        data.writeString16(String16("unknown_name")); // name of surface
+        sp<IBinder> b(bufferProducer->asBinder());
+        data.writeStrongBinder(b);
+
+        remote()->transact(CREATE_STREAM, data, &reply);
+
+        reply.readExceptionCode();
+        return reply.readInt32();
+    }
+
+    // Create a request object from a template.
+    virtual status_t createDefaultRequest(int templateId,
+                                          /*out*/
+                                          CameraMetadata* request)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        data.writeInt32(templateId);
+        remote()->transact(CREATE_DEFAULT_REQUEST, data, &reply);
+
+        reply.readExceptionCode();
+        status_t result = reply.readInt32();
+
+        CameraMetadata out;
+        if (reply.readInt32() != 0) {
+            out.readFromParcel(&reply);
+        }
+
+        if (request != NULL) {
+            request->swap(out);
+        }
+        return result;
+    }
+
+
+    virtual status_t getCameraInfo(int cameraId, camera_metadata** info)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        data.writeInt32(cameraId);
+        remote()->transact(GET_CAMERA_INFO, data, &reply);
+
+
+        reply.readExceptionCode();
+        status_t result = reply.readInt32();
+
+        if (reply.readInt32() != 0) {
+            CameraMetadata::readFromParcel(reply, /*out*/info);
+        } else if (info) {
+            *info = NULL;
+        }
+
+        return result;
+    }
+
+
+private:
+
+
+};
+
+IMPLEMENT_META_INTERFACE(CameraDeviceUser,
+                         "android.hardware.photography.ICameraDeviceUser");
+
+// ----------------------------------------------------------------------
+
+status_t BnCameraDeviceUser::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case DISCONNECT: {
+            ALOGV("DISCONNECT");
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+            disconnect();
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        case SUBMIT_REQUEST: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+
+            // arg0 = request
+            sp<CaptureRequest> request;
+            if (data.readInt32() != 0) {
+                request = new CaptureRequest();
+                request->readFromParcel(const_cast<Parcel*>(&data));
+            }
+
+            // arg1 = streaming (bool)
+            bool streaming = data.readInt32();
+
+            // return code: requestId (int32)
+            reply->writeNoException();
+            reply->writeInt32(submitRequest(request, streaming));
+
+            return NO_ERROR;
+        } break;
+        case CANCEL_REQUEST: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+            int requestId = data.readInt32();
+            reply->writeNoException();
+            reply->writeInt32(cancelRequest(requestId));
+            return NO_ERROR;
+        } break;
+        case DELETE_STREAM: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+            int streamId = data.readInt32();
+            reply->writeNoException();
+            reply->writeInt32(deleteStream(streamId));
+            return NO_ERROR;
+        } break;
+        case CREATE_STREAM: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+            int width, height, format;
+
+            width = data.readInt32();
+            ALOGV("%s: CREATE_STREAM: width = %d", __FUNCTION__, width);
+            height = data.readInt32();
+            ALOGV("%s: CREATE_STREAM: height = %d", __FUNCTION__, height);
+            format = data.readInt32();
+            ALOGV("%s: CREATE_STREAM: format = %d", __FUNCTION__, format);
+
+            sp<IGraphicBufferProducer> bp;
+            if (data.readInt32() != 0) {
+                String16 name = data.readString16();
+                bp = interface_cast<IGraphicBufferProducer>(
+                        data.readStrongBinder());
+
+                ALOGV("%s: CREATE_STREAM: bp = %p, name = %s", __FUNCTION__,
+                      bp.get(), String8(name).string());
+            } else {
+                ALOGV("%s: CREATE_STREAM: bp = unset, name = unset",
+                      __FUNCTION__);
+            }
+
+            status_t ret;
+            ret = createStream(width, height, format, bp);
+
+            reply->writeNoException();
+            ALOGV("%s: CREATE_STREAM: write noException", __FUNCTION__);
+            reply->writeInt32(ret);
+            ALOGV("%s: CREATE_STREAM: write ret = %d", __FUNCTION__, ret);
+
+            return NO_ERROR;
+        } break;
+
+        case CREATE_DEFAULT_REQUEST: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+
+            int templateId = data.readInt32();
+
+            CameraMetadata request;
+            status_t ret;
+            ret = createDefaultRequest(templateId, &request);
+
+            reply->writeNoException();
+            reply->writeInt32(ret);
+
+            reply->writeInt32(1); // to mark presence of metadata object
+            request.writeToParcel(const_cast<Parcel*>(reply));
+
+            return NO_ERROR;
+        } break;
+        case GET_CAMERA_INFO: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+
+            int cameraId = data.readInt32();
+
+            camera_metadata_t* info = NULL;
+            status_t ret;
+            ret = getCameraInfo(cameraId, &info);
+
+            reply->writeInt32(1); // to mark presence of metadata object
+            CameraMetadata::writeToParcel(*reply, info);
+
+            reply->writeNoException();
+            reply->writeInt32(ret);
+
+            free_camera_metadata(info);
+
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
index 8eeb2e7..fe2bd19 100644 (file)
@@ -22,6 +22,7 @@
 #include <utils/Vector.h>
 
 namespace android {
+class Parcel;
 
 /**
  * A convenience wrapper around the C-based camera_metadata_t library.
@@ -159,6 +160,12 @@ class CameraMetadata {
     status_t erase(uint32_t tag);
 
     /**
+     * Swap the underlying camera metadata between this and the other
+     * metadata object.
+     */
+    void swap(CameraMetadata &other);
+
+    /**
      * Dump contents into FD for debugging. The verbosity levels are
      * 0: Tag entry information only, no data values
      * 1: Level 0 plus at most 16 data values per entry
@@ -169,6 +176,31 @@ class CameraMetadata {
      */
     void dump(int fd, int verbosity = 1, int indentation = 0) const;
 
+    /**
+     * Serialization over Binder
+     */
+
+    // Metadata object is unchanged when reading from parcel fails.
+    status_t readFromParcel(Parcel *parcel);
+    status_t writeToParcel(Parcel *parcel) const;
+
+    /**
+      * Caller becomes the owner of the new metadata
+      * 'const Parcel' doesnt prevent us from calling the read functions.
+      *  which is interesting since it changes the internal state
+      *
+      * NULL can be returned when no metadata was sent, OR if there was an issue
+      * unpacking the serialized data (i.e. bad parcel or invalid structure).
+      */
+    static status_t readFromParcel(const Parcel &parcel,
+                                   camera_metadata_t** out);
+    /**
+      * Caller retains ownership of metadata
+      * - Write 2 (int32 + blob) args in the current position
+      */
+    static status_t writeToParcel(Parcel &parcel,
+                                  const camera_metadata_t* metadata);
+
   private:
     camera_metadata_t *mBuffer;
     bool               mLocked;
index 3c2e60a..fa715b7 100644 (file)
@@ -28,6 +28,8 @@ class ICameraClient;
 class IProCameraUser;
 class IProCameraCallbacks;
 class ICameraServiceListener;
+class ICameraDeviceUser;
+class ICameraDeviceCallbacks;
 
 class ICameraService : public IInterface
 {
@@ -40,6 +42,7 @@ public:
         GET_CAMERA_INFO,
         CONNECT,
         CONNECT_PRO,
+        CONNECT_DEVICE,
         ADD_LISTENER,
         REMOVE_LISTENER,
     };
@@ -77,6 +80,12 @@ public:
             int cameraId,
             const String16& clientPackageName,
             int clientUid) = 0;
+
+    virtual sp<ICameraDeviceUser> connect(
+            const sp<ICameraDeviceCallbacks>& cameraCb,
+            int cameraId,
+            const String16& clientPackageName,
+            int clientUid) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/camera/photography/CaptureRequest.h b/include/camera/photography/CaptureRequest.h
new file mode 100644 (file)
index 0000000..e56d61f
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef ANDROID_HARDWARE_PHOTOGRAPHY_CAPTUREREQUEST_H
+#define ANDROID_HARDWARE_PHOTOGRAPHY_CAPTUREREQUEST_H
+
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <camera/CameraMetadata.h>
+
+namespace android {
+
+class Surface;
+
+struct CaptureRequest : public virtual RefBase {
+public:
+
+    CameraMetadata          mMetadata;
+    Vector<sp<Surface> >    mSurfaceList;
+
+    /**
+     * Keep impl up-to-date with CaptureRequest.java in frameworks/base
+     */
+    status_t                readFromParcel(Parcel* parcel);
+    status_t                writeToParcel(Parcel* parcel) const;
+};
+}; // namespace android
+
+#endif
diff --git a/include/camera/photography/ICameraDeviceCallbacks.h b/include/camera/photography/ICameraDeviceCallbacks.h
new file mode 100644 (file)
index 0000000..041fa65
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef ANDROID_HARDWARE_PHOTOGRAPHY_CALLBACKS_H
+#define ANDROID_HARDWARE_PHOTOGRAPHY_CALLBACKS_H
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <utils/Timers.h>
+#include <system/camera.h>
+
+namespace android {
+class CameraMetadata;
+
+class ICameraDeviceCallbacks : public IInterface
+{
+    /**
+     * Keep up-to-date with ICameraDeviceCallbacks.aidl in frameworks/base
+     */
+public:
+    DECLARE_META_INTERFACE(CameraDeviceCallbacks);
+
+    // One way
+    virtual void            notifyCallback(int32_t msgType,
+                                           int32_t ext1,
+                                           int32_t ext2) = 0;
+
+    // One way
+    virtual void            onResultReceived(int32_t frameId,
+                                             const CameraMetadata& result) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnCameraDeviceCallbacks : public BnInterface<ICameraDeviceCallbacks>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/camera/photography/ICameraDeviceUser.h b/include/camera/photography/ICameraDeviceUser.h
new file mode 100644 (file)
index 0000000..1b8d666
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef ANDROID_HARDWARE_PHOTOGRAPHY_ICAMERADEVICEUSER_H
+#define ANDROID_HARDWARE_PHOTOGRAPHY_ICAMERADEVICEUSER_H
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+struct camera_metadata;
+
+namespace android {
+
+class ICameraDeviceUserClient;
+class IGraphicBufferProducer;
+class Surface;
+class CaptureRequest;
+class CameraMetadata;
+
+class ICameraDeviceUser : public IInterface
+{
+    /**
+     * Keep up-to-date with ICameraDeviceUser.aidl in frameworks/base
+     */
+public:
+    DECLARE_META_INTERFACE(CameraDeviceUser);
+
+    virtual void            disconnect() = 0;
+
+    /**
+     * Request Handling
+     **/
+
+    virtual int             submitRequest(sp<CaptureRequest> request,
+                                          bool streaming = false) = 0;
+    virtual status_t        cancelRequest(int requestId) = 0;
+
+    virtual status_t        deleteStream(int streamId) = 0;
+    virtual status_t        createStream(
+            int width, int height, int format,
+            const sp<IGraphicBufferProducer>& bufferProducer) = 0;
+
+    // Create a request object from a template.
+    virtual status_t        createDefaultRequest(int templateId,
+                                                 /*out*/
+                                                 CameraMetadata* request) = 0;
+    // Get static camera metadata
+    virtual status_t        getCameraInfo(int cameraId,
+                                          /*out*/
+                                          camera_metadata** info) = 0;
+
+};
+
+// ----------------------------------------------------------------------------
+
+class BnCameraDeviceUser: public BnInterface<ICameraDeviceUser>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif
index 83d9ccd..0eead1e 100644 (file)
@@ -31,6 +31,7 @@ LOCAL_SRC_FILES:=               \
     camera3/Camera3InputStream.cpp \
     camera3/Camera3OutputStream.cpp \
     camera3/Camera3ZslStream.cpp \
+    photography/CameraDeviceClient.cpp \
     gui/RingBufferConsumer.cpp \
 
 LOCAL_SHARED_LIBRARIES:= \
index 0623b89..5e4832c 100644 (file)
@@ -28,6 +28,8 @@
 #include "Camera2ClientBase.h"
 #include "camera2/ProFrameProcessor.h"
 
+#include "photography/CameraDeviceClient.h"
+
 #include "Camera2Device.h"
 
 namespace android {
@@ -325,5 +327,6 @@ void Camera2ClientBase<TClientBase>::SharedCameraCallbacks::clear() {
 
 template class Camera2ClientBase<CameraService::ProClient>;
 template class Camera2ClientBase<CameraService::Client>;
+template class Camera2ClientBase<CameraDeviceClientBase>;
 
 } // namespace android
index 9001efb..c9a24d7 100644 (file)
@@ -101,6 +101,10 @@ public:
 
 protected:
 
+    virtual sp<IBinder> asBinderWrapper() {
+        return IInterface::asBinder();
+    }
+
     virtual status_t      dumpDevice(int fd, const Vector<String16>& args);
 
     /** Binder client interface-related private members */
index 757a781..1b2204e 100644 (file)
@@ -41,6 +41,7 @@
 #include "CameraClient.h"
 #include "Camera2Client.h"
 #include "ProCamera2Client.h"
+#include "photography/CameraDeviceClient.h"
 
 namespace android {
 
@@ -164,7 +165,7 @@ void CameraService::onDeviceStatusChanged(int cameraId,
            Mutex::Autolock al(mServiceLock);
 
            /* Find all clients that we need to disconnect */
-           sp<Client> client = mClient[cameraId].promote();
+           sp<BasicClient> client = mClient[cameraId].promote();
            if (client.get() != NULL) {
                clientsToDisconnect.push_back(client);
            }
@@ -313,14 +314,14 @@ bool CameraService::validateConnect(int cameraId,
 bool CameraService::canConnectUnsafe(int cameraId,
                                      const String16& clientPackageName,
                                      const sp<IBinder>& remoteCallback,
-                                     sp<Client> &client) {
+                                     sp<BasicClient> &client) {
     String8 clientName8(clientPackageName);
     int callingPid = getCallingPid();
 
     if (mClient[cameraId] != 0) {
         client = mClient[cameraId].promote();
         if (client != 0) {
-            if (remoteCallback == client->getRemoteCallback()->asBinder()) {
+            if (remoteCallback == client->getRemote()) {
                 LOG1("CameraService::connect X (pid %d) (the same client)",
                      callingPid);
                 return true;
@@ -370,16 +371,17 @@ sp<ICamera> CameraService::connect(
         return NULL;
     }
 
-    sp<Client> client;
 
+    sp<Client> client;
     {
         Mutex::Autolock lock(mServiceLock);
+        sp<BasicClient> clientTmp;
         if (!canConnectUnsafe(cameraId, clientPackageName,
                               cameraClient->asBinder(),
-                              /*out*/client)) {
+                              /*out*/clientTmp)) {
             return NULL;
         } else if (client.get() != NULL) {
-            return client;
+            return static_cast<Client*>(clientTmp.get());
         }
 
         int facing = -1;
@@ -415,7 +417,8 @@ sp<ICamera> CameraService::connect(
             return NULL;
         }
 
-        if (!connectFinishUnsafe(client, client->asBinder())) {
+        if (!connectFinishUnsafe(client,
+                                 client->getRemote())) {
             // this is probably not recoverable.. maybe the client can try again
             // OK: we can only get here if we were originally in PRESENT state
             updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
@@ -434,12 +437,12 @@ sp<ICamera> CameraService::connect(
 }
 
 bool CameraService::connectFinishUnsafe(const sp<BasicClient>& client,
-                                        const sp<IBinder>& clientBinder) {
+                                        const sp<IBinder>& remoteCallback) {
     if (client->initialize(mModule) != OK) {
         return false;
     }
 
-    clientBinder->linkToDeath(this);
+    remoteCallback->linkToDeath(this);
 
     return true;
 }
@@ -464,7 +467,7 @@ sp<IProCameraUser> CameraService::connect(
     {
         Mutex::Autolock lock(mServiceLock);
         {
-            sp<Client> client;
+            sp<BasicClient> client;
             if (!canConnectUnsafe(cameraId, clientPackageName,
                                   cameraCb->asBinder(),
                                   /*out*/client)) {
@@ -494,7 +497,7 @@ sp<IProCameraUser> CameraService::connect(
             return NULL;
         }
 
-        if (!connectFinishUnsafe(client, client->asBinder())) {
+        if (!connectFinishUnsafe(client, client->getRemote())) {
             return NULL;
         }
 
@@ -509,6 +512,88 @@ sp<IProCameraUser> CameraService::connect(
     return client;
 }
 
+sp<ICameraDeviceUser> CameraService::connect(
+        const sp<ICameraDeviceCallbacks>& cameraCb,
+        int cameraId,
+        const String16& clientPackageName,
+        int clientUid)
+{
+    // TODO: this function needs to return status_t
+    // so that we have an error code when things go wrong and the client is NULL
+
+    String8 clientName8(clientPackageName);
+    int callingPid = getCallingPid();
+
+    LOG1("CameraService::connectDevice E (pid %d \"%s\", id %d)", callingPid,
+            clientName8.string(), cameraId);
+
+    if (!validateConnect(cameraId, /*inout*/clientUid)) {
+        return NULL;
+    }
+
+    sp<CameraDeviceClient> client;
+    {
+        Mutex::Autolock lock(mServiceLock);
+        {
+            sp<BasicClient> client;
+            if (!canConnectUnsafe(cameraId, clientPackageName,
+                                  cameraCb->asBinder(),
+                                  /*out*/client)) {
+                return NULL;
+            }
+        }
+
+        int facing = -1;
+        int deviceVersion = getDeviceVersion(cameraId, &facing);
+
+        // If there are other non-exclusive users of the camera,
+        //  this will tear them down before we can reuse the camera
+        if (isValidCameraId(cameraId)) {
+            // transition from PRESENT -> NOT_AVAILABLE
+            updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
+                         cameraId);
+        }
+
+        switch(deviceVersion) {
+          case CAMERA_DEVICE_API_VERSION_1_0:
+            ALOGE("Camera id %d uses old HAL, doesn't support CameraDevice",
+                  cameraId);
+            return NULL;
+            break;
+           // TODO: don't allow 2.0  Only allow 2.1 and higher
+          case CAMERA_DEVICE_API_VERSION_2_0:
+          case CAMERA_DEVICE_API_VERSION_2_1:
+          case CAMERA_DEVICE_API_VERSION_3_0:
+            client = new CameraDeviceClient(this, cameraCb, String16(),
+                    cameraId, facing, callingPid, USE_CALLING_UID, getpid());
+            break;
+          case -1:
+            ALOGE("Invalid camera id %d", cameraId);
+            return NULL;
+          default:
+            ALOGE("Unknown camera device HAL version: %d", deviceVersion);
+            return NULL;
+        }
+
+        if (!connectFinishUnsafe(client, client->getRemote())) {
+            // this is probably not recoverable.. maybe the client can try again
+            // OK: we can only get here if we were originally in PRESENT state
+            updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
+            return NULL;
+        }
+
+        LOG1("CameraService::connectDevice X (id %d, this pid is %d)", cameraId,
+                getpid());
+
+        mClient[cameraId] = client;
+    }
+    // important: release the mutex here so the client can call back
+    //    into the service from its destructor (can be at the end of the call)
+
+    return client;
+}
+
+
 status_t CameraService::addListener(
                                 const sp<ICameraServiceListener>& listener) {
     ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
@@ -566,14 +651,14 @@ void CameraService::removeClientByRemote(const wp<IBinder>& remoteBinder) {
     Mutex::Autolock lock(mServiceLock);
 
     int outIndex;
-    sp<Client> client = findClientUnsafe(remoteBinder, outIndex);
+    sp<BasicClient> client = findClientUnsafe(remoteBinder, outIndex);
 
     if (client != 0) {
         // Found our camera, clear and leave.
         LOG1("removeClient: clear camera %d", outIndex);
         mClient[outIndex].clear();
 
-        client->unlinkToDeath(this);
+        client->getRemote()->unlinkToDeath(this);
     } else {
 
         sp<ProClient> clientPro = findProClientUnsafe(remoteBinder);
@@ -620,9 +705,9 @@ sp<CameraService::ProClient> CameraService::findProClientUnsafe(
     return clientPro;
 }
 
-sp<CameraService::Client> CameraService::findClientUnsafe(
+sp<CameraService::BasicClient> CameraService::findClientUnsafe(
                         const wp<IBinder>& cameraClient, int& outIndex) {
-    sp<Client> client;
+    sp<BasicClient> client;
 
     for (int i = 0; i < mNumberOfCameras; i++) {
 
@@ -640,7 +725,7 @@ sp<CameraService::Client> CameraService::findClientUnsafe(
             continue;
         }
 
-        if (cameraClient == client->getRemoteCallback()->asBinder()) {
+        if (cameraClient == client->getRemote()) {
             // Found our camera
             outIndex = i;
             return client;
@@ -651,7 +736,7 @@ sp<CameraService::Client> CameraService::findClientUnsafe(
     return NULL;
 }
 
-CameraService::Client* CameraService::getClientByIdUnsafe(int cameraId) {
+CameraService::BasicClient* CameraService::getClientByIdUnsafe(int cameraId) {
     if (cameraId < 0 || cameraId >= mNumberOfCameras) return NULL;
     return mClient[cameraId].unsafe_get();
 }
@@ -906,7 +991,9 @@ Mutex* CameraService::Client::getClientLockFromCookie(void* user) {
 // Provide client pointer for callbacks. Client lock returned from getClientLockFromCookie should
 // be acquired for this to be safe
 CameraService::Client* CameraService::Client::getClientFromCookie(void* user) {
-    Client* client = gCameraService->getClientByIdUnsafe((int) user);
+    BasicClient *basicClient = gCameraService->getClientByIdUnsafe((int) user);
+    // OK: only CameraClient calls this, and they already cast anyway.
+    Client* client = static_cast<Client*>(basicClient);
 
     // This could happen if the Client is in the process of shutting down (the
     // last strong reference is gone, but the destructor hasn't finished
@@ -1058,7 +1145,7 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {
                 }
             }
 
-            sp<Client> client = mClient[i].promote();
+            sp<BasicClient> client = mClient[i].promote();
             if (client == 0) {
                 result = String8::format("  Device is closed, no client instance\n");
                 write(fd, result.string(), result.size());
index eaa316a..cab804e 100644 (file)
@@ -29,6 +29,8 @@
 #include <camera/ICameraClient.h>
 #include <camera/IProCameraUser.h>
 #include <camera/IProCameraCallbacks.h>
+#include <camera/photography/ICameraDeviceUser.h>
+#include <camera/photography/ICameraDeviceCallbacks.h>
 
 #include <camera/ICameraServiceListener.h>
 
@@ -74,6 +76,11 @@ public:
             const String16& clientPackageName, int clientUid);
     virtual sp<IProCameraUser> connect(const sp<IProCameraCallbacks>& cameraCb,
             int cameraId, const String16& clientPackageName, int clientUid);
+    virtual sp<ICameraDeviceUser> connect(
+            const sp<ICameraDeviceCallbacks>& cameraCb,
+            int cameraId,
+            const String16& clientPackageName,
+            int clientUid);
 
     virtual status_t    addListener(const sp<ICameraServiceListener>& listener);
     virtual status_t    removeListener(
@@ -105,7 +112,7 @@ public:
 
     // returns plain pointer of client. Note that mClientLock should be acquired to
     // prevent the client from destruction. The result can be NULL.
-    virtual Client*     getClientByIdUnsafe(int cameraId);
+    virtual BasicClient* getClientByIdUnsafe(int cameraId);
     virtual Mutex*      getClientLockById(int cameraId);
 
     class BasicClient : public virtual RefBase {
@@ -114,11 +121,17 @@ public:
 
         virtual void          disconnect() = 0;
 
+        // because we can't virtually inherit IInterface, which breaks
+        // virtual inheritance
+        virtual sp<IBinder> asBinderWrapper() = 0;
+
         // Return the remote callback binder object (e.g. IProCameraCallbacks)
-        wp<IBinder>     getRemote() {
+        sp<IBinder>     getRemote() {
             return mRemoteBinder;
         }
 
+        virtual status_t      dump(int fd, const Vector<String16>& args) = 0;
+
     protected:
         BasicClient(const sp<CameraService>& cameraService,
                 const sp<IBinder>& remoteCallback,
@@ -147,7 +160,7 @@ public:
         pid_t                           mServicePid;     // immutable after constructor
 
         // - The app-side Binder interface to receive callbacks from us
-        wp<IBinder>                     mRemoteBinder;   // immutable after constructor
+        sp<IBinder>                     mRemoteBinder;   // immutable after constructor
 
         // permissions management
         status_t                        startCameraOps();
@@ -223,6 +236,10 @@ public:
             return mRemoteCallback;
         }
 
+        virtual sp<IBinder> asBinderWrapper() {
+            return asBinder();
+        }
+
     protected:
         static Mutex*        getClientLockFromCookie(void* user);
         // convert client from cookie. Client lock should be acquired before getting Client.
@@ -296,16 +313,17 @@ private:
                                          const String16& clientPackageName,
                                          const sp<IBinder>& remoteCallback,
                                          /*out*/
-                                         sp<Client> &client);
+                                         sp<BasicClient> &client);
 
     // When connection is successful, initialize client and track its death
     bool                connectFinishUnsafe(const sp<BasicClient>& client,
-                                            const sp<IBinder>& clientBinder);
+                                            const sp<IBinder>& remoteCallback);
 
     virtual sp<BasicClient>  getClientByRemote(const wp<IBinder>& cameraClient);
 
     Mutex               mServiceLock;
-    wp<Client>          mClient[MAX_CAMERAS];  // protected by mServiceLock
+    // either a Client or CameraDeviceClient
+    wp<BasicClient>     mClient[MAX_CAMERAS];  // protected by mServiceLock
     Mutex               mClientLock[MAX_CAMERAS]; // prevent Client destruction inside callbacks
     int                 mNumberOfCameras;
 
@@ -313,7 +331,7 @@ private:
     Vector<weak_pro_client_ptr> mProClientList[MAX_CAMERAS];
 
     // needs to be called with mServiceLock held
-    sp<Client>          findClientUnsafe(const wp<IBinder>& cameraClient, int& outIndex);
+    sp<BasicClient>     findClientUnsafe(const wp<IBinder>& cameraClient, int& outIndex);
     sp<ProClient>       findProClientUnsafe(
                                      const wp<IBinder>& cameraCallbacksRemote);
 
diff --git a/services/camera/libcameraservice/photography/CameraDeviceClient.cpp b/services/camera/libcameraservice/photography/CameraDeviceClient.cpp
new file mode 100644 (file)
index 0000000..3209a56
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#define LOG_TAG "CameraDeviceClient"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+// #define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <cutils/properties.h>
+#include <gui/Surface.h>
+#include "camera2/Parameters.h"
+#include "CameraDeviceClient.h"
+#include "camera2/ProFrameProcessor.h"
+#include "CameraDeviceBase.h"
+#include <camera/photography/CaptureRequest.h>
+
+namespace android {
+using namespace camera2;
+
+CameraDeviceClientBase::CameraDeviceClientBase(
+        const sp<CameraService>& cameraService,
+        const sp<ICameraDeviceCallbacks>& remoteCallback,
+        const String16& clientPackageName,
+        int cameraId,
+        int cameraFacing,
+        int clientPid,
+        uid_t clientUid,
+        int servicePid) :
+    BasicClient(cameraService, remoteCallback->asBinder(), clientPackageName,
+                cameraId, cameraFacing, clientPid, clientUid, servicePid),
+    mRemoteCallback(remoteCallback) {
+}
+void CameraDeviceClientBase::notifyError() {
+    // Thread safe. Don't bother locking.
+    sp<ICameraDeviceCallbacks> remoteCb = mRemoteCallback;
+
+    if (remoteCb != 0) {
+        remoteCb->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0);
+    }
+}
+
+// Interface used by CameraService
+
+CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
+                                   const sp<ICameraDeviceCallbacks>& remoteCallback,
+                                   const String16& clientPackageName,
+                                   int cameraId,
+                                   int cameraFacing,
+                                   int clientPid,
+                                   uid_t clientUid,
+                                   int servicePid) :
+    Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
+                cameraId, cameraFacing, clientPid, clientUid, servicePid),
+    mRequestIdCounter(0) {
+
+    ATRACE_CALL();
+    ALOGI("CameraDeviceClient %d: Opened", cameraId);
+}
+
+status_t CameraDeviceClient::initialize(camera_module_t *module)
+{
+    ATRACE_CALL();
+    status_t res;
+
+    res = Camera2ClientBase::initialize(module);
+    if (res != OK) {
+        return res;
+    }
+
+    String8 threadName;
+    mFrameProcessor = new ProFrameProcessor(mDevice);
+    threadName = String8::format("CDU-%d-FrameProc", mCameraId);
+    mFrameProcessor->run(threadName.string());
+
+    mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
+                                      FRAME_PROCESSOR_LISTENER_MAX_ID,
+                                      /*listener*/this);
+
+    return OK;
+}
+
+CameraDeviceClient::~CameraDeviceClient() {
+}
+
+status_t CameraDeviceClient::submitRequest(sp<CaptureRequest> request,
+                                         bool streaming) {
+    ATRACE_CALL();
+    ALOGV("%s", __FUNCTION__);
+
+    status_t res;
+
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
+    if (request == 0) {
+        ALOGE("%s: Camera %d: Sent null request. Rejecting request.",
+              __FUNCTION__, mCameraId);
+        return BAD_VALUE;
+    }
+
+    CameraMetadata metadata(request->mMetadata);
+
+    if (metadata.isEmpty()) {
+        ALOGE("%s: Camera %d: Sent empty metadata packet. Rejecting request.",
+               __FUNCTION__, mCameraId);
+        return BAD_VALUE;
+    } else if (request->mSurfaceList.size() == 0) {
+        ALOGE("%s: Camera %d: Requests must have at least one surface target. "
+              "Rejecting request.", __FUNCTION__, mCameraId);
+        return BAD_VALUE;
+    }
+
+    if (!enforceRequestPermissions(metadata)) {
+        // Callee logs
+        return PERMISSION_DENIED;
+    }
+
+    /**
+     * Write in the output stream IDs which we calculate from
+     * the capture request's list of surface targets
+     */
+    Vector<uint8_t> outputStreamIds;
+    outputStreamIds.setCapacity(request->mSurfaceList.size());
+    for (size_t i = 0; i < request->mSurfaceList.size(); ++i) {
+        sp<Surface> surface = request->mSurfaceList[i];
+
+        if (surface == 0) continue;
+
+        sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer();
+        int idx = mStreamMap.indexOfKey(gbp->asBinder());
+
+        // Trying to submit request with surface that wasn't created
+        if (idx == NAME_NOT_FOUND) {
+            ALOGE("%s: Camera %d: Tried to submit a request with a surface that"
+                  " we have not called createStream on",
+                  __FUNCTION__, mCameraId);
+            return BAD_VALUE;
+        }
+
+        int streamId = mStreamMap.valueAt(idx);
+        outputStreamIds.push_back(streamId);
+        ALOGV("%s: Camera %d: Appending output stream %d to request",
+              __FUNCTION__, mCameraId, streamId);
+    }
+
+    metadata.update(ANDROID_REQUEST_OUTPUT_STREAMS, &outputStreamIds[0],
+                    outputStreamIds.size());
+
+    // TODO: @hide ANDROID_REQUEST_ID, or use another request token
+    int32_t requestId = mRequestIdCounter++;
+    metadata.update(ANDROID_REQUEST_ID, &requestId, /*size*/1);
+    ALOGV("%s: Camera %d: Submitting request with ID %d",
+          __FUNCTION__, mCameraId, requestId);
+
+    if (streaming) {
+        res = mDevice->setStreamingRequest(metadata);
+        if (res != OK) {
+            ALOGE("%s: Camera %d:  Got error %d after trying to set streaming "
+                  "request", __FUNCTION__, mCameraId, res);
+        } else {
+            mStreamingRequestList.push_back(mRequestIdCounter);
+        }
+    } else {
+        res = mDevice->capture(metadata);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Got error %d after trying to set capture",
+                  __FUNCTION__, mCameraId, res);
+        }
+    }
+
+    ALOGV("%s: Camera %d: End of function", __FUNCTION__, mCameraId);
+    if (res == OK) {
+        return requestId;
+    }
+
+    return res;
+}
+
+status_t CameraDeviceClient::cancelRequest(int requestId) {
+    ATRACE_CALL();
+    ALOGV("%s, requestId = %d", __FUNCTION__, requestId);
+
+    status_t res;
+
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
+    Vector<int>::iterator it, end;
+    for (it = mStreamingRequestList.begin(), end = mStreamingRequestList.end();
+         it != end; ++it) {
+        if (*it == requestId) {
+            break;
+        }
+    }
+
+    if (it == end) {
+        ALOGE("%s: Camera%d: Did not find request id %d in list of streaming "
+              "requests", __FUNCTION__, mCameraId, requestId);
+        return BAD_VALUE;
+    }
+
+    res = mDevice->clearStreamingRequest();
+
+    if (res == OK) {
+        ALOGV("%s: Camera %d: Successfully cleared streaming request",
+              __FUNCTION__, mCameraId);
+        mStreamingRequestList.erase(it);
+    }
+
+    return res;
+}
+
+status_t CameraDeviceClient::deleteStream(int streamId) {
+    ATRACE_CALL();
+    ALOGV("%s (streamId = 0x%x)", __FUNCTION__, streamId);
+
+    status_t res;
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
+    // Guard against trying to delete non-created streams
+    ssize_t index = NAME_NOT_FOUND;
+    for (size_t i = 0; i < mStreamMap.size(); ++i) {
+        if (streamId == mStreamMap.valueAt(i)) {
+            index = i;
+            break;
+        }
+    }
+
+    if (index == NAME_NOT_FOUND) {
+        ALOGW("%s: Camera %d: Invalid stream ID (%d) specified, no stream "
+              "created yet", __FUNCTION__, mCameraId, streamId);
+        return BAD_VALUE;
+    }
+
+    // Also returns BAD_VALUE if stream ID was not valid
+    res = mDevice->deleteStream(streamId);
+
+    if (res == BAD_VALUE) {
+        ALOGE("%s: Camera %d: Unexpected BAD_VALUE when deleting stream, but we"
+              " already checked and the stream ID (%d) should be valid.",
+              __FUNCTION__, mCameraId, streamId);
+    } else if (res == OK) {
+        mStreamMap.removeItemsAt(index);
+
+        ALOGV("%s: Camera %d: Successfully deleted stream ID (%d)",
+              __FUNCTION__, mCameraId, streamId);
+    }
+
+    return res;
+}
+
+status_t CameraDeviceClient::createStream(int width, int height, int format,
+                      const sp<IGraphicBufferProducer>& bufferProducer)
+{
+    ATRACE_CALL();
+    ALOGV("%s (w = %d, h = %d, f = 0x%x)", __FUNCTION__, width, height, format);
+
+    status_t res;
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
+    // Don't create multiple streams for the same target surface
+    {
+        ssize_t index = mStreamMap.indexOfKey(bufferProducer->asBinder());
+        if (index != NAME_NOT_FOUND) {
+            ALOGW("%s: Camera %d: Buffer producer already has a stream for it "
+                  "(ID %d)",
+                  __FUNCTION__, mCameraId, index);
+            return ALREADY_EXISTS;
+        }
+    }
+
+    sp<IBinder> binder;
+    sp<ANativeWindow> anw;
+    if (bufferProducer != 0) {
+        binder = bufferProducer->asBinder();
+        anw = new Surface(bufferProducer);
+    }
+
+    // TODO: remove w,h,f since we are ignoring them
+
+    if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) {
+        ALOGE("%s: Camera %d: Failed to query Surface width", __FUNCTION__,
+              mCameraId);
+        return res;
+    }
+    if ((res = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, &height)) != OK) {
+        ALOGE("%s: Camera %d: Failed to query Surface height", __FUNCTION__,
+              mCameraId);
+        return res;
+    }
+    if ((res = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &format)) != OK) {
+        ALOGE("%s: Camera %d: Failed to query Surface format", __FUNCTION__,
+              mCameraId);
+        return res;
+    }
+
+    // FIXME: remove this override since the default format should be
+    //       IMPLEMENTATION_DEFINED. b/9487482
+    if (format != HAL_PIXEL_FORMAT_BLOB &&
+        format != HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        ALOGW("%s: Camera %d: Overriding format 0x%x to IMPLEMENTATION_DEFINED",
+              __FUNCTION__, mCameraId, format);
+        format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+    }
+
+    // TODO: add startConfigure/stopConfigure call to CameraDeviceBase
+    // this will make it so Camera3Device doesn't call configure_streams
+    // after each call, but only once we are done with all.
+
+    int streamId = -1;
+    res = mDevice->createStream(anw, width, height, format, /*size*/1,
+                                &streamId);
+
+    if (res == OK) {
+        mStreamMap.add(bufferProducer->asBinder(), streamId);
+
+        ALOGV("%s: Camera %d: Successfully created a new stream ID %d",
+              __FUNCTION__, mCameraId, streamId);
+        return streamId;
+    }
+
+    return res;
+}
+
+// Create a request object from a template.
+status_t CameraDeviceClient::createDefaultRequest(int templateId,
+                                                  /*out*/
+                                                  CameraMetadata* request)
+{
+    ATRACE_CALL();
+    ALOGV("%s (templateId = 0x%x)", __FUNCTION__, templateId);
+
+    status_t res;
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
+    CameraMetadata metadata;
+    if ( (res = mDevice->createDefaultRequest(templateId, &metadata) ) == OK &&
+        request != NULL) {
+
+        request->swap(metadata);
+    }
+
+    return res;
+}
+
+status_t CameraDeviceClient::getCameraInfo(int cameraId,
+                                         /*out*/
+                                         camera_metadata** info)
+{
+    ATRACE_CALL();
+    ALOGV("%s", __FUNCTION__);
+
+    status_t res = OK;
+
+    // TODO: remove cameraId. this should be device-specific info, not static.
+    if (cameraId != mCameraId) {
+        return INVALID_OPERATION;
+    }
+
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
+    CameraMetadata deviceInfo = mDevice->info();
+    *info = deviceInfo.release();
+
+    return res;
+}
+
+status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
+    String8 result;
+    result.appendFormat("CameraDeviceClient[%d] (%p) PID: %d, dump:\n",
+            mCameraId,
+            getRemoteCallback()->asBinder().get(),
+            mClientPid);
+    result.append("  State: ");
+
+    // TODO: print dynamic/request section from most recent requests
+    mFrameProcessor->dump(fd, args);
+
+    return dumpDevice(fd, args);
+}
+
+// TODO: refactor the code below this with IProCameraUser.
+// it's 100% copy-pasted, so lets not change it right now to make it easier.
+
+void CameraDeviceClient::detachDevice() {
+    if (mDevice == 0) return;
+
+    ALOGV("Camera %d: Stopping processors", mCameraId);
+
+    mFrameProcessor->removeListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
+                                    FRAME_PROCESSOR_LISTENER_MAX_ID,
+                                    /*listener*/this);
+    mFrameProcessor->requestExit();
+    ALOGV("Camera %d: Waiting for threads", mCameraId);
+    mFrameProcessor->join();
+    ALOGV("Camera %d: Disconnecting device", mCameraId);
+
+    // WORKAROUND: HAL refuses to disconnect while there's streams in flight
+    {
+        mDevice->clearStreamingRequest();
+
+        status_t code;
+        if ((code = mDevice->waitUntilDrained()) != OK) {
+            ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__,
+                  code);
+        }
+    }
+
+    Camera2ClientBase::detachDevice();
+}
+
+/** Device-related methods */
+void CameraDeviceClient::onFrameAvailable(int32_t frameId,
+                                        const CameraMetadata& frame) {
+    ATRACE_CALL();
+    ALOGV("%s", __FUNCTION__);
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+    SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
+
+    if (mRemoteCallback != NULL) {
+        ALOGV("%s: frame = %p ", __FUNCTION__, &frame);
+        mRemoteCallback->onResultReceived(frameId, frame);
+    }
+
+}
+
+// TODO: move to Camera2ClientBase
+bool CameraDeviceClient::enforceRequestPermissions(CameraMetadata& metadata) {
+
+    const int pid = IPCThreadState::self()->getCallingPid();
+    const int selfPid = getpid();
+    camera_metadata_entry_t entry;
+
+    /**
+     * Mixin default important security values
+     * - android.led.transmit = defaulted ON
+     */
+    CameraMetadata staticInfo = mDevice->info();
+    entry = staticInfo.find(ANDROID_LED_AVAILABLE_LEDS);
+    for(size_t i = 0; i < entry.count; ++i) {
+        uint8_t led = entry.data.u8[i];
+
+        switch(led) {
+            case ANDROID_LED_AVAILABLE_LEDS_TRANSMIT: {
+                uint8_t transmitDefault = ANDROID_LED_TRANSMIT_ON;
+                if (!metadata.exists(ANDROID_LED_TRANSMIT)) {
+                    metadata.update(ANDROID_LED_TRANSMIT,
+                                    &transmitDefault, 1);
+                }
+                break;
+            }
+        }
+    }
+
+    // We can do anything!
+    if (pid == selfPid) {
+        return true;
+    }
+
+    /**
+     * Permission check special fields in the request
+     * - android.led.transmit = android.permission.CAMERA_DISABLE_TRANSMIT
+     */
+    entry = metadata.find(ANDROID_LED_TRANSMIT);
+    if (entry.count > 0 && entry.data.u8[0] != ANDROID_LED_TRANSMIT_ON) {
+        String16 permissionString =
+            String16("android.permission.CAMERA_DISABLE_TRANSMIT_LED");
+        if (!checkCallingPermission(permissionString)) {
+            const int uid = IPCThreadState::self()->getCallingUid();
+            ALOGE("Permission Denial: "
+                  "can't disable transmit LED pid=%d, uid=%d", pid, uid);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/photography/CameraDeviceClient.h b/services/camera/libcameraservice/photography/CameraDeviceClient.h
new file mode 100644 (file)
index 0000000..806aa15
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_PHOTOGRAPHY_CAMERADEVICECLIENT_H
+#define ANDROID_SERVERS_CAMERA_PHOTOGRAPHY_CAMERADEVICECLIENT_H
+
+#include "CameraDeviceBase.h"
+#include "CameraService.h"
+#include "camera2/ProFrameProcessor.h"
+#include "Camera2ClientBase.h"
+#include <camera/photography/ICameraDeviceUser.h>
+#include <camera/photography/ICameraDeviceCallbacks.h>
+
+namespace android {
+
+struct CameraDeviceClientBase :
+        public CameraService::BasicClient, public BnCameraDeviceUser
+{
+    typedef ICameraDeviceCallbacks TCamCallbacks;
+
+    const sp<ICameraDeviceCallbacks>& getRemoteCallback() {
+        return mRemoteCallback;
+    }
+
+protected:
+    CameraDeviceClientBase(const sp<CameraService>& cameraService,
+            const sp<ICameraDeviceCallbacks>& remoteCallback,
+            const String16& clientPackageName,
+            int cameraId,
+            int cameraFacing,
+            int clientPid,
+            uid_t clientUid,
+            int servicePid);
+
+    virtual void notifyError();
+
+    sp<ICameraDeviceCallbacks> mRemoteCallback;
+};
+
+/**
+ * Implements the binder ICameraDeviceUser API,
+ * meant for HAL3-public implementation of
+ * android.hardware.photography.CameraDevice
+ */
+class CameraDeviceClient :
+        public Camera2ClientBase<CameraDeviceClientBase>,
+        public camera2::ProFrameProcessor::FilteredListener
+{
+public:
+    /**
+     * ICameraDeviceUser interface (see ICameraDeviceUser for details)
+     */
+
+    // Note that the callee gets a copy of the metadata.
+    virtual int           submitRequest(sp<CaptureRequest> request,
+                                        bool streaming = false);
+    virtual status_t      cancelRequest(int requestId);
+
+    // Returns -EBUSY if device is not idle
+    virtual status_t      deleteStream(int streamId);
+
+    virtual status_t      createStream(
+            int width,
+            int height,
+            int format,
+            const sp<IGraphicBufferProducer>& bufferProducer);
+
+    // Create a request object from a template.
+    virtual status_t      createDefaultRequest(int templateId,
+                                               /*out*/
+                                               CameraMetadata* request);
+
+    // Get the static metadata for the camera
+    // -- Caller owns the newly allocated metadata
+    virtual status_t      getCameraInfo(int cameraId,
+                                        /*out*/
+                                        camera_metadata** info);
+
+    /**
+     * Interface used by CameraService
+     */
+
+    CameraDeviceClient(const sp<CameraService>& cameraService,
+            const sp<ICameraDeviceCallbacks>& remoteCallback,
+            const String16& clientPackageName,
+            int cameraId,
+            int cameraFacing,
+            int clientPid,
+            uid_t clientUid,
+            int servicePid);
+    virtual ~CameraDeviceClient();
+
+    virtual status_t      initialize(camera_module_t *module);
+
+    virtual status_t      dump(int fd, const Vector<String16>& args);
+
+    /**
+     * Interface used by independent components of CameraDeviceClient.
+     */
+protected:
+    /** FilteredListener implementation **/
+    virtual void          onFrameAvailable(int32_t frameId,
+                                           const CameraMetadata& frame);
+    virtual void          detachDevice();
+
+private:
+    /** ICameraDeviceUser interface-related private members */
+
+    /** Preview callback related members */
+    sp<camera2::ProFrameProcessor> mFrameProcessor;
+    static const int32_t FRAME_PROCESSOR_LISTENER_MIN_ID = 0;
+    static const int32_t FRAME_PROCESSOR_LISTENER_MAX_ID = 0x7fffffffL;
+
+    /** Utility members */
+    bool enforceRequestPermissions(CameraMetadata& metadata);
+
+    // IGraphicsBufferProducer binder -> Stream ID
+    KeyedVector<sp<IBinder>, int> mStreamMap;
+
+    // Stream ID
+    Vector<int> mStreamingRequestList;
+
+    int32_t mRequestIdCounter;
+};
+
+}; // namespace android
+
+#endif