From 8fdfbe27acd157d58fa35a849ec50c82464062f0 Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Wed, 27 Feb 2013 12:55:20 -0800 Subject: Camera: Drop ProCamera connections when a Camera connection happens * Also adds an ICameraServiceListener with available/not available statuses Bug: 8291653 Change-Id: I24680f1a2dc109510caf451cf7c7bd180b670d84 --- camera/Android.mk | 1 + camera/CameraBase.cpp | 16 ++++ camera/ICameraService.cpp | 33 +++++++++ camera/ICameraServiceListener.cpp | 86 ++++++++++++++++++++++ camera/tests/ProCameraTests.cpp | 150 +++++++++++++++++++++++++++++++++++--- 5 files changed, 274 insertions(+), 12 deletions(-) create mode 100644 camera/ICameraServiceListener.cpp (limited to 'camera') 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::getCameraInfo(int cameraId, return cs->getCameraInfo(cameraId, cameraInfo); } +template +status_t CameraBase::addServiceListener( + const sp& listener) { + const sp& cs = getCameraService(); + if (cs == 0) return UNKNOWN_ERROR; + return cs->addListener(listener); +} + +template +status_t CameraBase::removeServiceListener( + const sp& listener) { + const sp& cs = getCameraService(); + if (cs == 0) return UNKNOWN_ERROR; + return cs->removeListener(listener); +} + template class CameraBase; template class CameraBase; 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 #include +#include #include #include #include @@ -86,6 +87,24 @@ public: remote()->transact(BnCameraService::CONNECT_PRO, data, &reply); return interface_cast(reply.readStrongBinder()); } + + virtual status_t addListener(const sp& 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& 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 listener = + interface_cast(data.readStrongBinder()); + reply->writeInt32(addListener(listener)); + return NO_ERROR; + } break; + case REMOVE_LISTENER: { + CHECK_INTERFACE(ICameraService, data, reply); + sp listener = + interface_cast(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 +#include + +#include +#include +#include + +#include + +namespace android { + +namespace { + enum { + STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION, + }; +}; // namespace anonymous + +class BpCameraServiceListener: public BpInterface +{ + +public: + BpCameraServiceListener(const sp& impl) + : BpInterface(impl) + { + } + + virtual void onStatusChanged(Status status, int32_t cameraId) + { + Parcel data, reply; + data.writeInterfaceToken( + ICameraServiceListener::getInterfaceDescriptor()); + + data.writeInt32(static_cast(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(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 // for CAMERA2_TEMPLATE_PREVIEW only #include +#include + 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 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 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 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 listener = new ServiceListener(); + + EXPECT_OK(ProCamera::addServiceListener(listener)); + + sp 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)); +} + + + } } } -- cgit v1.1