camera_client: refactor Camera/ProCamera commonalities into BasicCamera

Change-Id: Ie10a4094522d49683657665fe94ab0b7ccd280e9
diff --git a/camera/Android.mk b/camera/Android.mk
index 3e7e5a5..3f30079 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -16,6 +16,7 @@
 	IProCameraUser.cpp \
 	IProCameraCallbacks.cpp \
 	ProCamera.cpp \
+	CameraBase.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index d8dc2a5..f417c90 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -27,46 +27,16 @@
 #include <camera/Camera.h>
 #include <camera/ICameraRecordingProxyListener.h>
 #include <camera/ICameraService.h>
+#include <camera/ICamera.h>
 
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/Surface.h>
 
 namespace android {
 
-// client singleton for camera service binder interface
-Mutex Camera::mLock;
-sp<ICameraService> Camera::mCameraService;
-sp<Camera::DeathNotifier> Camera::mDeathNotifier;
-
-// establish binder interface to camera service
-const sp<ICameraService>& Camera::getCameraService()
+Camera::Camera(int cameraId)
+    : CameraBase(cameraId)
 {
-    Mutex::Autolock _l(mLock);
-    if (mCameraService.get() == 0) {
-        sp<IServiceManager> sm = defaultServiceManager();
-        sp<IBinder> binder;
-        do {
-            binder = sm->getService(String16("media.camera"));
-            if (binder != 0)
-                break;
-            ALOGW("CameraService not published, waiting...");
-            usleep(500000); // 0.5 s
-        } while(true);
-        if (mDeathNotifier == NULL) {
-            mDeathNotifier = new DeathNotifier();
-        }
-        binder->linkToDeath(mDeathNotifier);
-        mCameraService = interface_cast<ICameraService>(binder);
-    }
-    ALOGE_IF(mCameraService==0, "no CameraService!?");
-    return mCameraService;
-}
-
-// ---------------------------------------------------------------------------
-
-Camera::Camera()
-{
-    init();
 }
 
 // construct a camera client from an existing camera remote
@@ -78,7 +48,7 @@
          return 0;
      }
 
-    sp<Camera> c = new Camera();
+    sp<Camera> c = new Camera(-1);
     if (camera->connect(c) == NO_ERROR) {
         c->mStatus = NO_ERROR;
         c->mCamera = camera;
@@ -88,11 +58,6 @@
     return 0;
 }
 
-void Camera::init()
-{
-    mStatus = UNKNOWN_ERROR;
-}
-
 Camera::~Camera()
 {
     // We don't need to call disconnect() here because if the CameraService
@@ -103,47 +68,10 @@
     // deadlock if we call any method of ICamera here.
 }
 
-int32_t Camera::getNumberOfCameras()
-{
-    const sp<ICameraService>& cs = getCameraService();
-    if (cs == 0) return 0;
-    return cs->getNumberOfCameras();
-}
-
-status_t Camera::getCameraInfo(int cameraId,
-                               struct CameraInfo* cameraInfo) {
-    const sp<ICameraService>& cs = getCameraService();
-    if (cs == 0) return UNKNOWN_ERROR;
-    return cs->getCameraInfo(cameraId, cameraInfo);
-}
-
 sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
         int clientUid)
 {
-    ALOGV("connect");
-    sp<Camera> c = new Camera();
-    sp<ICameraClient> cl = c;
-    const sp<ICameraService>& cs = getCameraService();
-    if (cs != 0) {
-        c->mCamera = cs->connect(cl, cameraId, clientPackageName, clientUid);
-    }
-    if (c->mCamera != 0) {
-        c->mCamera->asBinder()->linkToDeath(c);
-        c->mStatus = NO_ERROR;
-    } else {
-        c.clear();
-    }
-    return c;
-}
-
-void Camera::disconnect()
-{
-    ALOGV("disconnect");
-    if (mCamera != 0) {
-        mCamera->disconnect();
-        mCamera->asBinder()->unlinkToDeath(this);
-        mCamera = 0;
-    }
+    return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
 }
 
 status_t Camera::reconnect()
@@ -154,11 +82,6 @@
     return c->connect(this);
 }
 
