Merge "Remove tee sink debugging at compile time" into jb-mr2-dev
diff --git a/camera/Android.mk b/camera/Android.mk
index 3e7e5a5..e33fb50 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -11,11 +11,13 @@
 	ICamera.cpp \
 	ICameraClient.cpp \
 	ICameraService.cpp \
+	ICameraServiceListener.cpp \
 	ICameraRecordingProxy.cpp \
 	ICameraRecordingProxyListener.cpp \
 	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..29096da
--- /dev/null
+++ b/camera/CameraBase.cpp
@@ -0,0 +1,253 @@
+/*
+**
+** 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 <typename TCam, typename TCamTraits>
+status_t CameraBase<TCam, TCamTraits>::addServiceListener(
+                            const sp<ICameraServiceListener>& listener) {
+    const sp<ICameraService>& cs = getCameraService();
+    if (cs == 0) return UNKNOWN_ERROR;
+    return cs->addListener(listener);
+}
+
+template <typename TCam, typename TCamTraits>
+status_t CameraBase<TCam, TCamTraits>::removeServiceListener(
+                            const sp<ICameraServiceListener>& listener) {
+    const sp<ICameraService>& cs = getCameraService();
+    if (cs == 0) return UNKNOWN_ERROR;
+    return cs->removeListener(listener);
+}
+
+template class CameraBase<ProCamera>;
+template class CameraBase<Camera>;
+
+} // namespace android
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index fdf20ff..134f7f0 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -23,6 +23,11 @@
 #include <binder/IServiceManager.h>
 
 #include <camera/ICameraService.h>
+#include <camera/ICameraServiceListener.h>
+#include <camera/IProCameraUser.h>
+#include <camera/IProCameraCallbacks.h>
+#include <camera/ICamera.h>
+#include <camera/ICameraClient.h>
 
 namespace android {
 
@@ -70,15 +75,36 @@
     }
 
     // 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());
     }
+
+    virtual status_t addListener(const sp<ICameraServiceListener>& listener)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+        data.writeStrongBinder(listener->asBinder());
+        remote()->transact(BnCameraService::ADD_LISTENER, data, &reply);
+        return reply.readInt32();
+    }
+
+    virtual status_t removeListener(const sp<ICameraServiceListener>& listener)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+        data.writeStrongBinder(listener->asBinder());
+        remote()->transact(BnCameraService::REMOVE_LISTENER, data, &reply);
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService");
@@ -119,10 +145,28 @@
         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;
+        case ADD_LISTENER: {
+            CHECK_INTERFACE(ICameraService, data, reply);
+            sp<ICameraServiceListener> listener =
+                interface_cast<ICameraServiceListener>(data.readStrongBinder());
+            reply->writeInt32(addListener(listener));
+            return NO_ERROR;
+        } break;
+        case REMOVE_LISTENER: {
+            CHECK_INTERFACE(ICameraService, data, reply);
+            sp<ICameraServiceListener> listener =
+                interface_cast<ICameraServiceListener>(data.readStrongBinder());
+            reply->writeInt32(removeListener(listener));
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/camera/ICameraServiceListener.cpp b/camera/ICameraServiceListener.cpp
new file mode 100644
index 0000000..640ee35
--- /dev/null
+++ b/camera/ICameraServiceListener.cpp
@@ -0,0 +1,86 @@
+/*
+**
+** 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.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <camera/ICameraServiceListener.h>
+
+namespace android {
+
+namespace {
+    enum {
+        STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION,
+    };
+}; // namespace anonymous
+
+class BpCameraServiceListener: public BpInterface<ICameraServiceListener>
+{
+
+public:
+    BpCameraServiceListener(const sp<IBinder>& impl)
+        : BpInterface<ICameraServiceListener>(impl)
+    {
+    }
+
+    virtual void onStatusChanged(Status status, int32_t cameraId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(
+                              ICameraServiceListener::getInterfaceDescriptor());
+
+        data.writeInt32(static_cast<int32_t>(status));
+        data.writeInt32(cameraId);
+
+        remote()->transact(STATUS_CHANGED,
+                           data,
+                           &reply,
+                           IBinder::FLAG_ONEWAY);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(CameraServiceListener,
+                         "android.hardware.ICameraServiceListener");
+
+// ----------------------------------------------------------------------
+
+status_t BnCameraServiceListener::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case STATUS_CHANGED: {
+            CHECK_INTERFACE(ICameraServiceListener, data, reply);
+
+            Status status = static_cast<Status>(data.readInt32());
+            int32_t cameraId = data.readInt32();
+
+            onStatusChanged(status, cameraId);
+
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index 7c66d62..3cfabf6 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,21 @@
 }
 
 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) {
+    return createStreamCpu(width, height, format, heapCount,
+                           /*synchronousMode*/true,
+                           cpuConsumer, streamId);
+}
+
+status_t ProCamera::createStreamCpu(int width, int height, int format,
+                                    int heapCount,
+                                    bool synchronousMode,
+                                    /*out*/
+                                    sp<CpuConsumer>* cpuConsumer,
+                                    int* streamId)
 {
     ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
                                                                         format);
@@ -348,14 +262,15 @@
     sp <IProCameraUser> c = mCamera;
     if (c == 0) return NO_INIT;
 
-    sp<CpuConsumer> cc = new CpuConsumer(heapCount);
+    sp<CpuConsumer> cc = new CpuConsumer(heapCount, synchronousMode);
     cc->setName(String8("ProCamera::mCpuConsumer"));
 
     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__,
@@ -368,6 +283,7 @@
 
     getStreamInfo(*streamId).cpuStream = true;
     getStreamInfo(*streamId).cpuConsumer = cc;
+    getStreamInfo(*streamId).synchronousMode = synchronousMode;
     getStreamInfo(*streamId).stc = stc;
     // for lifetime management
     getStreamInfo(*streamId).frameAvailableListener = frameAvailableListener;
@@ -379,15 +295,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);
 
@@ -478,6 +385,13 @@
         return BAD_VALUE;
     }
 
+    if (!si.synchronousMode) {
+        ALOGW("%s: No need to drop frames on asynchronous streams,"
+              " as asynchronous mode only keeps 1 latest frame around.",
+              __FUNCTION__);
+        return BAD_VALUE;
+    }
+
     int numDropped = 0;
     for (int i = 0; i < count; ++i) {
         CpuConsumer::LockedBuffer buffer;
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index f93e5cd..1a8564e 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -33,6 +33,8 @@
 #include <hardware/camera2.h> // for CAMERA2_TEMPLATE_PREVIEW only
 #include <camera/CameraMetadata.h>
 
+#include <camera/ICameraServiceListener.h>
+
 namespace android {
 namespace camera2 {
 namespace tests {
@@ -48,9 +50,9 @@
 #define TEST_FORMAT_DEPTH HAL_PIXEL_FORMAT_Y16
 
 // defaults for display "test"
-#define TEST_DISPLAY_FORMAT HAL_PIXEL_FORMAT_Y16
-#define TEST_DISPLAY_WIDTH 1280
-#define TEST_DISPLAY_HEIGHT 960
+#define TEST_DISPLAY_FORMAT HAL_PIXEL_FORMAT_Y8
+#define TEST_DISPLAY_WIDTH 320
+#define TEST_DISPLAY_HEIGHT 240
 
 #define TEST_CPU_FRAME_COUNT 2
 #define TEST_CPU_HEAP_COUNT 5
@@ -68,6 +70,52 @@
 
 class ProCameraTest;
 
+struct ServiceListener : public BnCameraServiceListener {
+
+    ServiceListener() :
+        mLatestStatus(STATUS_UNKNOWN),
+        mPrevStatus(STATUS_UNKNOWN)
+    {
+    }
+
+    void onStatusChanged(Status status, int32_t cameraId) {
+        dout << "On status changed: 0x" << std::hex
+             << status << " cameraId " << cameraId
+             << std::endl;
+
+        Mutex::Autolock al(mMutex);
+
+        mLatestStatus = status;
+        mCondition.broadcast();
+    }
+
+    status_t waitForStatusChange(Status& newStatus) {
+        Mutex::Autolock al(mMutex);
+
+        if (mLatestStatus != mPrevStatus) {
+            newStatus = mLatestStatus;
+            mPrevStatus = mLatestStatus;
+            return OK;
+        }
+
+        status_t stat = mCondition.waitRelative(mMutex,
+                                               TEST_LISTENER_TIMEOUT);
+
+        if (stat == OK) {
+            newStatus = mLatestStatus;
+            mPrevStatus = mLatestStatus;
+        }
+
+        return stat;
+    }
+
+    Condition mCondition;
+    Mutex mMutex;
+
+    Status mLatestStatus;
+    Status mPrevStatus;
+};
+
 enum ProEvent {
     UNKNOWN,
     ACQUIRED,
@@ -441,7 +489,6 @@
         }
         request.acquire(requestTmp);
     }
-
 };
 
 sp<Thread> ProCameraTest::mTestThread;
@@ -538,18 +585,52 @@
     }
 
     int depthStreamId = -1;
-    EXPECT_OK(mCamera->createStream(mDisplayW, mDisplayH, mDisplayFmt, surface,
-                                    &depthStreamId));
-    EXPECT_NE(-1, depthStreamId);
 
-    EXPECT_OK(mCamera->exclusiveTryLock());
+    sp<ServiceListener> listener = new ServiceListener();
+    EXPECT_OK(ProCamera::addServiceListener(listener));
 
-    uint8_t streams[] = { depthStreamId };
-    ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/1));
+    ServiceListener::Status currentStatus = ServiceListener::STATUS_AVAILABLE;
 
-    dout << "will sleep now for " << mDisplaySecs << std::endl;
-    sleep(mDisplaySecs);
+    dout << "Will now stream and resume infinitely..." << std::endl;
+    while (true) {
 
+        if (currentStatus == ServiceListener::STATUS_AVAILABLE) {
+
+            EXPECT_OK(mCamera->createStream(mDisplayW, mDisplayH, mDisplayFmt,
+                                            surface,
+                                            &depthStreamId));
+            EXPECT_NE(-1, depthStreamId);
+
+            EXPECT_OK(mCamera->exclusiveTryLock());
+
+            uint8_t streams[] = { depthStreamId };
+            ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(
+                                                 streams,
+                                                 /*count*/1));
+        }
+
+        ServiceListener::Status stat = ServiceListener::STATUS_UNKNOWN;
+
+        // TODO: maybe check for getch every once in a while?
+        while (listener->waitForStatusChange(/*out*/stat) != OK);
+
+        if (currentStatus != stat) {
+            if (stat == ServiceListener::STATUS_AVAILABLE) {
+                dout << "Reconnecting to camera" << std::endl;
+                mCamera = ProCamera::connect(CAMERA_ID);
+            } else if (stat == ServiceListener::STATUS_NOT_AVAILABLE) {
+                dout << "Disconnecting from camera" << std::endl;
+                mCamera->disconnect();
+            } else {
+                dout << "Unknown status change "
+                     << std::hex << stat << std::endl;
+            }
+
+            currentStatus = stat;
+        }
+    }
+
+    EXPECT_OK(ProCamera::removeServiceListener(listener));
     EXPECT_OK(mCamera->deleteStream(depthStreamId));
     EXPECT_OK(mCamera->exclusiveUnlock());
 }
@@ -980,7 +1061,7 @@
     EXPECT_OK(mCamera->exclusiveUnlock());
 }
 
-TEST_F(ProCameraTest, WaitForSingleStreamBufferAndDropFrames) {
+TEST_F(ProCameraTest, WaitForSingleStreamBufferAndDropFramesSync) {
     if (HasFatalFailure()) {
         return;
     }
@@ -990,7 +1071,8 @@
     int streamId = -1;
     sp<CpuConsumer> consumer;
     EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960,
-                  TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &consumer, &streamId));
+                  TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT,
+                  /*synchronousMode*/true, &consumer, &streamId));
     EXPECT_NE(-1, streamId);
 
     EXPECT_OK(mCamera->exclusiveTryLock());
@@ -1001,11 +1083,6 @@
 
     // Consume a couple of results
     for (int i = 0; i < NUM_REQUESTS; ++i) {
-        // Process at 10fps, stream is at 15fps.
-        // This means we will definitely fill up the buffer queue with
-        // extra buffers and need to drop them.
-        usleep(TEST_FRAME_PROCESSING_DELAY_US);
-
         int numFrames;
         EXPECT_TRUE((numFrames = mCamera->waitForFrameBuffer(streamId)) > 0);
 
@@ -1025,6 +1102,11 @@
                 ", dataPtr = " << (void*)buf.data <<
                 ", timestamp = " << buf.timestamp << std::endl;
 
+        // Process at 10fps, stream is at 15fps.
+        // This means we will definitely fill up the buffer queue with
+        // extra buffers and need to drop them.
+        usleep(TEST_FRAME_PROCESSING_DELAY_US);
+
         EXPECT_OK(consumer->unlockBuffer(buf));
     }
 
@@ -1033,6 +1115,102 @@
     EXPECT_OK(mCamera->exclusiveUnlock());
 }
 
