summaryrefslogtreecommitdiffstats
path: root/camera
diff options
context:
space:
mode:
authorIgor Murashkin <iam@google.com>2013-02-27 12:55:20 -0800
committerIgor Murashkin <iam@google.com>2013-02-28 15:55:15 -0800
commit8fdfbe27acd157d58fa35a849ec50c82464062f0 (patch)
tree19a08d59c5e5cfd56cda29b01ef1ea1b4f00ed77 /camera
parent721f17283e2493426c47bbaa267c337b2af5726e (diff)
downloadframeworks_av-8fdfbe27acd157d58fa35a849ec50c82464062f0.zip
frameworks_av-8fdfbe27acd157d58fa35a849ec50c82464062f0.tar.gz
frameworks_av-8fdfbe27acd157d58fa35a849ec50c82464062f0.tar.bz2
Camera: Drop ProCamera connections when a Camera connection happens
* Also adds an ICameraServiceListener with available/not available statuses Bug: 8291653 Change-Id: I24680f1a2dc109510caf451cf7c7bd180b670d84
Diffstat (limited to 'camera')
-rw-r--r--camera/Android.mk1
-rw-r--r--camera/CameraBase.cpp16
-rw-r--r--camera/ICameraService.cpp33
-rw-r--r--camera/ICameraServiceListener.cpp86
-rw-r--r--camera/tests/ProCameraTests.cpp150
5 files changed, 274 insertions, 12 deletions
diff --git a/camera/Android.mk b/camera/Android.mk
index 3f30079..e33fb50 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -11,6 +11,7 @@ LOCAL_SRC_FILES:= \
ICamera.cpp \
ICameraClient.cpp \
ICameraService.cpp \
+ ICameraServiceListener.cpp \
ICameraRecordingProxy.cpp \
ICameraRecordingProxyListener.cpp \
IProCameraUser.cpp \
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index 9b0e6bf..29096da 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -231,6 +231,22 @@ status_t CameraBase<TCam, TCamTraits>::getCameraInfo(int cameraId,
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>;
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index b54d63f..134f7f0 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -23,6 +23,7 @@
#include <binder/IServiceManager.h>
#include <camera/ICameraService.h>
+#include <camera/ICameraServiceListener.h>
#include <camera/IProCameraUser.h>
#include <camera/IProCameraCallbacks.h>
#include <camera/ICamera.h>
@@ -86,6 +87,24 @@ public:
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");
@@ -134,6 +153,20 @@ status_t BnCameraService::onTransact(
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/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index 39456af..c61e71a 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 @@ namespace client {
#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 @@ namespace client {
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 @@ protected:
}
request.acquire(requestTmp);
}
-
};
sp<Thread> ProCameraTest::mTestThread;
@@ -538,18 +585,52 @@ TEST_F(ProCameraTest, DISABLED_StreamingImageSingle) {
}
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());
}
@@ -1035,6 +1116,51 @@ TEST_F(ProCameraTest, WaitForSingleStreamBufferAndDropFrames) {
+//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));
+}
+
+
+
}
}
}