-sp<ICamera> Camera::remote()
-{
-    return mCamera;
-}
-
 status_t Camera::lock()
 {
     sp <ICamera> c = mCamera;
@@ -353,28 +276,14 @@
 // callback from camera service
 void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
 {
-    sp<CameraListener> listener;
-    {
-        Mutex::Autolock _l(mLock);
-        listener = mListener;
-    }
-    if (listener != NULL) {
-        listener->notify(msgType, ext1, ext2);
-    }
+    return CameraBaseT::notifyCallback(msgType, ext1, ext2);
 }
 
 // callback from camera service when frame or image is ready
 void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
                           camera_frame_metadata_t *metadata)
 {
-    sp<CameraListener> listener;
-    {
-        Mutex::Autolock _l(mLock);
-        listener = mListener;
-    }
-    if (listener != NULL) {
-        listener->postData(msgType, dataPtr, metadata);
-    }
+    return CameraBaseT::dataCallback(msgType, dataPtr, metadata);
 }
 
 // callback from camera service when timestamped frame is ready
@@ -393,31 +302,12 @@
         return;
     }
 
-    sp<CameraListener> listener;
-    {
-        Mutex::Autolock _l(mLock);
-        listener = mListener;
-    }
-    if (listener != NULL) {
-        listener->postDataTimestamp(timestamp, msgType, dataPtr);
-    } else {
+    if (!CameraBaseT::dataCallbackTimestamp(timestamp, msgType, dataPtr)) {
         ALOGW("No listener was set. Drop a recording frame.");
         releaseRecordingFrame(dataPtr);
     }
 }
 
