1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "ACameraManagerTest"
18 //#define LOG_NDEBUG 0
19 
20 #include <gtest/gtest.h>
21 
22 #include <mutex>
23 #include <set>
24 #include <string>
25 
26 #include <utils/Log.h>
27 #include <camera/NdkCameraError.h>
28 #include <camera/NdkCameraManager.h>
29 
30 namespace {
31 
32 class CameraServiceListener {
33   public:
34     typedef std::set<std::pair<std::string, std::string>> StringPairSet;
35 
onAvailable(void * obj,const char * cameraId)36     static void onAvailable(void* obj, const char* cameraId) {
37         ALOGV("Camera %s onAvailable", cameraId);
38         if (obj == nullptr) {
39             return;
40         }
41         CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
42         std::lock_guard<std::mutex> lock(thiz->mMutex);
43         thiz->mOnAvailableCount++;
44         thiz->mAvailableMap[cameraId] = true;
45         return;
46     }
47 
onUnavailable(void * obj,const char * cameraId)48     static void onUnavailable(void* obj, const char* cameraId) {
49         ALOGV("Camera %s onUnavailable", cameraId);
50         if (obj == nullptr) {
51             return;
52         }
53         CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
54         std::lock_guard<std::mutex> lock(thiz->mMutex);
55         thiz->mOnUnavailableCount++;
56         thiz->mAvailableMap[cameraId] = false;
57         return;
58     }
59 
onCameraAccessPrioritiesChanged(void *)60     static void onCameraAccessPrioritiesChanged(void* /*obj*/) {
61         return;
62     }
63 
onPhysicalCameraAvailable(void * obj,const char * cameraId,const char * physicalCameraId)64     static void onPhysicalCameraAvailable(void* obj, const char* cameraId,
65             const char* physicalCameraId) {
66         ALOGV("Camera %s : %s onAvailable", cameraId, physicalCameraId);
67         if (obj == nullptr) {
68             return;
69         }
70         CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
71         std::lock_guard<std::mutex> lock(thiz->mMutex);
72         thiz->mOnPhysicalCameraAvailableCount++;
73         return;
74     }
75 
onPhysicalCameraUnavailable(void * obj,const char * cameraId,const char * physicalCameraId)76     static void onPhysicalCameraUnavailable(void* obj, const char* cameraId,
77             const char* physicalCameraId) {
78         ALOGV("Camera %s : %s onUnavailable", cameraId, physicalCameraId);
79         if (obj == nullptr) {
80             return;
81         }
82         CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj);
83         std::lock_guard<std::mutex> lock(thiz->mMutex);
84         thiz->mUnavailablePhysicalCameras.emplace(cameraId, physicalCameraId);
85         return;
86     }
87 
resetCount()88     void resetCount() {
89         std::lock_guard<std::mutex> lock(mMutex);
90         mOnAvailableCount = 0;
91         mOnUnavailableCount = 0;
92         mOnPhysicalCameraAvailableCount = 0;
93         mUnavailablePhysicalCameras.clear();
94         return;
95     }
96 
getAvailableCount()97     int getAvailableCount() {
98         std::lock_guard<std::mutex> lock(mMutex);
99         return mOnAvailableCount;
100     }
101 
getUnavailableCount()102     int getUnavailableCount() {
103         std::lock_guard<std::mutex> lock(mMutex);
104         return mOnUnavailableCount;
105     }
106 
getPhysicalCameraAvailableCount()107     int getPhysicalCameraAvailableCount() {
108         std::lock_guard<std::mutex> lock(mMutex);
109         return mOnPhysicalCameraAvailableCount;
110     }
111 
getUnavailablePhysicalCameras()112     StringPairSet getUnavailablePhysicalCameras() {
113         std::lock_guard<std::mutex> lock(mMutex);
114         return mUnavailablePhysicalCameras;
115     }
116 
isAvailable(const char * cameraId)117     bool isAvailable(const char* cameraId) {
118         std::lock_guard<std::mutex> lock(mMutex);
119         if (mAvailableMap.count(cameraId) == 0) {
120             return false;
121         }
122         return mAvailableMap[cameraId];
123     }
124 
125   private:
126     std::mutex mMutex;
127     int mOnAvailableCount = 0;
128     int mOnUnavailableCount = 0;
129     int mOnPhysicalCameraAvailableCount = 0;
130     std::map<std::string, bool> mAvailableMap;
131     StringPairSet mUnavailablePhysicalCameras;
132 };
133 
134 class ACameraManagerTest : public ::testing::Test {
135   public:
SetUp()136     void SetUp() override {
137         mCameraManager = ACameraManager_create();
138         if (mCameraManager == nullptr) {
139             ALOGE("Failed to create ACameraManager.");
140             return;
141         }
142 
143         camera_status_t ret = ACameraManager_getCameraIdList(mCameraManager, &mCameraIdList);
144         if (ret != ACAMERA_OK) {
145             ALOGE("Failed to get cameraIdList: ret=%d", ret);
146             return;
147         }
148         if (mCameraIdList->numCameras < 1) {
149             ALOGW("Device has no camera on board.");
150             return;
151         }
152     }
TearDown()153     void TearDown() override {
154         // Destroy camera manager
155         if (mCameraIdList) {
156             ACameraManager_deleteCameraIdList(mCameraIdList);
157             mCameraIdList = nullptr;
158         }
159         if (mCameraManager) {
160             ACameraManager_delete(mCameraManager);
161             mCameraManager = nullptr;
162         }
163     }
164 
165     // Camera manager
166     ACameraManager* mCameraManager = nullptr;
167     ACameraIdList* mCameraIdList = nullptr;
168     CameraServiceListener mAvailabilityListener;
169     ACameraManager_ExtendedAvailabilityCallbacks mCbs = {
170         {
171             &mAvailabilityListener,
172                 CameraServiceListener::onAvailable,
173                 CameraServiceListener::onUnavailable
174         },
175         CameraServiceListener::onCameraAccessPrioritiesChanged,
176         CameraServiceListener::onPhysicalCameraAvailable,
177         CameraServiceListener::onPhysicalCameraUnavailable,
178         {}
179     };
180 };
181 
TEST_F(ACameraManagerTest,testCameraManagerExtendedAvailabilityCallbacks)182 TEST_F(ACameraManagerTest, testCameraManagerExtendedAvailabilityCallbacks) {
183     camera_status_t ret = ACameraManager_registerExtendedAvailabilityCallback(mCameraManager,
184             &mCbs);
185     ASSERT_EQ(ret, ACAMERA_OK);
186 
187     sleep(1);
188 
189     // Should at least get onAvailable for each camera once
190     ASSERT_EQ(mAvailabilityListener.getAvailableCount(), mCameraIdList->numCameras);
191 
192     // Expect no available callbacks for physical cameras
193     int availablePhysicalCamera = mAvailabilityListener.getPhysicalCameraAvailableCount();
194     ASSERT_EQ(availablePhysicalCamera, 0);
195 
196     CameraServiceListener::StringPairSet unavailablePhysicalCameras;
197     CameraServiceListener::StringPairSet physicalCameraIdPairs;
198 
199     unavailablePhysicalCameras = mAvailabilityListener.getUnavailablePhysicalCameras();
200     for (int i = 0; i < mCameraIdList->numCameras; i++) {
201         const char* cameraId = mCameraIdList->cameraIds[i];
202         ASSERT_NE(cameraId, nullptr);
203         ASSERT_TRUE(mAvailabilityListener.isAvailable(cameraId));
204 
205         ACameraMetadata* chars = nullptr;
206         ret = ACameraManager_getCameraCharacteristics(mCameraManager, cameraId, &chars);
207         ASSERT_EQ(ret, ACAMERA_OK);
208         ASSERT_NE(chars, nullptr);
209 
210         size_t physicalCameraCnt = 0;
211         const char *const* physicalCameraIds = nullptr;
212         if (!ACameraMetadata_isLogicalMultiCamera(
213                 chars, &physicalCameraCnt, &physicalCameraIds)) {
214             ACameraMetadata_free(chars);
215             continue;
216         }
217         for (size_t j = 0; j < physicalCameraCnt; j++) {
218             physicalCameraIdPairs.emplace(cameraId, physicalCameraIds[j]);
219         }
220         ACameraMetadata_free(chars);
221     }
222     for (const auto& unavailIdPair : unavailablePhysicalCameras) {
223         bool validPair = false;
224         for (const auto& idPair : physicalCameraIdPairs) {
225             if (idPair.first == unavailIdPair.first && idPair.second == unavailIdPair.second) {
226                 validPair = true;
227                 break;
228             }
229         }
230         // Expect valid unavailable physical cameras
231         ASSERT_TRUE(validPair);
232     }
233 
234     ret = ACameraManager_unregisterExtendedAvailabilityCallback(mCameraManager, &mCbs);
235     ASSERT_EQ(ret, ACAMERA_OK);
236 }
237 
238 }  // namespace
239