+TEST_F(ProCameraTest, WaitForSingleStreamBufferAndDropFramesAsync) {
+    if (HasFatalFailure()) {
+        return;
+    }
+
+    const int NUM_REQUESTS = 20 * TEST_CPU_FRAME_COUNT;
+
+    int streamId = -1;
+    sp<CpuConsumer> consumer;
+    EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960,
+                  TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT,
+                  /*synchronousMode*/false, &consumer, &streamId));
+    EXPECT_NE(-1, streamId);
+
+    EXPECT_OK(mCamera->exclusiveTryLock());
+
+    uint8_t streams[] = { streamId };
+    ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/1,
+                                                     /*requests*/NUM_REQUESTS));
+
+    // Consume a couple of results
+    for (int i = 0; i < NUM_REQUESTS; ++i) {
+        int numFrames;
+        EXPECT_TRUE((numFrames = mCamera->waitForFrameBuffer(streamId)) > 0);
+
+        dout << "Dropped " << (numFrames - 1) << " frames" << std::endl;
+
+        // Skip the counter ahead, don't try to consume these frames again
+        i += numFrames-1;
+
+        // "Consume" the buffer
+        CpuConsumer::LockedBuffer buf;
+        EXPECT_OK(consumer->lockNextBuffer(&buf));
+
+        dout << "Buffer asynchronously received on streamId = " << streamId <<
+                ", dataPtr = " << (void*)buf.data <<
+                ", timestamp = " << buf.timestamp << std::endl;
+
+        // Process at 10fps, stream is at 15fps.
+        // This means we will definitely fill up the buffer queue with
+        // extra buffers and need to drop them.
+        usleep(TEST_FRAME_PROCESSING_DELAY_US);
+
+        EXPECT_OK(consumer->unlockBuffer(buf));
+    }
+
+    // Done: clean up
+    EXPECT_OK(mCamera->deleteStream(streamId));
+    EXPECT_OK(mCamera->exclusiveUnlock());
+}
+
+
+
+//TODO: refactor into separate file
+TEST_F(ProCameraTest, ServiceListenersSubscribe) {
+
+    ASSERT_EQ(4u, sizeof(ServiceListener::Status));
+
+    sp<ServiceListener> listener = new ServiceListener();
+
+    EXPECT_EQ(BAD_VALUE, ProCamera::removeServiceListener(listener));
+    EXPECT_OK(ProCamera::addServiceListener(listener));
+
+    EXPECT_EQ(ALREADY_EXISTS, ProCamera::addServiceListener(listener));
+    EXPECT_OK(ProCamera::removeServiceListener(listener));
+
+    EXPECT_EQ(BAD_VALUE, ProCamera::removeServiceListener(listener));
+}
+
+//TODO: refactor into separate file
+TEST_F(ProCameraTest, ServiceListenersFunctional) {
+
+    sp<ServiceListener> listener = new ServiceListener();
+
+    EXPECT_OK(ProCamera::addServiceListener(listener));
+
+    sp<Camera> cam = Camera::connect(CAMERA_ID,
+                                     /*clientPackageName*/String16(),
+                                     -1);
+    EXPECT_NE((void*)NULL, cam.get());
+
+    ServiceListener::Status stat = ServiceListener::STATUS_UNKNOWN;
+    EXPECT_OK(listener->waitForStatusChange(/*out*/stat));
+
+    EXPECT_EQ(ServiceListener::STATUS_NOT_AVAILABLE, stat);
+
+    if (cam.get()) {
+        cam->disconnect();
+    }
+
+    EXPECT_OK(listener->waitForStatusChange(/*out*/stat));
+    EXPECT_EQ(ServiceListener::STATUS_AVAILABLE, stat);
+
+    EXPECT_OK(ProCamera::removeServiceListener(listener));
+}
+
 
 
 }
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index be2b7f4..71c66ce 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -23,35 +23,13 @@
 #include <camera/ICameraClient.h>
 #include <camera/ICameraRecordingProxy.h>
 #include <camera/ICameraRecordingProxyListener.h>
+#include <camera/ICameraService.h>
+#include <camera/ICamera.h>
+#include <camera/CameraBase.h>
 
 namespace android {
 
-struct CameraInfo {
-    /**
-     * The direction that the camera faces to. It should be CAMERA_FACING_BACK
-     * or CAMERA_FACING_FRONT.
-     */
-    int facing;
-
-    /**
-     * The orientation of the camera image. The value is the angle that the
-     * camera image needs to be rotated clockwise so it shows correctly on the
-     * display in its natural orientation. It should be 0, 90, 180, or 270.
-     *
-     * For example, suppose a device has a naturally tall screen. The
-     * back-facing camera sensor is mounted in landscape. You are looking at
-     * the screen. If the top side of the camera sensor is aligned with the
-     * right edge of the screen in natural orientation, the value should be
-     * 90. If the top side of a front-facing camera sensor is aligned with the
-     * right of the screen, the value should be 270.
-     */
-    int orientation;
-};
-
-class ICameraService;
-class ICamera;
 class Surface;
-class Mutex;
 class String8;
 class String16;
 
@@ -65,32 +43,37 @@
     virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) = 0;
 };
 
-class Camera : public BnCameraClient, public IBinder::DeathRecipient
+class Camera;
+
+template <>
+struct CameraTraits<Camera>
+{
+    typedef CameraListener        TCamListener;
+    typedef ICamera               TCamUser;
+    typedef ICameraClient         TCamCallbacks;
+};
+
+class Camera :
+    public CameraBase<Camera>,
+    public BnCameraClient
 {
 public:
     enum {
-        USE_CALLING_UID = -1
+        USE_CALLING_UID = ICameraService::USE_CALLING_UID
     };
 
             // construct a camera client from an existing remote
     static  sp<Camera>  create(const sp<ICamera>& camera);
-    static  int32_t     getNumberOfCameras();
-    static  status_t    getCameraInfo(int cameraId,
-                                      struct CameraInfo* cameraInfo);
     static  sp<Camera>  connect(int cameraId,
                                 const String16& clientPackageName,
                                 int clientUid);
 
             virtual     ~Camera();
-            void        init();
 
             status_t    reconnect();
-            void        disconnect();
             status_t    lock();
             status_t    unlock();
 
-            status_t    getStatus() { return mStatus; }
-
             // pass the buffered Surface to the camera service
             status_t    setPreviewDisplay(const sp<Surface>& surface);
 
@@ -151,8 +134,6 @@
                                      camera_frame_metadata_t *metadata);
     virtual void        dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
 
-    sp<ICamera>         remote();
-
     class RecordingProxy : public BnCameraRecordingProxy
     {
     public:
@@ -168,35 +149,13 @@
     };
 
 protected:
-                        Camera();
+                        Camera(int cameraId);
                         Camera(const Camera&);
                         Camera& operator=(const Camera);
-                        virtual void binderDied(const wp<IBinder>& who);
 
-            class DeathNotifier: public IBinder::DeathRecipient
-            {
-            public:
-                DeathNotifier() {
-                }
+    sp<ICameraRecordingProxyListener>  mRecordingProxyListener;
 
-                virtual void binderDied(const wp<IBinder>& who);
-            };
-
-            static sp<DeathNotifier> mDeathNotifier;
-
-            // helper function to obtain camera service handle
-            static const sp<ICameraService>& getCameraService();
-
-            sp<ICamera>         mCamera;
-            status_t            mStatus;
-
-            sp<CameraListener>  mListener;
-            sp<ICameraRecordingProxyListener>  mRecordingProxyListener;
-
-            friend class DeathNotifier;
-
-            static  Mutex               mLock;
-            static  sp<ICameraService>  mCameraService;
+    friend class        CameraBase;
 };
 
 }; // namespace android