-void Camera::binderDied(const wp<IBinder>& who) {
-    ALOGW("ICamera died");
-    notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_SERVER_DIED, 0);
-}
-
-void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) {
-    ALOGV("binderDied");
-    Mutex::Autolock _l(Camera::mLock);
-    Camera::mCameraService.clear();
-    ALOGW("Camera server died!");
-}
-
 sp<ICameraRecordingProxy> Camera::getRecordingProxy() {
     ALOGV("getProxy");
     return new RecordingProxy(this);
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
new file mode 100644
index 0000000..9b0e6bf
--- /dev/null
+++ b/camera/CameraBase.cpp
@@ -0,0 +1,237 @@
+/*
+**
+** 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_NDEBUG 0
+#define LOG_TAG "CameraBase"
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/Mutex.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IMemory.h>
+
+#include <camera/CameraBase.h>
+#include <camera/ICameraService.h>
+
+// needed to instantiate
+#include <camera/ProCamera.h>
+#include <camera/Camera.h>
+
+#include <system/camera_metadata.h>
+
+namespace android {
+
+namespace {
+    sp<ICameraService>        gCameraService;
+    const int                 kCameraServicePollDelay = 500000; // 0.5s
+    const char*               kCameraServiceName      = "media.camera";
+
+    Mutex                     gLock;
+
+    class DeathNotifier : public IBinder::DeathRecipient
+    {
+    public:
+        DeathNotifier() {
+        }
+
+        virtual void binderDied(const wp<IBinder>& who) {
+            ALOGV("binderDied");
+            Mutex::Autolock _l(gLock);
+            gCameraService.clear();
+            ALOGW("Camera service died!");
+        }
+    };
+
+    sp<DeathNotifier>         gDeathNotifier;
+}; // namespace anonymous
+
+///////////////////////////////////////////////////////////
+// CameraBase definition
+///////////////////////////////////////////////////////////
+
+// establish binder interface to camera service
+template <typename TCam, typename TCamTraits>
+const sp<ICameraService>& CameraBase<TCam, TCamTraits>::getCameraService()
+{
+    Mutex::Autolock _l(gLock);
+    if (gCameraService.get() == 0) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        do {
+            binder = sm->getService(String16(kCameraServiceName));
+            if (binder != 0) {
+                break;
+            }
+            ALOGW("CameraService not published, waiting...");
+            usleep(kCameraServicePollDelay);
+        } while(true);
+        if (gDeathNotifier == NULL) {
+            gDeathNotifier = new DeathNotifier();
+        }
+        binder->linkToDeath(gDeathNotifier);
+        gCameraService = interface_cast<ICameraService>(binder);
+    }
+    ALOGE_IF(gCameraService == 0, "no CameraService!?");
+    return gCameraService;
+}
+
+template <typename TCam, typename TCamTraits>
+sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
+                                         const String16& clientPackageName,
+                                               int clientUid)
+{
+    ALOGV("%s: connect", __FUNCTION__);
+    sp<TCam> c = new TCam(cameraId);
+    sp<TCamCallbacks> cl = c;
+    const sp<ICameraService>& cs = getCameraService();
+    if (cs != 0) {
+        c->mCamera = cs->connect(cl, cameraId, clientPackageName, clientUid);
+    }
+    if (c->mCamera != 0) {
+        c->mCamera->asBinder()->linkToDeath(c);
+        c->mStatus = NO_ERROR;
+    } else {
+        c.clear();
+    }
+    return c;
+}
+
+template <typename TCam, typename TCamTraits>
+void CameraBase<TCam, TCamTraits>::disconnect()
+{
+    ALOGV("%s: disconnect", __FUNCTION__);
+    if (mCamera != 0) {
+        mCamera->disconnect();
+        mCamera->asBinder()->unlinkToDeath(this);
+        mCamera = 0;
+    }
+    ALOGV("%s: disconnect (done)", __FUNCTION__);
+}
+
+template <typename TCam, typename TCamTraits>
+CameraBase<TCam, TCamTraits>::CameraBase(int cameraId) :
+    mStatus(UNKNOWN_ERROR),
+    mCameraId(cameraId)
+{
+}
+
+template <typename TCam, typename TCamTraits>
+CameraBase<TCam, TCamTraits>::~CameraBase()
+{
+}
+
+template <typename TCam, typename TCamTraits>
+sp<typename TCamTraits::TCamUser> CameraBase<TCam, TCamTraits>::remote()
+{
+    return mCamera;
+}
+
+template <typename TCam, typename TCamTraits>
+status_t CameraBase<TCam, TCamTraits>::getStatus()
+{
+    return mStatus;
+}
+
+template <typename TCam, typename TCamTraits>
+void CameraBase<TCam, TCamTraits>::binderDied(const wp<IBinder>& who) {
+    ALOGW("mediaserver's remote binder Camera object died");
+    notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_SERVER_DIED, /*ext2*/0);
+}
+
+template <typename TCam, typename TCamTraits>
+void CameraBase<TCam, TCamTraits>::setListener(const sp<TCamListener>& listener)
+{
+    Mutex::Autolock _l(mLock);
+    mListener = listener;
+}
+
+// callback from camera service
+template <typename TCam, typename TCamTraits>
+void CameraBase<TCam, TCamTraits>::notifyCallback(int32_t msgType,
+                                                  int32_t ext1,
+                                                  int32_t ext2)
+{
+    sp<TCamListener> listener;
+    {
+        Mutex::Autolock _l(mLock);
+        listener = mListener;
+    }
+    if (listener != NULL) {
+        listener->notify(msgType, ext1, ext2);
+    }
+}
+
+// callback from camera service when frame or image is ready
+template <typename TCam, typename TCamTraits>
+void CameraBase<TCam, TCamTraits>::dataCallback(int32_t msgType,
+                                                const sp<IMemory>& dataPtr,
+                                                camera_frame_metadata *metadata)
+{
+    sp<TCamListener> listener;
+    {
+        Mutex::Autolock _l(mLock);
+        listener = mListener;
+    }
+    if (listener != NULL) {
+        listener->postData(msgType, dataPtr, metadata);
+    }
+}
+
+// callback from camera service when timestamped frame is ready
+template <typename TCam, typename TCamTraits>
+bool CameraBase<TCam, TCamTraits>::dataCallbackTimestamp(nsecs_t timestamp,
+                                                         int32_t msgType,
+                                                   const sp<IMemory>& dataPtr)
+{
+    sp<TCamListener> listener;
+    {
+        Mutex::Autolock _l(mLock);
+        listener = mListener;
+    }
+    if (listener != NULL) {
+        listener->postDataTimestamp(timestamp, msgType, dataPtr);
+        return true;
+    }
+
+    return false;
+}
+
+template <typename TCam, typename TCamTraits>
+int CameraBase<TCam, TCamTraits>::getNumberOfCameras() {
+    const sp<ICameraService> cs = getCameraService();
+
+    if (!cs.get()) {
+        // as required by the public Java APIs
+        return 0;
+    }
+    return cs->getNumberOfCameras();
+}
+
+// this can be in BaseCamera but it should be an instance method
+template <typename TCam, typename TCamTraits>
+status_t CameraBase<TCam, TCamTraits>::getCameraInfo(int cameraId,
+                               struct CameraInfo* cameraInfo) {
+    const sp<ICameraService>& cs = getCameraService();
+    if (cs == 0) return UNKNOWN_ERROR;
+    return cs->getCameraInfo(cameraId, cameraInfo);
+}
+
+template class CameraBase<ProCamera>;
+template class CameraBase<Camera>;
+
+} // namespace android
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index fdf20ff..b54d63f 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -23,6 +23,10 @@
 #include <binder/IServiceManager.h>
 
 #include <camera/ICameraService.h>
+#include <camera/IProCameraUser.h>
+#include <camera/IProCameraCallbacks.h>
+#include <camera/ICamera.h>
+#include <camera/ICameraClient.h>
 
 namespace android {
 
@@ -70,12 +74,15 @@
     }
 
     // connect to camera service (pro client)
-    virtual sp<IProCameraUser> connect(const sp<IProCameraCallbacks>& cameraCb, int cameraId)
+    virtual sp<IProCameraUser> connect(const sp<IProCameraCallbacks>& 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_PRO, data, &reply);
         return interface_cast<IProCameraUser>(reply.readStrongBinder());
     }
@@ -119,7 +126,11 @@
         case CONNECT_PRO: {
             CHECK_INTERFACE(ICameraService, data, reply);
             sp<IProCameraCallbacks> cameraClient = interface_cast<IProCameraCallbacks>(data.readStrongBinder());
-            sp<IProCameraUser> camera = connect(cameraClient, data.readInt32());
+            int32_t cameraId = data.readInt32();
+            const String16 clientName = data.readString16();
+            int32_t clientUid = data.readInt32();
+            sp<IProCameraUser> camera = connect(cameraClient, cameraId,
+                                                clientName, clientUid);
             reply->writeStrongBinder(camera->asBinder());
             return NO_ERROR;
         } break;
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index 7c66d62..13ba07c 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -31,71 +31,19 @@
 #include <camera/IProCameraCallbacks.h>
 
 #include <gui/IGraphicBufferProducer.h>
-#include <gui/Surface.h>
 
 #include <system/camera_metadata.h>
 
 namespace android {
 
-// client singleton for camera service binder interface
-Mutex ProCamera::mLock;
-sp<ICameraService> ProCamera::mCameraService;
-sp<ProCamera::DeathNotifier> ProCamera::mDeathNotifier;
-
-// establish binder interface to camera service
-const sp<ICameraService>& ProCamera::getCameraService()
-{
-    Mutex::Autolock _l(mLock);
-    if (mCameraService.get() == 0) {
-        sp<IServiceManager> sm = defaultServiceManager();
-        sp<IBinder> binder;
-        do {
-            binder = sm->getService(String16("media.camera"));
-            if (binder != 0)
-                break;
-            ALOGW("CameraService not published, waiting...");
-            usleep(500000); // 0.5 s
-        } while(true);
-        if (mDeathNotifier == NULL) {
-            mDeathNotifier = new DeathNotifier();
-        }
-        binder->linkToDeath(mDeathNotifier);
-        mCameraService = interface_cast<ICameraService>(binder);
-    }
-    ALOGE_IF(mCameraService==0, "no CameraService!?");
-    return mCameraService;
-}
-
 sp<ProCamera> ProCamera::connect(int cameraId)
 {
-    ALOGV("connect");
-    sp<ProCamera> c = new ProCamera();
-    sp<IProCameraCallbacks> cl = c;
-    const sp<ICameraService>& cs = getCameraService();
-    if (cs != 0) {
-        c->mCamera = cs->connect(cl, cameraId);
-    }
-    if (c->mCamera != 0) {
-        c->mCamera->asBinder()->linkToDeath(c);
-        c->mStatus = NO_ERROR;
-    } else {
-        c.clear();
-    }
-    return c;
+    return CameraBaseT::connect(cameraId, String16(),
+                                 ICameraService::USE_CALLING_UID);
 }
 
-void ProCamera::disconnect()
-{
-    ALOGV("%s: disconnect", __FUNCTION__);
-    if (mCamera != 0) {
-        mCamera->disconnect();
-        mCamera->asBinder()->unlinkToDeath(this);
-        mCamera = 0;
-    }
-    ALOGV("%s: disconnect (done)", __FUNCTION__);
-}
-
-ProCamera::ProCamera()
+ProCamera::ProCamera(int cameraId)
+    : CameraBase(cameraId)
 {
 }
 
@@ -104,74 +52,28 @@
 
 }
 