diff --git a/include/camera/CameraBase.h b/include/camera/CameraBase.h
new file mode 100644
index 0000000..2735a86
--- /dev/null
+++ b/include/camera/CameraBase.h
@@ -0,0 +1,123 @@
+/*
+ * 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_CAMERA_BASE_H
+#define ANDROID_HARDWARE_CAMERA_BASE_H
+
+#include <utils/Mutex.h>
+#include <camera/ICameraService.h>
+
+struct camera_frame_metadata;
+
+namespace android {
+
+struct CameraInfo {
+    /**
+     * The direction that the camera faces to. It should be CAMERA_FACING_BACK
+     * or CAMERA_FACING_FRONT.
+     */
+    int facing;
+
+    /**
+     * The orientation of the camera image. The value is the angle that the
+     * camera image needs to be rotated clockwise so it shows correctly on the
+     * display in its natural orientation. It should be 0, 90, 180, or 270.
+     *
+     * For example, suppose a device has a naturally tall screen. The
+     * back-facing camera sensor is mounted in landscape. You are looking at
+     * the screen. If the top side of the camera sensor is aligned with the
+     * right edge of the screen in natural orientation, the value should be
+     * 90. If the top side of a front-facing camera sensor is aligned with the
+     * right of the screen, the value should be 270.
+     */
+    int orientation;
+};
+
+template <typename TCam>
+struct CameraTraits {
+};
+
+template <typename TCam, typename TCamTraits = CameraTraits<TCam> >
+class CameraBase : public IBinder::DeathRecipient
+{
+public:
+    typedef typename TCamTraits::TCamListener    TCamListener;
+    typedef typename TCamTraits::TCamUser        TCamUser;
+    typedef typename TCamTraits::TCamCallbacks   TCamCallbacks;
+
+    static sp<TCam>      connect(int cameraId,
+                                 const String16& clientPackageName,
+                                 int clientUid);
+    virtual void         disconnect();
+
+    void                 setListener(const sp<TCamListener>& listener);
+
+    static int           getNumberOfCameras();
+
+    static status_t      getCameraInfo(int cameraId,
+                                       /*out*/
+                                       struct CameraInfo* cameraInfo);
+
+    static status_t      addServiceListener(
+                                    const sp<ICameraServiceListener>& listener);
+
+    static status_t      removeServiceListener(
+                                    const sp<ICameraServiceListener>& listener);
+
+    sp<TCamUser>         remote();
+
+    // Status is set to 'UNKNOWN_ERROR' after successful (re)connection
+    status_t             getStatus();
+
+protected:
+    CameraBase(int cameraId);
+    virtual              ~CameraBase();
+
+    ////////////////////////////////////////////////////////
+    // TCamCallbacks implementation
+    ////////////////////////////////////////////////////////
+    virtual void         notifyCallback(int32_t msgType, int32_t ext,
+                                        int32_t ext2);
+    virtual void         dataCallback(int32_t msgType,
+                                      const sp<IMemory>& dataPtr,
+                                      camera_frame_metadata *metadata);
+    bool                 dataCallbackTimestamp(nsecs_t timestamp,
+                                               int32_t msgType,
+                                               const sp<IMemory>& dataPtr);
+
+    ////////////////////////////////////////////////////////
+    // Common instance variables
+    ////////////////////////////////////////////////////////
+    Mutex                            mLock;
+
+    virtual void                     binderDied(const wp<IBinder>& who);
+
+    // helper function to obtain camera service handle
+    static const sp<ICameraService>& getCameraService();
+
+    sp<TCamUser>                     mCamera;
+    status_t                         mStatus;
+
+    sp<TCamListener>                 mListener;
+
+    const int                        mCameraId;
+
+    typedef CameraBase<TCam>        CameraBaseT;
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index aa64243..aaf6eb3 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -21,12 +21,14 @@
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
 
-#include <camera/ICameraClient.h>
-#include <camera/ICamera.h>
-#include <camera/IProCameraUser.h>
-
 namespace android {
 
+class ICamera;
+class ICameraClient;
+class IProCameraUser;
+class IProCameraCallbacks;
+class ICameraServiceListener;
+
 class ICameraService : public IInterface
 {
 public:
@@ -34,7 +36,9 @@
         GET_NUMBER_OF_CAMERAS = IBinder::FIRST_CALL_TRANSACTION,
         GET_CAMERA_INFO,
         CONNECT,
-        CONNECT_PRO
+        CONNECT_PRO,
+        ADD_LISTENER,
+        REMOVE_LISTENER,
     };
 
     enum {
@@ -44,9 +48,18 @@
 public:
     DECLARE_META_INTERFACE(CameraService);
 
-    virtual int32_t         getNumberOfCameras() = 0;
-    virtual status_t        getCameraInfo(int cameraId,
+    virtual int32_t  getNumberOfCameras() = 0;
+    virtual status_t getCameraInfo(int cameraId,
                                           struct CameraInfo* cameraInfo) = 0;
+
+    // Returns 'OK' if operation succeeded
+    // - Errors: ALREADY_EXISTS if the listener was already added
+    virtual status_t addListener(const sp<ICameraServiceListener>& listener)
+                                                                            = 0;
+    // Returns 'OK' if operation succeeded
+    // - Errors: BAD_VALUE if specified listener was not in the listener list
+    virtual status_t removeListener(const sp<ICameraServiceListener>& listener)
+                                                                            = 0;
     /**
      * clientPackageName and clientUid are used for permissions checking.  if
      * clientUid == USE_CALLING_UID, then the calling UID is used instead. Only
@@ -58,7 +71,9 @@
             int clientUid) = 0;
 
     virtual sp<IProCameraUser> connect(const sp<IProCameraCallbacks>& cameraCb,
-            int cameraId) = 0;
+            int cameraId,
+            const String16& clientPackageName,
+            int clientUid) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/camera/ICameraServiceListener.h b/include/camera/ICameraServiceListener.h
new file mode 100644
index 0000000..207116a
--- /dev/null
+++ b/include/camera/ICameraServiceListener.h
@@ -0,0 +1,64 @@
+/*
+ * 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_ICAMERASERVICE_LISTENER_H
+#define ANDROID_HARDWARE_ICAMERASERVICE_LISTENER_H
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <hardware/camera_common.h>
+
+namespace android {
+
+class ICameraServiceListener : public IInterface
+{
+public:
+
+    enum Status {
+        // Device physically unplugged
+        STATUS_PRESENT          = CAMERA_DEVICE_STATUS_PRESENT,
+        // Device physically re-plugged
+        STATUS_NOT_PRESENT      = CAMERA_DEVICE_STATUS_NOT_PRESENT,
+
+        // Camera can be used exclusively
+        STATUS_AVAILABLE        = 0x80000000,
+        // Camera is in use by another app and cannot be used exclusively
+        STATUS_NOT_AVAILABLE,
+
+        // Use to initialize variables only
+        STATUS_UNKNOWN          = 0xFFFFFFFF,
+    };
+
+    DECLARE_META_INTERFACE(CameraServiceListener);
+
+    virtual void onStatusChanged(Status status, int32_t cameraId) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnCameraServiceListener : public BnInterface<ICameraServiceListener>
+{
+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/ProCamera.h b/include/camera/ProCamera.h
index cd2772c..5d6cfaa 100644
--- a/include/camera/ProCamera.h
+++ b/include/camera/ProCamera.h
@@ -27,9 +27,13 @@
 #include <camera/CameraMetadata.h>
 #include <gui/CpuConsumer.h>
 
+#include <gui/Surface.h>
+
 #include <utils/Condition.h>
 #include <utils/Mutex.h>
 
+#include <camera/CameraBase.h>
+
 struct camera_metadata;
 
 namespace android {
@@ -53,6 +57,8 @@
     // OnBufferReceived and OnRequestReceived can come in with any order,
     // use android.sensor.timestamp and LockedBuffer.timestamp to correlate them
 
+    // TODO: remove onBufferReceived
+
     // A new frame buffer has been received for this stream.
     // -- This callback only fires for createStreamCpu streams
     // -- Use buf.timestamp to correlate with metadata's
@@ -67,22 +73,36 @@
       */
     virtual void onResultReceived(int32_t frameId, camera_metadata* result) = 0;
 
+    // TODO: make onFrameAvailable pure virtual
 
     // A new frame buffer has been received for this stream.
     // -- This callback only fires for createStreamCpu streams
     // -- Use buf.timestamp to correlate with metadata's android.sensor.timestamp
     // -- The buffer should be accessed with CpuConsumer::lockNextBuffer
     //      and CpuConsumer::unlockBuffer
-    virtual void onFrameAvailable(int streamId,
-                                  const sp<CpuConsumer>& cpuConsumer) {
+    virtual void onFrameAvailable(int /*streamId*/,
+                                  const sp<CpuConsumer>& /*cpuConsumer*/) {
     }
 
+    // TODO: Remove useOnFrameAvailable
     virtual bool useOnFrameAvailable() {
         return false;
     }
 };
 
-class ProCamera : public BnProCameraCallbacks, public IBinder::DeathRecipient
+class ProCamera;
+
+template <>
+struct CameraTraits<ProCamera>
+{
+    typedef ProCameraListener     TCamListener;
+    typedef IProCameraUser        TCamUser;
+    typedef IProCameraCallbacks   TCamCallbacks;
+};
+
+class ProCamera :
+    public CameraBase<ProCamera>,
+    public BnProCameraCallbacks
 {
 public:
     /**
@@ -91,11 +111,8 @@
      * to be acquired with exclusive[Try]Lock.
      */
     static sp<ProCamera> connect(int cameraId);
-    virtual void disconnect();
     virtual ~ProCamera();
 
-    void setListener(const sp<ProCameraListener>& listener);
-
     /**
      * Exclusive Locks:
      * - We may request exclusive access to a camera if no other
@@ -152,6 +169,9 @@
     /**
       * Delete a stream.
       * Lock free.
+      *
+      * NOTE: As a side effect this cancels ALL streaming requests.
+      *
       * Errors: BAD_VALUE if unknown stream ID.
       *         PERMISSION_DENIED if the stream wasn't yours
       */
@@ -181,15 +201,18 @@
                           /*out*/
                           sp<CpuConsumer>* cpuConsumer,
                           int* streamId);
+    status_t createStreamCpu(int width, int height, int format,
+                          int heapCount,
+                          bool synchronousMode,
+                          /*out*/
+                          sp<CpuConsumer>* cpuConsumer,
+                          int* streamId);
 
     // Create a request object from a template.
     status_t createDefaultRequest(int templateId,
                                  /*out*/
                                   camera_metadata** request) const;
 
-    // Get number of cameras
-    static int getNumberOfCameras();
-
     // Get static camera metadata
     camera_metadata* getCameraInfo(int cameraId);
 
@@ -222,8 +245,6 @@
     //   BAD_VALUE - invalid streamId or count passed
     int dropFrameBuffer(int streamId, int count);
 
-    sp<IProCameraUser>         remote();
-
 protected:
     ////////////////////////////////////////////////////////
     // IProCameraCallbacks implementation
@@ -241,35 +262,8 @@
 
     virtual void        onResultReceived(int32_t frameId,
                                          camera_metadata* result);
-
-    class DeathNotifier: public IBinder::DeathRecipient
-    {
-    public:
-        DeathNotifier() {
-        }
-
-        virtual void binderDied(const wp<IBinder>& who);
-    };
-
 private:
-    ProCamera();
-
-    virtual void binderDied(const wp<IBinder>& who);
-
-    // helper function to obtain camera service handle
-    static const sp<ICameraService>& getCameraService();
-
-    static sp<DeathNotifier> mDeathNotifier;
-
-    sp<IProCameraUser>  mCamera;
-    status_t            mStatus;
-
-    sp<ProCameraListener>  mListener;
-
-    friend class DeathNotifier;
-
-    static  Mutex               mLock;
-    static  sp<ICameraService>  mCameraService;
+    ProCamera(int cameraId);
 
     class ProFrameListener : public CpuConsumer::FrameAvailableListener {
     public:
@@ -308,6 +302,7 @@
         int  streamID;
         bool cpuStream;
         sp<CpuConsumer> cpuConsumer;
+        bool synchronousMode;
         sp<ProFrameListener> frameAvailableListener;
         sp<Surface> stc;
         int frameReady;
@@ -324,7 +319,7 @@
 
     StreamInfo& getStreamInfo(int streamId);
 
-
+    friend class CameraBase;
 };
 
 }; // namespace android
diff --git a/include/media/AudioBufferProvider.h b/include/media/AudioBufferProvider.h
index 865ed7e..43e4de7 100644
--- a/include/media/AudioBufferProvider.h
+++ b/include/media/AudioBufferProvider.h
@@ -36,11 +36,8 @@
         size_t frameCount;
     };
 
-protected:
-    AudioBufferProvider() : mValid(kValid) { }
-    virtual ~AudioBufferProvider() { mValid = kDead; }
+    virtual ~AudioBufferProvider() {}
 
-public:
     // value representing an invalid presentation timestamp
     static const int64_t kInvalidPTS = 0x7FFFFFFFFFFFFFFFLL;    // <stdint.h> is too painful
 
@@ -50,13 +47,6 @@
     virtual status_t getNextBuffer(Buffer* buffer, int64_t pts = kInvalidPTS) = 0;
 
     virtual void releaseBuffer(Buffer* buffer) = 0;
-
-    int getValid() const { return mValid; }
-    static const int kValid = 'GOOD';
-    static const int kDead = 'DEAD';
-
-private:
-    int mValid;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 14986b2..056b47a 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -2612,7 +2612,8 @@
     mOwner->writeInt32(0x480000);    // vert resolution
     mOwner->writeInt32(0);           // reserved
     mOwner->writeInt16(1);           // frame count
-    mOwner->write("                                ", 32);
+    mOwner->writeInt8(0);            // compressor string length
+    mOwner->write("                               ", 31);
     mOwner->writeInt16(0x18);        // depth
     mOwner->writeInt16(-1);          // predefined
 
diff --git a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
index c5f733b..4d4212f 100644
--- a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
@@ -154,7 +154,7 @@
 
             amrParams->nChannels = 1;
             amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
-            amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatConformance;
+            amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
 
             if (!isConfigured()) {
                 amrParams->nBitRate = 0;
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index 13dfc8c..922ac61 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -93,7 +93,7 @@
 
     def.format.audio.pNativeRender = NULL;
     def.format.audio.bFlagErrorConcealment = OMX_FALSE;
-    def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingVORBIS;
 
     addPort(def);
 
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 82fb637..9499712 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -536,7 +536,7 @@
     size_t nalSize;
     bool foundSlice = false;
     while ((err = getNextNALUnit(&data, &size, &nalStart, &nalSize)) == OK) {
-        CHECK_GT(nalSize, 0u);
+        if (nalSize == 0) continue;
 
         unsigned nalType = nalStart[0] & 0x1f;
         bool flush = false;
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 2a8a955..17b6a8a 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -1113,12 +1113,6 @@
         e0 &= ~(1<<i);
         track_t& t = state->tracks[i];
         t.buffer.frameCount = state->frameCount;
-        int valid = t.bufferProvider->getValid();
-        if (valid != AudioBufferProvider::kValid) {
-            ALOGE("invalid bufferProvider=%p name=%d frameCount=%d valid=%#x enabledTracks=%#x",
-                    t.bufferProvider, i, t.buffer.frameCount, valid, enabledTracks);
-            // expect to crash
-        }
         t.bufferProvider->getNextBuffer(&t.buffer, pts);
         t.frameCount = t.buffer.frameCount;
         t.in = t.buffer.raw;
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index f76c861..d6ad889 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -11,7 +11,9 @@
     CameraClient.cpp \
     Camera2Client.cpp \
     ProCamera2Client.cpp \
+    CameraDeviceBase.cpp \
     Camera2Device.cpp \
+    Camera3Device.cpp \
     camera2/Parameters.cpp \
     camera2/FrameProcessor.cpp \
     camera2/StreamingProcessor.cpp \
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index 38d6949..8295905 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -25,6 +25,8 @@
 #include <gui/Surface.h>
 #include "camera2/Parameters.h"
 #include "Camera2Client.h"
+#include "Camera2Device.h"
+#include "Camera3Device.h"
 
 #define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
 #define ALOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
@@ -45,7 +47,8 @@
         int cameraFacing,
         int clientPid,
         uid_t clientUid,
-        int servicePid):
+        int servicePid,
+        int deviceVersion):
         Client(cameraService, cameraClient, clientPackageName,
                 cameraId, cameraFacing, clientPid, clientUid, servicePid),
         mSharedCameraClient(cameraClient),
@@ -54,7 +57,20 @@
     ATRACE_CALL();
     ALOGI("Camera %d: Opened", cameraId);
 
-    mDevice = new Camera2Device(cameraId);
+    switch (deviceVersion) {
+        case CAMERA_DEVICE_API_VERSION_2_0:
+            mDevice = new Camera2Device(cameraId);
+            break;
+        case CAMERA_DEVICE_API_VERSION_3_0:
+            mDevice = new Camera3Device(cameraId);
+            break;
+        default:
+            ALOGE("Camera %d: Unknown HAL device version %d",
+                    cameraId, deviceVersion);
+            mDevice = NULL;
+            break;
+    }
+
 
     SharedParameters::Lock l(mParameters);
     l.mParameters.state = Parameters::DISCONNECTED;
@@ -81,6 +97,12 @@
         return res;
     }
 
+    if (mDevice == NULL) {
+        ALOGE("%s: Camera %d: No device connected",
+                __FUNCTION__, mCameraId);
+        return NO_INIT;
+    }
+
     res = mDevice->initialize(module);
     if (res != OK) {
         ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
@@ -1465,7 +1487,7 @@
     return mCameraId;
 }
 
-const sp<Camera2Device>& Camera2Client::getCameraDevice() {
+const sp<CameraDeviceBase>& Camera2Client::getCameraDevice() {
     return mDevice;
 }
 
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h
index 173b65e..80b88f4 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_H
 #define ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_H
 
-#include "Camera2Device.h"
+#include "CameraDeviceBase.h"
 #include "CameraService.h"
 #include "camera2/Parameters.h"
 #include "camera2/FrameProcessor.h"
@@ -31,12 +31,12 @@
 
 class IMemory;
 /**
- * Implements the android.hardware.camera API on top of
- * camera device HAL version 2.
+ * Interface between android.hardware.Camera API and Camera HAL device for versions
+ * CAMERA_DEVICE_API_VERSION_2_0 and 3_0.
  */
 class Camera2Client :
         public CameraService::Client,
-        public Camera2Device::NotificationListener
+        public CameraDeviceBase::NotificationListener
 {
 public:
     /**
@@ -77,7 +77,9 @@
             int cameraFacing,
             int clientPid,
             uid_t clientUid,
-            int servicePid);
+            int servicePid,
+            int deviceVersion);
+
     virtual ~Camera2Client();
 
     status_t initialize(camera_module_t *module);
@@ -85,7 +87,7 @@
     virtual status_t dump(int fd, const Vector<String16>& args);
 
     /**
-     * Interface used by Camera2Device
+     * Interface used by CameraDeviceBase
      */
 
     virtual void notifyError(int errorCode, int arg1, int arg2);
@@ -99,7 +101,7 @@
      */
 
     int getCameraId() const;
-    const sp<Camera2Device>& getCameraDevice();
+    const sp<CameraDeviceBase>& getCameraDevice();
     const sp<CameraService>& getCameraService();
     camera2::SharedParameters& getParameters();
 
@@ -211,9 +213,9 @@
 
     bool mAfInMotion;
 
-    /** Camera2Device instance wrapping HAL2 entry */
+    /** CameraDevice instance, wraps HAL camera device */
 
-    sp<Camera2Device> mDevice;
+    sp<CameraDeviceBase> mDevice;
 
     /** Utility members */
 
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index 921c8fc..81e58ca 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -34,7 +34,7 @@
 
 Camera2Device::Camera2Device(int id):
         mId(id),
-        mDevice(NULL)
+        mHal2Device(NULL)
 {
     ATRACE_CALL();
     ALOGV("%s: Created device for camera %d", __FUNCTION__, id);
@@ -51,7 +51,7 @@
 {
     ATRACE_CALL();
     ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId);
-    if (mDevice != NULL) {
+    if (mHal2Device != NULL) {
         ALOGE("%s: Already initialized!", __FUNCTION__);
         return INVALID_OPERATION;
     }
@@ -131,7 +131,7 @@
     }
 
     mDeviceInfo = info.static_camera_characteristics;
-    mDevice = device;
+    mHal2Device = device;
 
     return OK;
 }
@@ -139,23 +139,23 @@
 status_t Camera2Device::disconnect() {
     ATRACE_CALL();
     status_t res = OK;
-    if (mDevice) {
+    if (mHal2Device) {
         ALOGV("%s: Closing device for camera %d", __FUNCTION__, mId);
 
-        int inProgressCount = mDevice->ops->get_in_progress_count(mDevice);
+        int inProgressCount = mHal2Device->ops->get_in_progress_count(mHal2Device);
         if (inProgressCount > 0) {
             ALOGW("%s: Closing camera device %d with %d requests in flight!",
                     __FUNCTION__, mId, inProgressCount);
         }
         mReprocessStreams.clear();
         mStreams.clear();
-        res = mDevice->common.close(&mDevice->common);
+        res = mHal2Device->common.close(&mHal2Device->common);
         if (res != OK) {
             ALOGE("%s: Could not close camera %d: %s (%d)",
                     __FUNCTION__,
                     mId, strerror(-res), res);
         }
-        mDevice = NULL;
+        mHal2Device = NULL;
         ALOGV("%s: Shutdown complete", __FUNCTION__);
     }
     return res;
@@ -197,7 +197,7 @@
     write(fd, result.string(), result.size());
 
     status_t res;
-    res = mDevice->ops->dump(mDevice, fd);
+    res = mHal2Device->ops->dump(mHal2Device, fd);
 
     return res;
 }
@@ -240,7 +240,7 @@
     status_t res;
     ALOGV("%s: E", __FUNCTION__);
 
-    sp<StreamAdapter> stream = new StreamAdapter(mDevice);
+    sp<StreamAdapter> stream = new StreamAdapter(mHal2Device);
 
     res = stream->connectToDevice(consumer, width, height, format, size);
     if (res != OK) {
@@ -276,7 +276,7 @@
         return BAD_VALUE;
     }
 
-    sp<ReprocessStreamAdapter> stream = new ReprocessStreamAdapter(mDevice);
+    sp<ReprocessStreamAdapter> stream = new ReprocessStreamAdapter(mHal2Device);
 
     res = stream->connectToDevice((*streamI));
     if (res != OK) {
@@ -401,8 +401,8 @@
     status_t err;
     ALOGV("%s: E", __FUNCTION__);
     camera_metadata_t *rawRequest;
-    err = mDevice->ops->construct_default_request(
-        mDevice, templateId, &rawRequest);
+    err = mHal2Device->ops->construct_default_request(
+        mHal2Device, templateId, &rawRequest);
     request->acquire(rawRequest);
     return err;
 }
@@ -417,12 +417,12 @@
 
     // TODO: Set up notifications from HAL, instead of sleeping here
     uint32_t totalTime = 0;
-    while (mDevice->ops->get_in_progress_count(mDevice) > 0) {
+    while (mHal2Device->ops->get_in_progress_count(mHal2Device) > 0) {
         usleep(kSleepTime);
         totalTime += kSleepTime;
         if (totalTime > kMaxSleepTime) {
             ALOGE("%s: Waited %d us, %d requests still in flight", __FUNCTION__,
-                    mDevice->ops->get_in_progress_count(mDevice), totalTime);
+                    mHal2Device->ops->get_in_progress_count(mHal2Device), totalTime);
             return TIMED_OUT;
         }
     }
@@ -433,7 +433,7 @@
 status_t Camera2Device::setNotifyCallback(NotificationListener *listener) {
     ATRACE_CALL();
     status_t res;
-    res = mDevice->ops->set_notify_callback(mDevice, notificationCallback,
+    res = mHal2Device->ops->set_notify_callback(mHal2Device, notificationCallback,
             reinterpret_cast<void*>(listener) );
     if (res != OK) {
         ALOGE("%s: Unable to set notification callback!", __FUNCTION__);
@@ -497,7 +497,7 @@
     ATRACE_CALL();
     status_t res;
     ALOGV("%s: Triggering autofocus, id %d", __FUNCTION__, id);
-    res = mDevice->ops->trigger_action(mDevice,
+    res = mHal2Device->ops->trigger_action(mHal2Device,
             CAMERA2_TRIGGER_AUTOFOCUS, id, 0);
     if (res != OK) {
         ALOGE("%s: Error triggering autofocus (id %d)",
@@ -510,7 +510,7 @@
     ATRACE_CALL();
     status_t res;
     ALOGV("%s: Canceling autofocus, id %d", __FUNCTION__, id);
-    res = mDevice->ops->trigger_action(mDevice,
+    res = mHal2Device->ops->trigger_action(mHal2Device,
             CAMERA2_TRIGGER_CANCEL_AUTOFOCUS, id, 0);
     if (res != OK) {
         ALOGE("%s: Error canceling autofocus (id %d)",
@@ -523,7 +523,7 @@
     ATRACE_CALL();
     status_t res;
     ALOGV("%s: Triggering precapture metering, id %d", __FUNCTION__, id);
-    res = mDevice->ops->trigger_action(mDevice,
+    res = mHal2Device->ops->trigger_action(mHal2Device,
             CAMERA2_TRIGGER_PRECAPTURE_METERING, id, 0);
     if (res != OK) {
         ALOGE("%s: Error triggering precapture metering (id %d)",
@@ -560,18 +560,11 @@
 }
 
 /**
- * Camera2Device::NotificationListener
- */
-
-Camera2Device::NotificationListener::~NotificationListener() {
-}
-
-/**
  * Camera2Device::MetadataQueue
  */
 
 Camera2Device::MetadataQueue::MetadataQueue():
-            mDevice(NULL),
+            mHal2Device(NULL),
             mFrameCount(0),
             mLatestRequestId(0),
             mCount(0),
@@ -602,7 +595,7 @@
     res = d->ops->set_request_queue_src_ops(d,
             this);
     if (res != OK) return res;
-    mDevice = d;
+    mHal2Device = d;
     return OK;
 }
 
@@ -835,12 +828,12 @@
     ATRACE_CALL();
     status_t res = OK;
     notEmpty.signal();
-    if (mSignalConsumer && mDevice != NULL) {
+    if (mSignalConsumer && mHal2Device != NULL) {
         mSignalConsumer = false;
 
         mMutex.unlock();
         ALOGV("%s: Signaling consumer", __FUNCTION__);
-        res = mDevice->ops->notify_request_queue_not_empty(mDevice);
+        res = mHal2Device->ops->notify_request_queue_not_empty(mHal2Device);
         mMutex.lock();
     }
     return res;
@@ -939,7 +932,7 @@
 
 Camera2Device::StreamAdapter::StreamAdapter(camera2_device_t *d):
         mState(RELEASED),
-        mDevice(d),
+        mHal2Device(d),
         mId(-1),
         mWidth(0), mHeight(0), mFormat(0), mSize(0), mUsage(0),
         mMaxProducerBuffers(0), mMaxConsumerBuffers(0),
@@ -990,7 +983,7 @@
     uint32_t formatActual;
     uint32_t usage;
     uint32_t maxBuffers = 2;
-    res = mDevice->ops->allocate_stream(mDevice,
+    res = mHal2Device->ops->allocate_stream(mHal2Device,
             mWidth, mHeight, mFormatRequested, getStreamOps(),
             &id, &formatActual, &usage, &maxBuffers);
     if (res != OK) {
@@ -1106,7 +1099,7 @@
     }
 
     ALOGV("%s: Registering %d buffers with camera HAL", __FUNCTION__, mTotalBuffers);
-    res = mDevice->ops->register_stream_buffers(mDevice,
+    res = mHal2Device->ops->register_stream_buffers(mHal2Device,
             mId,
             mTotalBuffers,
             buffers);
@@ -1138,7 +1131,7 @@
     status_t res;
     ALOGV("%s: Releasing stream %d", __FUNCTION__, mId);
     if (mState >= ALLOCATED) {
-        res = mDevice->ops->release_stream(mDevice, mId);
+        res = mHal2Device->ops->release_stream(mHal2Device, mId);
         if (res != OK) {
             ALOGE("%s: Unable to release stream %d",
                     __FUNCTION__, mId);
@@ -1319,7 +1312,7 @@
 
 Camera2Device::ReprocessStreamAdapter::ReprocessStreamAdapter(camera2_device_t *d):
         mState(RELEASED),
-        mDevice(d),
+        mHal2Device(d),
         mId(-1),
         mWidth(0), mHeight(0), mFormat(0),
         mActiveBuffers(0),
@@ -1361,7 +1354,7 @@
     // Allocate device-side stream interface
 
     uint32_t id;
-    res = mDevice->ops->allocate_reprocess_stream_from_stream(mDevice,
+    res = mHal2Device->ops->allocate_reprocess_stream_from_stream(mHal2Device,
             outputStream->getId(), getStreamOps(),
             &id);
     if (res != OK) {
@@ -1385,7 +1378,7 @@
     status_t res;
     ALOGV("%s: Releasing stream %d", __FUNCTION__, mId);
     if (mState >= ACTIVE) {
-        res = mDevice->ops->release_reprocess_stream(mDevice, mId);
+        res = mHal2Device->ops->release_reprocess_stream(mHal2Device, mId);
         if (res != OK) {
             ALOGE("%s: Unable to release stream %d",
                     __FUNCTION__, mId);
diff --git a/services/camera/libcameraservice/Camera2Device.h b/services/camera/libcameraservice/Camera2Device.h
index 86ff80f..1adb7a9 100644
--- a/services/camera/libcameraservice/Camera2Device.h
+++ b/services/camera/libcameraservice/Camera2Device.h
@@ -21,184 +21,53 @@
 #include <utils/Errors.h>
 #include <utils/List.h>
 #include <utils/Mutex.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
 
-#include "hardware/camera2.h"
-#include "camera/CameraMetadata.h"
+#include "CameraDeviceBase.h"
 
 namespace android {
 
-class Camera2Device : public virtual RefBase {
+/**
+ * CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_2_0
+ */
+class Camera2Device: public CameraDeviceBase {
   public:
     Camera2Device(int id);
 
-    ~Camera2Device();
-
-    status_t initialize(camera_module_t *module);
-    status_t disconnect();
-
-    status_t dump(int fd, const Vector<String16>& args);
+    virtual ~Camera2Device();
 
     /**
-     * The device's static characteristics metadata buffer
+     * CameraDevice interface
      */
-    const CameraMetadata& info() const;
-
-    /**
-     * Submit request for capture. The Camera2Device takes ownership of the
-     * passed-in buffer.
-     */
-    status_t capture(CameraMetadata &request);
-
-    /**
-     * Submit request for streaming. The Camera2Device makes a copy of the
-     * passed-in buffer and the caller retains ownership.
-     */
-    status_t setStreamingRequest(const CameraMetadata &request);
-
-    /**
-     * Clear the streaming request slot.
-     */
-    status_t clearStreamingRequest();
-
-    /**
-     * Wait until a request with the given ID has been dequeued by the
-     * HAL. Returns TIMED_OUT if the timeout duration is reached. Returns
-     * immediately if the latest request received by the HAL has this id.
-     */
-    status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);
-
-    /**
-     * Create an output stream of the requested size and format.
-     *
-     * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device selects
-     * an appropriate format; it can be queried with getStreamInfo.
-     *
-     * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must be
-     * equal to the size in bytes of the buffers to allocate for the stream. For
-     * other formats, the size parameter is ignored.
-     */
-    status_t createStream(sp<ANativeWindow> consumer,
+    virtual status_t initialize(camera_module_t *module);
+    virtual status_t disconnect();
+    virtual status_t dump(int fd, const Vector<String16>& args);
+    virtual const CameraMetadata& info() const;
+    virtual status_t capture(CameraMetadata &request);
+    virtual status_t setStreamingRequest(const CameraMetadata &request);
+    virtual status_t clearStreamingRequest();
+    virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);
+    virtual status_t createStream(sp<ANativeWindow> consumer,
             uint32_t width, uint32_t height, int format, size_t size,
             int *id);
-
-    /**
-     * Create an input reprocess stream that uses buffers from an existing
-     * output stream.
-     */
-    status_t createReprocessStreamFromStream(int outputId, int *id);
-
-    /**
-     * Get information about a given stream.
-     */
-    status_t getStreamInfo(int id,
+    virtual status_t createReprocessStreamFromStream(int outputId, int *id);
+    virtual status_t getStreamInfo(int id,
             uint32_t *width, uint32_t *height, uint32_t *format);
-
-    /**
-     * Set stream gralloc buffer transform
-     */
-    status_t setStreamTransform(int id, int transform);
-
-    /**
-     * Delete stream. Must not be called if there are requests in flight which
-     * reference that stream.
-     */
-    status_t deleteStream(int id);
-
-    /**
-     * Delete reprocess stream. Must not be called if there are requests in
-     * flight which reference that stream.
-     */
-    status_t deleteReprocessStream(int id);
-
-    /**
-     * Create a metadata buffer with fields that the HAL device believes are
-     * best for the given use case
-     */
-    status_t createDefaultRequest(int templateId, CameraMetadata *request);
-
-    /**
-     * Wait until all requests have been processed. Returns INVALID_OPERATION if
-     * the streaming slot is not empty, or TIMED_OUT if the requests haven't
-     * finished processing in 10 seconds.
-     */
-    status_t waitUntilDrained();
-
-    /**
-     * Abstract class for HAL notification listeners
-     */
-    class NotificationListener {
-      public:
-        // Refer to the Camera2 HAL definition for notification definitions
-        virtual void notifyError(int errorCode, int arg1, int arg2) = 0;
-        virtual void notifyShutter(int frameNumber, nsecs_t timestamp) = 0;
-        virtual void notifyAutoFocus(uint8_t newState, int triggerId) = 0;
-        virtual void notifyAutoExposure(uint8_t newState, int triggerId) = 0;
-        virtual void notifyAutoWhitebalance(uint8_t newState, int triggerId) = 0;
-      protected:
-        virtual ~NotificationListener();
-    };
-
-    /**
-     * Connect HAL notifications to a listener. Overwrites previous
-     * listener. Set to NULL to stop receiving notifications.
-     */
-    status_t setNotifyCallback(NotificationListener *listener);
-
-    /**
-     * Wait for a new frame to be produced, with timeout in nanoseconds.
-     * Returns TIMED_OUT when no frame produced within the specified duration
-     */
-    status_t waitForNextFrame(nsecs_t timeout);
-
-    /**
-     * Get next metadata frame from the frame queue. Returns NULL if the queue
-     * is empty; caller takes ownership of the metadata buffer.
-     */
-    status_t getNextFrame(CameraMetadata *frame);
-
-    /**
-     * Trigger auto-focus. The latest ID used in a trigger autofocus or cancel
-     * autofocus call will be returned by the HAL in all subsequent AF
-     * notifications.
-     */
-    status_t triggerAutofocus(uint32_t id);
-
-    /**
-     * Cancel auto-focus. The latest ID used in a trigger autofocus/cancel
-     * autofocus call will be returned by the HAL in all subsequent AF
-     * notifications.
-     */
-    status_t triggerCancelAutofocus(uint32_t id);
-
-    /**
-     * Trigger pre-capture metering. The latest ID used in a trigger pre-capture
-     * call will be returned by the HAL in all subsequent AE and AWB
-     * notifications.
-     */
-    status_t triggerPrecaptureMetering(uint32_t id);
-
-    /**
-     * Abstract interface for clients that want to listen to reprocess buffer
-     * release events
-     */
-    struct BufferReleasedListener: public virtual RefBase {
-        virtual void onBufferReleased(buffer_handle_t *handle) = 0;
-    };
-
-    /**
-     * Push a buffer to be reprocessed into a reprocessing stream, and
-     * provide a listener to call once the buffer is returned by the HAL
-     */
-    status_t pushReprocessBuffer(int reprocessStreamId,
+    virtual status_t setStreamTransform(int id, int transform);
+    virtual status_t deleteStream(int id);
+    virtual status_t deleteReprocessStream(int id);
+    virtual status_t createDefaultRequest(int templateId, CameraMetadata *request);
+    virtual status_t waitUntilDrained();
+    virtual status_t setNotifyCallback(NotificationListener *listener);
+    virtual status_t waitForNextFrame(nsecs_t timeout);
+    virtual status_t getNextFrame(CameraMetadata *frame);
+    virtual status_t triggerAutofocus(uint32_t id);
+    virtual status_t triggerCancelAutofocus(uint32_t id);
+    virtual status_t triggerPrecaptureMetering(uint32_t id);
+    virtual status_t pushReprocessBuffer(int reprocessStreamId,
             buffer_handle_t *buffer, wp<BufferReleasedListener> listener);
-
   private:
     const int mId;
-    camera2_device_t *mDevice;
+    camera2_device_t *mHal2Device;
 
     CameraMetadata mDeviceInfo;
     vendor_tag_query_ops_t *mVendorTagOps;
@@ -249,7 +118,7 @@
         status_t freeBuffers(List<camera_metadata_t*>::iterator start,
                 List<camera_metadata_t*>::iterator end);
 
-        camera2_device_t *mDevice;
+        camera2_device_t *mHal2Device;
 
         Mutex mMutex;
         Condition notEmpty;
@@ -341,7 +210,7 @@
         } mState;
 
         sp<ANativeWindow> mConsumerInterface;
-        camera2_device_t *mDevice;
+        camera2_device_t *mHal2Device;
 
         uint32_t mId;
         uint32_t mWidth;
@@ -435,7 +304,7 @@
 
         List<QueueEntry> mInFlightQueue;
 
-        camera2_device_t *mDevice;
+        camera2_device_t *mHal2Device;
 
         uint32_t mId;
         uint32_t mWidth;
diff --git a/services/camera/libcameraservice/Camera3Device.cpp b/services/camera/libcameraservice/Camera3Device.cpp
new file mode 100644
index 0000000..2a1be09
--- /dev/null
+++ b/services/camera/libcameraservice/Camera3Device.cpp
@@ -0,0 +1,375 @@
+/*
+ * 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 "Camera3-Device"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0  // Per-frame verbose logging
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <utils/Timers.h>
+#include "Camera3Device.h"
+
+namespace android {
+
+
+Camera3Device::Camera3Device(int id):
+        mId(id),
+        mHal3Device(NULL)
+{
+    ATRACE_CALL();
+    camera3_callback_ops::notify = &sNotify;
+    camera3_callback_ops::process_capture_result = &sProcessCaptureResult;
+    ALOGV("%s: Created device for camera %d", __FUNCTION__, id);
+}
+
+Camera3Device::~Camera3Device()
+{
+    ATRACE_CALL();
+    ALOGV("%s: Tearing down for camera id %d", __FUNCTION__, mId);
+    disconnect();
+}
+
+status_t Camera3Device::initialize(camera_module_t *module)
+{
+    ATRACE_CALL();
+    ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId);
+    if (mHal3Device != NULL) {
+        ALOGE("%s: Already initialized!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    /** Open HAL device */
+
+    status_t res;
+    String8 deviceName = String8::format("%d", mId);
+
+    camera3_device_t *device;
+
+    res = module->common.methods->open(&module->common, deviceName.string(),
+            reinterpret_cast<hw_device_t**>(&device));
+
+    if (res != OK) {
+        ALOGE("%s: Could not open camera %d: %s (%d)", __FUNCTION__,
+                mId, strerror(-res), res);
+        return res;
+    }
+
+    /** Cross-check device version */
+
+    if (device->common.version != CAMERA_DEVICE_API_VERSION_3_0) {
+        ALOGE("%s: Could not open camera %d: "
+                "Camera device is not version %x, reports %x instead",
+                __FUNCTION__, mId, CAMERA_DEVICE_API_VERSION_3_0,
+                device->common.version);
+        device->common.close(&device->common);
+        return BAD_VALUE;
+    }
+
+    camera_info info;
+    res = module->get_camera_info(mId, &info);
+    if (res != OK) return res;
+
+    if (info.device_version != device->common.version) {
+        ALOGE("%s: HAL reporting mismatched camera_info version (%x)"
+                " and device version (%x).", __FUNCTION__,
+                device->common.version, info.device_version);
+        device->common.close(&device->common);
+        return BAD_VALUE;
+    }
+
+    /** Initialize device with callback functions */
+
+    res = device->ops->initialize(device, this);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to initialize HAL device: %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        device->common.close(&device->common);
+        return BAD_VALUE;
+    }
+
+    /** Get vendor metadata tags */
+
+    mVendorTagOps.get_camera_vendor_section_name = NULL;
+
+    device->ops->get_metadata_vendor_tag_ops(device, &mVendorTagOps);
+
+    if (mVendorTagOps.get_camera_vendor_section_name != NULL) {
+        res = set_camera_metadata_vendor_tag_ops(&mVendorTagOps);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to set tag ops: %s (%d)",
+                    __FUNCTION__, mId, strerror(-res), res);
+            device->common.close(&device->common);
+            return res;
+        }
+    }
+
+    /** Start up request queue thread */
+
+    requestThread = new RequestThread(this);
+    res = requestThread->run(String8::format("C3Dev-%d-ReqQueue", mId).string());
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to start request queue thread: %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        device->common.close(&device->common);
+        return res;
+    }
+
+    /** Everything is good to go */
+
+    mDeviceInfo = info.static_camera_characteristics;
+    mHal3Device = device;
+
+    return OK;
+}
+
+status_t Camera3Device::disconnect() {
+    ATRACE_CALL();
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+status_t Camera3Device::dump(int fd, const Vector<String16> &args) {
+    ATRACE_CALL();
+    (void)args;
+
+    mHal3Device->ops->dump(mHal3Device, fd);
+
+    return OK;
+}
+
+const CameraMetadata& Camera3Device::info() const {
+    ALOGVV("%s: E", __FUNCTION__);
+
+    return mDeviceInfo;
+}
+
+status_t Camera3Device::capture(CameraMetadata &request) {
+    ATRACE_CALL();
+    (void)request;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+
+status_t Camera3Device::setStreamingRequest(const CameraMetadata &request) {
+    ATRACE_CALL();
+    (void)request;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+status_t Camera3Device::clearStreamingRequest() {
+    ATRACE_CALL();
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+status_t Camera3Device::waitUntilRequestReceived(int32_t requestId, nsecs_t timeout) {
+    ATRACE_CALL();
+    (void)requestId; (void)timeout;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+status_t Camera3Device::createStream(sp<ANativeWindow> consumer,
+        uint32_t width, uint32_t height, int format, size_t size, int *id) {
+    ATRACE_CALL();
+    (void)consumer; (void)width; (void)height; (void)format;
+    (void)size; (void)id;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+status_t Camera3Device::createReprocessStreamFromStream(int outputId, int *id) {
+    ATRACE_CALL();
+    (void)outputId; (void)id;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+
+status_t Camera3Device::getStreamInfo(int id,
+        uint32_t *width, uint32_t *height, uint32_t *format) {
+    ATRACE_CALL();
+    (void)id; (void)width; (void)height; (void)format;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+status_t Camera3Device::setStreamTransform(int id,
+        int transform) {
+    ATRACE_CALL();
+    (void)id; (void)transform;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+status_t Camera3Device::deleteStream(int id) {
+    ATRACE_CALL();
+    (void)id;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+status_t Camera3Device::deleteReprocessStream(int id) {
+    ATRACE_CALL();
+    (void)id;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+
+status_t Camera3Device::createDefaultRequest(int templateId,
+        CameraMetadata *request) {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+
+    const camera_metadata_t *rawRequest;
+    rawRequest = mHal3Device->ops->construct_default_request_settings(
+        mHal3Device, templateId);
+    if (rawRequest == NULL) return DEAD_OBJECT;
+    *request = rawRequest;
+
+    return OK;
+}
+
+status_t Camera3Device::waitUntilDrained() {
+    ATRACE_CALL();
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+status_t Camera3Device::setNotifyCallback(NotificationListener *listener) {
+    ATRACE_CALL();
+    (void)listener;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+status_t Camera3Device::waitForNextFrame(nsecs_t timeout) {
+    (void)timeout;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+status_t Camera3Device::getNextFrame(CameraMetadata *frame) {
+    ATRACE_CALL();
+    (void)frame;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+status_t Camera3Device::triggerAutofocus(uint32_t id) {
+    ATRACE_CALL();
+    (void)id;
+
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+status_t Camera3Device::triggerCancelAutofocus(uint32_t id) {
+    ATRACE_CALL();
+    (void)id;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+
+}
+
+status_t Camera3Device::triggerPrecaptureMetering(uint32_t id) {
+    ATRACE_CALL();
+    (void)id;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+
+}
+
+status_t Camera3Device::pushReprocessBuffer(int reprocessStreamId,
+        buffer_handle_t *buffer, wp<BufferReleasedListener> listener) {
+    ATRACE_CALL();
+    (void)reprocessStreamId; (void)buffer; (void)listener;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
+Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent) :
+        Thread(false),
+        mParent(parent) {
+}
+
+bool Camera3Device::RequestThread::threadLoop() {
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+
+    return false;
+}
+
+void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
+    (void)result;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+}
+
+void Camera3Device::notify(const camera3_notify_msg *msg) {
+    (void)msg;
+
+    ALOGE("%s: Unimplemented", __FUNCTION__);
+}
+
+/**
+ * Static callback forwarding methods from HAL to instance
+ */
+
+void Camera3Device::sProcessCaptureResult(const camera3_callback_ops *cb,
+        const camera3_capture_result *result) {
+    Camera3Device *d =
+            const_cast<Camera3Device*>(static_cast<const Camera3Device*>(cb));
+    d->processCaptureResult(result);
+}
+
+void Camera3Device::sNotify(const camera3_callback_ops *cb,
+        const camera3_notify_msg *msg) {
+    Camera3Device *d =
+            const_cast<Camera3Device*>(static_cast<const Camera3Device*>(cb));
+    d->notify(msg);
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/Camera3Device.h b/services/camera/libcameraservice/Camera3Device.h
new file mode 100644
index 0000000..2bc7cf0
--- /dev/null
+++ b/services/camera/libcameraservice/Camera3Device.h
@@ -0,0 +1,133 @@
+/*
+ * 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_CAMERA3DEVICE_H
+#define ANDROID_SERVERS_CAMERA_CAMERA3DEVICE_H
+
+#include <utils/Condition.h>
+#include <utils/Errors.h>
+#include <utils/List.h>
+#include <utils/Mutex.h>
+#include <utils/Thread.h>
+
+#include "CameraDeviceBase.h"
+
+#include "hardware/camera3.h"
+
+/**
+ * Function pointer types with C calling convention to
+ * use for HAL callback functions.
+ */
+extern "C" {
+    typedef void (callbacks_process_capture_result_t)(
+        const struct camera3_callback_ops *,
+        const camera3_capture_result_t *);
+
+    typedef void (callbacks_notify_t)(
+        const struct camera3_callback_ops *,
+        const camera3_notify_msg_t *);
+}
+
+namespace android {
+
+/**
+ * CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_3_0
+ */
+class Camera3Device :
+            public CameraDeviceBase,
+            private camera3_callback_ops {
+  public:
+    Camera3Device(int id);
+
+    virtual ~Camera3Device();
+
+    /**
+     * CameraDevice interface
+     */
+    virtual status_t initialize(camera_module_t *module);
+    virtual status_t disconnect();
+    virtual status_t dump(int fd, const Vector<String16> &args);
+    virtual const CameraMetadata& info() const;
+    virtual status_t capture(CameraMetadata &request);
+    virtual status_t setStreamingRequest(const CameraMetadata &request);
+    virtual status_t clearStreamingRequest();
+    virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);
+    virtual status_t createStream(sp<ANativeWindow> consumer,
+            uint32_t width, uint32_t height, int format, size_t size,
+            int *id);
+    virtual status_t createReprocessStreamFromStream(int outputId, int *id);
+    virtual status_t getStreamInfo(int id,
+            uint32_t *width, uint32_t *height, uint32_t *format);
+    virtual status_t setStreamTransform(int id, int transform);
+    virtual status_t deleteStream(int id);
+    virtual status_t deleteReprocessStream(int id);
+    virtual status_t createDefaultRequest(int templateId, CameraMetadata *request);
+    virtual status_t waitUntilDrained();
+    virtual status_t setNotifyCallback(NotificationListener *listener);
+    virtual status_t waitForNextFrame(nsecs_t timeout);
+    virtual status_t getNextFrame(CameraMetadata *frame);
+    virtual status_t triggerAutofocus(uint32_t id);
+    virtual status_t triggerCancelAutofocus(uint32_t id);
+    virtual status_t triggerPrecaptureMetering(uint32_t id);
+    virtual status_t pushReprocessBuffer(int reprocessStreamId,
+            buffer_handle_t *buffer, wp<BufferReleasedListener> listener);
+
+  private:
+    const int              mId;
+    camera3_device_t      *mHal3Device;
+
+    CameraMetadata         mDeviceInfo;
+    vendor_tag_query_ops_t mVendorTagOps;
+
+    /**
+     * Thread for managing capture request submission to HAL device.
+     */
+    class RequestThread: public Thread {
+
+      public:
+
+        RequestThread(wp<Camera3Device> parent);
+
+      protected:
+
+        virtual bool threadLoop();
+
+      private:
+
+        wp<Camera3Device> mParent;
+
+    };
+    sp<RequestThread> requestThread;
+
+    /**
+     * Callback functions from HAL device
+     */
+    void processCaptureResult(const camera3_capture_result *result);
+
+    void notify(const camera3_notify_msg *msg);
+
+    /**
+     * Static callback forwarding methods from HAL to instance
+     */
+    static callbacks_process_capture_result_t sProcessCaptureResult;
+
+    static callbacks_notify_t sNotify;
+
+}; // class Camera3Device
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/CameraClient.h b/services/camera/libcameraservice/CameraClient.h
index 00dc90c..7f0cb29 100644
--- a/services/camera/libcameraservice/CameraClient.h
+++ b/services/camera/libcameraservice/CameraClient.h
@@ -24,6 +24,11 @@
 class MemoryHeapBase;
 class CameraHardwareInterface;
 
+/**
+ * Interface between android.hardware.Camera API and Camera HAL device for version
+ * CAMERA_DEVICE_API_VERSION_1_0.
+ */
+
 class CameraClient : public CameraService::Client
 {
 public:
diff --git a/services/camera/libcameraservice/CameraDeviceBase.cpp b/services/camera/libcameraservice/CameraDeviceBase.cpp
new file mode 100644
index 0000000..6c4e87f
--- /dev/null
+++ b/services/camera/libcameraservice/CameraDeviceBase.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#include "CameraDeviceBase.h"
+
+namespace android {
+
+/**
+ * Base class destructors
+ */
+CameraDeviceBase::~CameraDeviceBase() {
+}
+
+CameraDeviceBase::NotificationListener::~NotificationListener() {
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/CameraDeviceBase.h b/services/camera/libcameraservice/CameraDeviceBase.h
new file mode 100644
index 0000000..8252af7
--- /dev/null
+++ b/services/camera/libcameraservice/CameraDeviceBase.h
@@ -0,0 +1,204 @@
+/*
+ * 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_CAMERADEVICEBASE_H
+#define ANDROID_SERVERS_CAMERA_CAMERADEVICEBASE_H
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+#include <utils/Timers.h>
+
+#include "hardware/camera2.h"
+#include "camera/CameraMetadata.h"
+
+namespace android {
+
+/**
+ * Base interface for version >= 2 camera device classes, which interface to
+ * camera HAL device versions >= 2.
+ */
+class CameraDeviceBase : public virtual RefBase {
+  public:
+    virtual ~CameraDeviceBase();
+
+    virtual status_t initialize(camera_module_t *module) = 0;
+    virtual status_t disconnect() = 0;
+
+    virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+    /**
+     * The device's static characteristics metadata buffer
+     */
+    virtual const CameraMetadata& info() const = 0;
+
+    /**
+     * Submit request for capture. The CameraDevice takes ownership of the
+     * passed-in buffer.
+     */
+    virtual status_t capture(CameraMetadata &request) = 0;
+
+    /**
+     * Submit request for streaming. The CameraDevice makes a copy of the
+     * passed-in buffer and the caller retains ownership.
+     */
+    virtual status_t setStreamingRequest(const CameraMetadata &request) = 0;
+
+    /**
+     * Clear the streaming request slot.
+     */
+    virtual status_t clearStreamingRequest() = 0;
+
+    /**
+     * Wait until a request with the given ID has been dequeued by the
+     * HAL. Returns TIMED_OUT if the timeout duration is reached. Returns
+     * immediately if the latest request received by the HAL has this id.
+     */
+    virtual status_t waitUntilRequestReceived(int32_t requestId,
+            nsecs_t timeout) = 0;
+
+    /**
+     * Create an output stream of the requested size and format.
+     *
+     * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device selects
+     * an appropriate format; it can be queried with getStreamInfo.
+     *
+     * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must be
+     * equal to the size in bytes of the buffers to allocate for the stream. For
+     * other formats, the size parameter is ignored.
+     */
+    virtual status_t createStream(sp<ANativeWindow> consumer,
+            uint32_t width, uint32_t height, int format, size_t size,
+            int *id) = 0;
+
+    /**
+     * Create an input reprocess stream that uses buffers from an existing
+     * output stream.
+     */
+    virtual status_t createReprocessStreamFromStream(int outputId, int *id) = 0;
+
+    /**
+     * Get information about a given stream.
+     */
+    virtual status_t getStreamInfo(int id,
+            uint32_t *width, uint32_t *height, uint32_t *format) = 0;
+
+    /**
+     * Set stream gralloc buffer transform
+     */
+    virtual status_t setStreamTransform(int id, int transform) = 0;
+
+    /**
+     * Delete stream. Must not be called if there are requests in flight which
+     * reference that stream.
+     */
+    virtual status_t deleteStream(int id) = 0;
+
+    /**
+     * Delete reprocess stream. Must not be called if there are requests in
+     * flight which reference that stream.
+     */
+    virtual status_t deleteReprocessStream(int id) = 0;
+
+    /**
+     * Create a metadata buffer with fields that the HAL device believes are
+     * best for the given use case
+     */
+    virtual status_t createDefaultRequest(int templateId,
+            CameraMetadata *request) = 0;
+
+    /**
+     * Wait until all requests have been processed. Returns INVALID_OPERATION if
+     * the streaming slot is not empty, or TIMED_OUT if the requests haven't
+     * finished processing in 10 seconds.
+     */
+    virtual status_t waitUntilDrained() = 0;
+
+    /**
+     * Abstract class for HAL notification listeners
+     */
+    class NotificationListener {
+      public:
+        // Refer to the Camera2 HAL definition for notification definitions
+        virtual void notifyError(int errorCode, int arg1, int arg2) = 0;
+        virtual void notifyShutter(int frameNumber, nsecs_t timestamp) = 0;
+        virtual void notifyAutoFocus(uint8_t newState, int triggerId) = 0;
+        virtual void notifyAutoExposure(uint8_t newState, int triggerId) = 0;
+        virtual void notifyAutoWhitebalance(uint8_t newState,
+                int triggerId) = 0;
+      protected:
+        virtual ~NotificationListener();
+    };
+
+    /**
+     * Connect HAL notifications to a listener. Overwrites previous
+     * listener. Set to NULL to stop receiving notifications.
+     */
+    virtual status_t setNotifyCallback(NotificationListener *listener) = 0;
+
+    /**
+     * Wait for a new frame to be produced, with timeout in nanoseconds.
+     * Returns TIMED_OUT when no frame produced within the specified duration
+     */
+    virtual status_t waitForNextFrame(nsecs_t timeout) = 0;
+
+    /**
+     * Get next metadata frame from the frame queue. Returns NULL if the queue
+     * is empty; caller takes ownership of the metadata buffer.
+     */
+    virtual status_t getNextFrame(CameraMetadata *frame) = 0;
+
+    /**
+     * Trigger auto-focus. The latest ID used in a trigger autofocus or cancel
+     * autofocus call will be returned by the HAL in all subsequent AF
+     * notifications.
+     */
+    virtual status_t triggerAutofocus(uint32_t id) = 0;
+
+    /**
+     * Cancel auto-focus. The latest ID used in a trigger autofocus/cancel
+     * autofocus call will be returned by the HAL in all subsequent AF
+     * notifications.
+     */
+    virtual status_t triggerCancelAutofocus(uint32_t id) = 0;
+
+    /**
+     * Trigger pre-capture metering. The latest ID used in a trigger pre-capture
+     * call will be returned by the HAL in all subsequent AE and AWB
+     * notifications.
+     */
+    virtual status_t triggerPrecaptureMetering(uint32_t id) = 0;
+
+    /**
+     * Abstract interface for clients that want to listen to reprocess buffer
+     * release events
+     */
+    struct BufferReleasedListener : public virtual RefBase {
+        virtual void onBufferReleased(buffer_handle_t *handle) = 0;
+    };
+
+    /**
+     * Push a buffer to be reprocessed into a reprocessing stream, and
+     * provide a listener to call once the buffer is returned by the HAL
+     */
+    virtual status_t pushReprocessBuffer(int reprocessStreamId,
+            buffer_handle_t *buffer, wp<BufferReleasedListener> listener) = 0;
+};
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/CameraHardwareInterface.h b/services/camera/libcameraservice/CameraHardwareInterface.h
index 167b37c..87b2807 100644
--- a/services/camera/libcameraservice/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/CameraHardwareInterface.h
@@ -47,7 +47,8 @@
 /**
  * CameraHardwareInterface.h defines the interface to the
  * camera hardware abstraction layer, used for setting and getting
- * parameters, live previewing, and taking pictures.
+ * parameters, live previewing, and taking pictures. It is used for
+ * HAL devices with version CAMERA_DEVICE_API_VERSION_1_0 only.
  *
  * It is a referenced counted interface with RefBase as its base class.
  * CameraService calls openCameraHardware() to retrieve a strong pointer to the
@@ -56,24 +57,18 @@
  *
  *   -# After CameraService calls openCameraHardware(), getParameters() and
  *      setParameters() are used to initialize the camera instance.
- *      CameraService calls getPreviewHeap() to establish access to the
- *      preview heap so it can be registered with SurfaceFlinger for
- *      efficient display updating while in preview mode.
- *   -# startPreview() is called.  The camera instance then periodically
- *      sends the message CAMERA_MSG_PREVIEW_FRAME (if enabled) each time
- *      a new preview frame is available.  If data callback code needs to use
- *      this memory after returning, it must copy the data.
+ *   -# startPreview() is called.
  *
- * Prior to taking a picture, CameraService calls autofocus(). When auto
+ * Prior to taking a picture, CameraService often calls autofocus(). When auto
  * focusing has completed, the camera instance sends a CAMERA_MSG_FOCUS notification,
  * which informs the application whether focusing was successful. The camera instance
  * only sends this message once and it is up  to the application to call autoFocus()
  * again if refocusing is desired.
  *
  * CameraService calls takePicture() to request the camera instance take a
- * picture. At this point, if a shutter, postview, raw, and/or compressed callback
- * is desired, the corresponding message must be enabled. As with CAMERA_MSG_PREVIEW_FRAME,
- * any memory provided in a data callback must be copied if it's needed after returning.
+ * picture. At this point, if a shutter, postview, raw, and/or compressed
+ * callback is desired, the corresponding message must be enabled. Any memory
+ * provided in a data callback must be copied if it's needed after returning.
  */
 
 class CameraHardwareInterface : public virtual RefBase {
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index ec1c3f0..8c4f619 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -77,6 +77,10 @@
 {
     ALOGI("CameraService started (pid=%d)", getpid());
     gCameraService = this;
+
+    for (size_t i = 0; i < MAX_CAMERAS; ++i) {
+        mStatusList[i] = ICameraServiceListener::STATUS_AVAILABLE;
+    }
 }
 
 void CameraService::onFirstRef()
@@ -155,6 +159,23 @@
     return deviceVersion;
 }
 
+bool CameraService::isValidCameraId(int cameraId) {
+    int facing;
+    int deviceVersion = getDeviceVersion(cameraId, &facing);
+
+    switch(deviceVersion) {
+      case CAMERA_DEVICE_API_VERSION_1_0:
+      case CAMERA_DEVICE_API_VERSION_2_0:
+      case CAMERA_DEVICE_API_VERSION_2_1:
+      case CAMERA_DEVICE_API_VERSION_3_0:
+        return true;
+      default:
+        return false;
+    }
+
+    return false;
+}
+
 sp<ICamera> CameraService::connect(
         const sp<ICameraClient>& cameraClient,
         int cameraId,
@@ -236,6 +257,10 @@
     int facing = -1;
     int deviceVersion = getDeviceVersion(cameraId, &facing);
 
+    if (isValidCameraId(cameraId)) {
+        updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE, cameraId);
+    }
+
     switch(deviceVersion) {
       case CAMERA_DEVICE_API_VERSION_1_0:
         client = new CameraClient(this, cameraClient,
@@ -244,9 +269,11 @@
         break;
       case CAMERA_DEVICE_API_VERSION_2_0:
       case CAMERA_DEVICE_API_VERSION_2_1:
+      case CAMERA_DEVICE_API_VERSION_3_0:
         client = new Camera2Client(this, cameraClient,
                 clientPackageName, cameraId,
-                facing, callingPid, clientUid, getpid());
+                facing, callingPid, clientUid, getpid(),
+                deviceVersion);
         break;
       case -1:
         ALOGE("Invalid camera id %d", cameraId);
@@ -257,6 +284,9 @@
     }
 
     if (client->initialize(mModule) != OK) {
+        // this is probably not recoverable.. but maybe the client can try again
+        updateStatus(ICameraServiceListener::STATUS_AVAILABLE, cameraId);
+
         return NULL;
     }
 
@@ -264,15 +294,21 @@
 
     mClient[cameraId] = client;
     LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId, getpid());
+
     return client;
 }
 
 sp<IProCameraUser> CameraService::connect(
                                         const sp<IProCameraCallbacks>& cameraCb,
-                                        int cameraId)
+                                        int cameraId,
+                                        const String16& clientPackageName,
+                                        int clientUid)
 {
+    String8 clientName8(clientPackageName);
     int callingPid = getCallingPid();
 
+    // TODO: use clientPackageName and clientUid with appOpsMangr
+
     LOG1("CameraService::connectPro E (pid %d, id %d)", callingPid, cameraId);
 
     if (!mModule) {
@@ -295,6 +331,15 @@
         return NULL;
     }
 
+    // TODO: allow concurrent connections with a ProCamera
+    if (mBusy[cameraId]) {
+
+        ALOGW("CameraService::connectPro X (pid %d, \"%s\") rejected"
+                " (camera %d is still busy).", callingPid,
+                clientName8.string(), cameraId);
+        return NULL;
+    }
+
     int facing = -1;
     int deviceVersion = getDeviceVersion(cameraId, &facing);
 
@@ -327,9 +372,45 @@
     LOG1("CameraService::connectPro X (id %d, this pid is %d)", cameraId,
             getpid());
     return client;
+}
 
+status_t CameraService::addListener(
+                                const sp<ICameraServiceListener>& listener) {
+    ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
 
-    return NULL;
+    Mutex::Autolock lock(mServiceLock);
+
+    Vector<sp<ICameraServiceListener> >::iterator it, end;
+    for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
+        if ((*it)->asBinder() == listener->asBinder()) {
+            ALOGW("%s: Tried to add listener %p which was already subscribed",
+                  __FUNCTION__, listener.get());
+            return ALREADY_EXISTS;
+        }
+    }
+
+    mListenerList.push_back(listener);
+
+    return OK;
+}
+status_t CameraService::removeListener(
+                                const sp<ICameraServiceListener>& listener) {
+    ALOGV("%s: Remove listener %p", __FUNCTION__, listener.get());
+
+    Mutex::Autolock lock(mServiceLock);
+
+    Vector<sp<ICameraServiceListener> >::iterator it;
+    for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
+        if ((*it)->asBinder() == listener->asBinder()) {
+            mListenerList.erase(it);
+            return OK;
+        }
+    }
+
+    ALOGW("%s: Tried to remove a listener %p which was not subscribed",
+          __FUNCTION__, listener.get());
+
+    return BAD_VALUE;
 }
 
 void CameraService::removeClientByRemote(const wp<IBinder>& remoteBinder) {
@@ -693,6 +774,8 @@
 void CameraService::Client::disconnect() {
     BasicClient::disconnect();
     mCameraService->setCameraFree(mCameraId);
+    mCameraService->updateStatus(ICameraServiceListener::STATUS_AVAILABLE,
+                                 mCameraId);
 }
 
 CameraService::Client::OpsCallback::OpsCallback(wp<BasicClient> client):
@@ -768,6 +851,10 @@
     return false;
 }
 
+void CameraService::ProClient::onExclusiveLockStolen() {
+    ALOGE("%s: not implemented yet", __FUNCTION__);
+}
+
 status_t CameraService::ProClient::submitRequest(camera_metadata_t* request, bool streaming) {
     ALOGE("%s: not implemented yet", __FUNCTION__);
 
@@ -938,4 +1025,47 @@
 
 }
 
+void CameraService::updateStatus(ICameraServiceListener::Status status,
+                                 int32_t cameraId) {
+    // do not lock mServiceLock here or can get into a deadlock from
+    //  connect() -> ProClient::disconnect -> updateStatus
+    Mutex::Autolock lock(mStatusMutex);
+    updateStatusUnsafe(status, cameraId);
+}
+
+void CameraService::updateStatusUnsafe(ICameraServiceListener::Status status,
+                                       int32_t cameraId) {
+
+    ICameraServiceListener::Status oldStatus = mStatusList[cameraId];
+
+    mStatusList[cameraId] = status;
+
+    if (oldStatus != status) {
+        ALOGV("%s: Status has changed for camera ID %d from 0x%x to 0x%x",
+              __FUNCTION__, cameraId, (uint32_t)oldStatus, (uint32_t)status);
+
+        /**
+          * ProClients lose their exclusive lock.
+          * - Done before the CameraClient can initialize the HAL device,
+          *   since we want to be able to close it before they get to initialize
+          */
+        if (status == ICameraServiceListener::STATUS_NOT_AVAILABLE) {
+            Vector<wp<ProClient> > proClients(mProClientList[cameraId]);
+            Vector<wp<ProClient> >::const_iterator it;
+
+            for (it = proClients.begin(); it != proClients.end(); ++it) {
+                sp<ProClient> proCl = it->promote();
+                if (proCl.get() != NULL) {
+                    proCl->onExclusiveLockStolen();
+                }
+            }
+        }
+
+        Vector<sp<ICameraServiceListener> >::const_iterator it;
+        for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
+            (*it)->onStatusChanged(status, cameraId);
+        }
+    }
+}
+
 }; // namespace android
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index b017505..8acc63f 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -25,6 +25,13 @@
 #include <camera/ICameraService.h>
 #include <hardware/camera.h>
 
+#include <camera/ICamera.h>
+#include <camera/ICameraClient.h>
+#include <camera/IProCameraUser.h>
+#include <camera/IProCameraCallbacks.h>
+
+#include <camera/ICameraServiceListener.h>
+
 /* This needs to be increased if we can have more cameras */
 #define MAX_CAMERAS 2
 
@@ -60,7 +67,11 @@
     virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId,
             const String16& clientPackageName, int clientUid);
     virtual sp<IProCameraUser> connect(const sp<IProCameraCallbacks>& cameraCb,
-            int cameraId);
+            int cameraId, const String16& clientPackageName, int clientUid);
+
+    virtual status_t    addListener(const sp<ICameraServiceListener>& listener);
+    virtual status_t    removeListener(
+                                    const sp<ICameraServiceListener>& listener);
 
     // Extra permissions checks
     virtual status_t    onTransact(uint32_t code, const Parcel& data,
@@ -258,6 +269,9 @@
         virtual status_t      requestStream(int streamId);
         virtual status_t      cancelStream(int streamId);
 
+        // Callbacks from camera service
+        virtual void          onExclusiveLockStolen();
+
     protected:
         virtual void          notifyError();
 
@@ -298,11 +312,30 @@
 
     camera_module_t *mModule;
 
+    Vector<sp<ICameraServiceListener> >
+                        mListenerList;
+
+    // guard only mStatusList and the broadcasting of ICameraServiceListener
+    Mutex               mStatusMutex;
+    ICameraServiceListener::Status
+                        mStatusList[MAX_CAMERAS];
+
+    // Broadcast the new status if it changed (locks the service mutex)
+    void                updateStatus(
+                            ICameraServiceListener::Status status,
+                            int32_t cameraId);
+    // Call this one when the service mutex is already held (idempotent)
+    void                updateStatusUnsafe(
+                            ICameraServiceListener::Status status,
+                            int32_t cameraId);
+
     // IBinder::DeathRecipient implementation
-    virtual void binderDied(const wp<IBinder> &who);
+    virtual void        binderDied(const wp<IBinder> &who);
 
     // Helpers
     int                 getDeviceVersion(int cameraId, int* facing);
+
+    bool                isValidCameraId(int cameraId);
 };
 
 } // namespace android
diff --git a/services/camera/libcameraservice/ProCamera2Client.cpp b/services/camera/libcameraservice/ProCamera2Client.cpp
index eda3012..6fed8b4 100644
--- a/services/camera/libcameraservice/ProCamera2Client.cpp
+++ b/services/camera/libcameraservice/ProCamera2Client.cpp
@@ -115,6 +115,8 @@
     Mutex::Autolock icl(mIProCameraUserLock);
     SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
 
+    if (!mDevice.get()) return PERMISSION_DENIED;
+
     if (!mExclusiveLock) {
         mExclusiveLock = true;
 
@@ -144,6 +146,8 @@
     Mutex::Autolock icl(mIProCameraUserLock);
     SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
 
+    if (!mDevice.get()) return PERMISSION_DENIED;
+
     /**
      * TODO: this should asynchronously 'wait' until the lock becomes available
      * if another client already has an exclusive lock.
@@ -197,12 +201,33 @@
     return mExclusiveLock;
 }
 
+void ProCamera2Client::onExclusiveLockStolen() {
+    ALOGV("%s: ProClient lost exclusivity (id %d)",
+          __FUNCTION__, mCameraId);
+
+    Mutex::Autolock icl(mIProCameraUserLock);
+    SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
+
+    if (mExclusiveLock && mRemoteCallback.get() != NULL) {
+        mRemoteCallback->onLockStatusChanged(
+                                       IProCameraCallbacks::LOCK_STOLEN);
+    }
+
+    mExclusiveLock = false;
+
+    //TODO: we should not need to detach the device, merely reset it.
+    detachDevice();
+}
+
 status_t ProCamera2Client::submitRequest(camera_metadata_t* request,
                                          bool streaming) {
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
 
     Mutex::Autolock icl(mIProCameraUserLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
     if (!mExclusiveLock) {
         return PERMISSION_DENIED;
     }
@@ -224,6 +249,9 @@
     ALOGV("%s", __FUNCTION__);
 
     Mutex::Autolock icl(mIProCameraUserLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
     if (!mExclusiveLock) {
         return PERMISSION_DENIED;
     }
@@ -247,6 +275,7 @@
 
     Mutex::Autolock icl(mIProCameraUserLock);
 
+    if (!mDevice.get()) return DEAD_OBJECT;
     mDevice->clearStreamingRequest();
 
     status_t code;
@@ -274,6 +303,8 @@
 
     Mutex::Autolock icl(mIProCameraUserLock);
 
+    if (!mDevice.get()) return DEAD_OBJECT;
+
     sp<IBinder> binder;
     sp<ANativeWindow> window;
     if (bufferProducer != 0) {
@@ -303,6 +334,8 @@
 
     Mutex::Autolock icl(mIProCameraUserLock);
 
+    if (!mDevice.get()) return DEAD_OBJECT;
+
     CameraMetadata metadata;
     if ( (res = mDevice->createDefaultRequest(templateId, &metadata) ) == OK) {
         *request = metadata.release();
@@ -319,6 +352,10 @@
         return INVALID_OPERATION;
     }
 
+    Mutex::Autolock icl(mIProCameraUserLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
     CameraMetadata deviceInfo = mDevice->info();
     *info = deviceInfo.release();
 
@@ -341,6 +378,12 @@
     result = "  Device dump:\n";
     write(fd, result.string(), result.size());
 
+    if (!mDevice.get()) {
+        result = "  *** Device is detached\n";
+        write(fd, result.string(), result.size());
+        return NO_ERROR;
+    }
+
     status_t res = mDevice->dump(fd, args);
     if (res != OK) {
         result = String8::format("   Error dumping device: %s (%d)",
@@ -363,9 +406,19 @@
     int callingPid = getCallingPid();
     if (callingPid != mClientPid && callingPid != mServicePid) return;
 
+    ALOGV("Camera %d: Shutting down", mCameraId);
+
+    detachDevice();
+    ProClient::disconnect();
+
+    ALOGV("Camera %d: Shut down complete complete", mCameraId);
+}
+
+void ProCamera2Client::detachDevice() {
     if (mDevice == 0) return;
 
-    ALOGV("Camera %d: Shutting down", mCameraId);
+    ALOGV("Camera %d: Stopping processors", mCameraId);
+
     mFrameProcessor->removeListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
                                     FRAME_PROCESSOR_LISTENER_MAX_ID,
                                     /*listener*/this);
@@ -374,11 +427,22 @@
     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);
+        }
+    }
+
     mDevice->disconnect();
 
     mDevice.clear();
 
-    ProClient::disconnect();
+    ALOGV("Camera %d: Detach complete", mCameraId);
 }
 
 status_t ProCamera2Client::connect(const sp<IProCameraCallbacks>& client) {
diff --git a/services/camera/libcameraservice/ProCamera2Client.h b/services/camera/libcameraservice/ProCamera2Client.h
index 9f514f4..ff6f4e2 100644
--- a/services/camera/libcameraservice/ProCamera2Client.h
+++ b/services/camera/libcameraservice/ProCamera2Client.h
@@ -104,6 +104,9 @@
     const sp<Camera2Device>& getCameraDevice();
     const sp<CameraService>& getCameraService();
 
+    // Callbacks from camera service
+    virtual void onExclusiveLockStolen();
+
     /**
      * Interface used by independent components of ProCamera2Client.
      */
@@ -167,6 +170,8 @@
     // - if no we can't modify the request queue.
     // note that creating/deleting streams we own is still OK
     bool mExclusiveLock;
+
+    void detachDevice();
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
index c4055e0..9a14758 100644
--- a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
@@ -23,7 +23,7 @@
 
 #include "CallbackProcessor.h"
 #include <gui/Surface.h>
-#include "../Camera2Device.h"
+#include "../CameraDeviceBase.h"
 #include "../Camera2Client.h"
 
 
@@ -58,7 +58,7 @@
 
     sp<Camera2Client> client = mClient.promote();
     if (client == 0) return OK;
-    sp<Camera2Device> device = client->getCameraDevice();
+    sp<CameraDeviceBase> device = client->getCameraDevice();
 
     if (mCallbackConsumer == 0) {
         // Create CPU buffer queue endpoint
@@ -125,7 +125,7 @@
     if (mCallbackStreamId != NO_STREAM) {
         sp<Camera2Client> client = mClient.promote();
         if (client == 0) return OK;
-        sp<Camera2Device> device = client->getCameraDevice();
+        sp<CameraDeviceBase> device = client->getCameraDevice();
 
         device->deleteStream(mCallbackStreamId);
 
diff --git a/services/camera/libcameraservice/camera2/FrameProcessor.cpp b/services/camera/libcameraservice/camera2/FrameProcessor.cpp
index 8ee5de7..3129a0b 100644
--- a/services/camera/libcameraservice/camera2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/FrameProcessor.cpp
@@ -22,7 +22,7 @@
 #include <utils/Trace.h>
 
 #include "FrameProcessor.h"
-#include "../Camera2Device.h"
+#include "../CameraDeviceBase.h"
 #include "../Camera2Client.h"
 
 namespace android {
@@ -71,7 +71,7 @@
 bool FrameProcessor::threadLoop() {
     status_t res;
 
-    sp<Camera2Device> device;
+    sp<CameraDeviceBase> device;
     {
         sp<Camera2Client> client = mClient.promote();
         if (client == 0) return false;
diff --git a/services/camera/libcameraservice/camera2/JpegProcessor.cpp b/services/camera/libcameraservice/camera2/JpegProcessor.cpp
index 1ec5694..286fac4 100644
--- a/services/camera/libcameraservice/camera2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/JpegProcessor.cpp
@@ -27,7 +27,7 @@
 
 #include "JpegProcessor.h"
 #include <gui/Surface.h>
-#include "../Camera2Device.h"
+#include "../CameraDeviceBase.h"
 #include "../Camera2Client.h"
 
 
@@ -66,7 +66,7 @@
 
     sp<Camera2Client> client = mClient.promote();
     if (client == 0) return OK;
-    sp<Camera2Device> device = client->getCameraDevice();
+    sp<CameraDeviceBase> device = client->getCameraDevice();
 
     // Find out buffer size for JPEG
     camera_metadata_ro_entry_t maxJpegSize =
@@ -145,7 +145,7 @@
     if (mCaptureStreamId != NO_STREAM) {
         sp<Camera2Client> client = mClient.promote();
         if (client == 0) return OK;
-        sp<Camera2Device> device = client->getCameraDevice();
+        sp<CameraDeviceBase> device = client->getCameraDevice();
 
         device->deleteStream(mCaptureStreamId);
 
diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
index a0d1093..6a4b95d 100644
--- a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
@@ -26,7 +26,7 @@
 #include "StreamingProcessor.h"
 #include "Camera2Heap.h"
 #include "../Camera2Client.h"
-#include "../Camera2Device.h"
+#include "../CameraDeviceBase.h"
 
 namespace android {
 namespace camera2 {
@@ -110,7 +110,7 @@
     status_t res;
     sp<Camera2Client> client = mClient.promote();
     if (client == 0) return INVALID_OPERATION;
-    sp<Camera2Device> device = client->getCameraDevice();
+    sp<CameraDeviceBase> device = client->getCameraDevice();
 
     if (mPreviewStreamId != NO_STREAM) {
         // Check if stream parameters have to change
@@ -176,7 +176,7 @@
     if (mPreviewStreamId != NO_STREAM) {
         sp<Camera2Client> client = mClient.promote();
         if (client == 0) return INVALID_OPERATION;
-        sp<Camera2Device> device = client->getCameraDevice();
+        sp<CameraDeviceBase> device = client->getCameraDevice();
 
         ALOGV("%s: for cameraId %d on streamId %d",
             __FUNCTION__, client->getCameraId(), mPreviewStreamId);
@@ -272,7 +272,7 @@
 
     sp<Camera2Client> client = mClient.promote();
     if (client == 0) return INVALID_OPERATION;
-    sp<Camera2Device> device = client->getCameraDevice();
+    sp<CameraDeviceBase> device = client->getCameraDevice();
 
     if (mRecordingConsumer == 0) {
         // Create CPU buffer queue endpoint. We need one more buffer here so that we can
@@ -339,7 +339,7 @@
     if (mRecordingStreamId != NO_STREAM) {
         sp<Camera2Client> client = mClient.promote();
         if (client == 0) return INVALID_OPERATION;
-        sp<Camera2Device> device = client->getCameraDevice();
+        sp<CameraDeviceBase> device = client->getCameraDevice();
 
         res = device->waitUntilDrained();
         if (res != OK) {
@@ -415,7 +415,7 @@
 
     sp<Camera2Client> client = mClient.promote();
     if (client == 0) return INVALID_OPERATION;
-    sp<Camera2Device> device = client->getCameraDevice();
+    sp<CameraDeviceBase> device = client->getCameraDevice();
 
     res = device->clearStreamingRequest();
     if (res != OK) {
diff --git a/services/camera/libcameraservice/camera2/ZslProcessor.cpp b/services/camera/libcameraservice/camera2/ZslProcessor.cpp
index 900c099..769d9bd 100644
--- a/services/camera/libcameraservice/camera2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/ZslProcessor.cpp
@@ -30,7 +30,7 @@
 
 #include "ZslProcessor.h"
 #include <gui/Surface.h>
-#include "../Camera2Device.h"
+#include "../CameraDeviceBase.h"
 #include "../Camera2Client.h"
 
 
@@ -114,7 +114,7 @@
 
     sp<Camera2Client> client = mClient.promote();
     if (client == 0) return OK;
-    sp<Camera2Device> device = client->getCameraDevice();
+    sp<CameraDeviceBase> device = client->getCameraDevice();
 
     if (mZslConsumer == 0) {
         // Create CPU buffer queue endpoint
@@ -202,7 +202,7 @@
     if (mZslStreamId != NO_STREAM) {
         sp<Camera2Client> client = mClient.promote();
         if (client == 0) return OK;
-        sp<Camera2Device> device = client->getCameraDevice();
+        sp<CameraDeviceBase> device = client->getCameraDevice();
 
         res = device->deleteReprocessStream(mZslReprocessStreamId);
         if (res != OK) {
@@ -289,10 +289,12 @@
         uint8_t requestType = ANDROID_REQUEST_TYPE_REPROCESS;
         res = request.update(ANDROID_REQUEST_TYPE,
                 &requestType, 1);
-        uint8_t inputStreams[1] = { mZslReprocessStreamId };
+        uint8_t inputStreams[1] =
+                { static_cast<uint8_t>(mZslReprocessStreamId) };
         if (res == OK) request.update(ANDROID_REQUEST_INPUT_STREAMS,
                 inputStreams, 1);
-        uint8_t outputStreams[1] = { client->getCaptureStreamId() };
+        uint8_t outputStreams[1] =
+                { static_cast<uint8_t>(client->getCaptureStreamId()) };
         if (res == OK) request.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                 outputStreams, 1);
         res = request.update(ANDROID_REQUEST_ID,
diff --git a/services/camera/libcameraservice/camera2/ZslProcessor.h b/services/camera/libcameraservice/camera2/ZslProcessor.h
index ec16eef..b2cf5b1 100644
--- a/services/camera/libcameraservice/camera2/ZslProcessor.h
+++ b/services/camera/libcameraservice/camera2/ZslProcessor.h
@@ -27,7 +27,7 @@
 #include "FrameProcessor.h"
 #include "camera/CameraMetadata.h"
 #include "Camera2Heap.h"
-#include "../Camera2Device.h"
+#include "../CameraDeviceBase.h"
 
 namespace android {
 
@@ -44,7 +44,7 @@
             virtual public Thread,
             virtual public BufferItemConsumer::FrameAvailableListener,
             virtual public FrameProcessor::FilteredListener,
-            virtual public Camera2Device::BufferReleasedListener {
+            virtual public CameraDeviceBase::BufferReleasedListener {
   public:
     ZslProcessor(wp<Camera2Client> client, wp<CaptureSequencer> sequencer);
     ~ZslProcessor();