-sp<IProCameraUser> ProCamera::remote()
-{
-    return mCamera;
-}
-
-void ProCamera::binderDied(const wp<IBinder>& who) {
-    ALOGW("IProCameraUser died");
-    notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_SERVER_DIED, 0);
-}
-
-void ProCamera::DeathNotifier::binderDied(const wp<IBinder>& who) {
-    ALOGV("binderDied");
-    Mutex::Autolock _l(ProCamera::mLock);
-    ProCamera::mCameraService.clear();
-    ALOGW("Camera service died!");
-}
-
-void ProCamera::setListener(const sp<ProCameraListener>& listener)
-{
-    Mutex::Autolock _l(mLock);
-    mListener = listener;
-}
-
+/* IProCameraUser's implementation */
 
 // callback from camera service
 void ProCamera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
 {
-    sp<ProCameraListener> listener;
-    {
-        Mutex::Autolock _l(mLock);
-        listener = mListener;
-    }
-    if (listener != NULL) {
-        listener->notify(msgType, ext1, ext2);
-    }
+    return CameraBaseT::notifyCallback(msgType, ext1, ext2);
 }
 
 // callback from camera service when frame or image is ready
 void ProCamera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
                           camera_frame_metadata_t *metadata)
 {
-    sp<ProCameraListener> listener;
-    {
-        Mutex::Autolock _l(mLock);
-        listener = mListener;
-    }
-    if (listener != NULL) {
-        listener->postData(msgType, dataPtr, metadata);
-    }
+    return CameraBaseT::dataCallback(msgType, dataPtr, metadata);
 }
 
 // callback from camera service when timestamped frame is ready
 void ProCamera::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
-                                                    const sp<IMemory>& dataPtr)
+                                   const sp<IMemory>& dataPtr)
 {
-    sp<ProCameraListener> listener;
-    {
-        Mutex::Autolock _l(mLock);
-        listener = mListener;
-    }
-    if (listener != NULL) {
-        listener->postDataTimestamp(timestamp, msgType, dataPtr);
-    } else {
-        ALOGW("No listener was set. Drop a recording frame.");
-    }
+    CameraBaseT::dataCallbackTimestamp(timestamp, msgType, dataPtr);
 }
 
-/* IProCameraUser's implementation */
 
 void ProCamera::onLockStatusChanged(
                                  IProCameraCallbacks::LockStatus newLockStatus)
@@ -291,9 +193,9 @@
 }
 
 status_t ProCamera::createStream(int width, int height, int format,
-                          const sp<Surface>& surface,
-                          /*out*/
-                          int* streamId)
+                                 const sp<Surface>& surface,
+                                 /*out*/
+                                 int* streamId)
 {
     *streamId = -1;
 
@@ -304,14 +206,15 @@
         return BAD_VALUE;
     }
 
-    return createStream(width, height, format, surface->getIGraphicBufferProducer(),
+    return createStream(width, height, format,
+                        surface->getIGraphicBufferProducer(),
                         streamId);
 }
 
 status_t ProCamera::createStream(int width, int height, int format,
-                          const sp<IGraphicBufferProducer>& bufferProducer,
-                          /*out*/
-                          int* streamId) {
+                                 const sp<IGraphicBufferProducer>& bufferProducer,
+                                 /*out*/
+                                 int* streamId) {
     *streamId = -1;
 
     ALOGV("%s: createStreamT %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
@@ -335,10 +238,10 @@
 }
 
 status_t ProCamera::createStreamCpu(int width, int height, int format,
-                          int heapCount,
-                          /*out*/
-                          sp<CpuConsumer>* cpuConsumer,
-                          int* streamId)
+                                    int heapCount,
+                                    /*out*/
+                                    sp<CpuConsumer>* cpuConsumer,
+                                    int* streamId)
 {
     ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
                                                                         format);
@@ -354,8 +257,9 @@
     sp<Surface> stc = new Surface(
         cc->getProducerInterface());
 
-    status_t s = createStream(width, height, format, stc->getIGraphicBufferProducer(),
-                        streamId);
+    status_t s = createStream(width, height, format,
+                              stc->getIGraphicBufferProducer(),
+                              streamId);
 
     if (s != OK) {
         ALOGE("%s: Failure to create stream %dx%d (fmt=0x%x)", __FUNCTION__,
@@ -379,15 +283,6 @@
     return s;
 }
 
-int ProCamera::getNumberOfCameras() {
-    const sp<ICameraService> cs = getCameraService();
-
-    if (!cs.get()) {
-        return DEAD_OBJECT;
-    }
-    return cs->getNumberOfCameras();
-}
-
 camera_metadata* ProCamera::getCameraInfo(int cameraId) {
     ALOGV("%s: cameraId = %d", __FUNCTION__, cameraId);