1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/camera/TestGonkCameraHardware.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,503 @@ 1.4 +/* 1.5 + * Copyright (C) 2013-2014 Mozilla Foundation 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * Unless required by applicable law or agreed to in writing, software 1.14 + * distributed under the License is distributed on an "AS IS" BASIS, 1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.16 + * See the License for the specific language governing permissions and 1.17 + * limitations under the License. 1.18 + */ 1.19 + 1.20 +#include "TestGonkCameraHardware.h" 1.21 + 1.22 +#include "mozilla/Preferences.h" 1.23 +#include "nsThreadUtils.h" 1.24 + 1.25 +using namespace android; 1.26 +using namespace mozilla; 1.27 + 1.28 +TestGonkCameraHardware::TestGonkCameraHardware(nsGonkCameraControl* aTarget, 1.29 + uint32_t aCameraId, 1.30 + const sp<Camera>& aCamera) 1.31 + : GonkCameraHardware(aTarget, aCameraId, aCamera) 1.32 +{ 1.33 + DOM_CAMERA_LOGA("v===== Created TestGonkCameraHardware =====v\n"); 1.34 + DOM_CAMERA_LOGT("%s:%d : this=%p (aTarget=%p)\n", 1.35 + __func__, __LINE__, this, aTarget); 1.36 + MOZ_COUNT_CTOR(TestGonkCameraHardware); 1.37 +} 1.38 + 1.39 +TestGonkCameraHardware::~TestGonkCameraHardware() 1.40 +{ 1.41 + MOZ_COUNT_DTOR(TestGonkCameraHardware); 1.42 + DOM_CAMERA_LOGA("^===== Destroyed TestGonkCameraHardware =====^\n"); 1.43 +} 1.44 + 1.45 +nsresult 1.46 +TestGonkCameraHardware::Init() 1.47 +{ 1.48 + if (IsTestCase("init-failure")) { 1.49 + return NS_ERROR_FAILURE; 1.50 + } 1.51 + 1.52 + return GonkCameraHardware::Init(); 1.53 +} 1.54 + 1.55 +const nsCString 1.56 +TestGonkCameraHardware::TestCase() 1.57 +{ 1.58 + const nsCString test = Preferences::GetCString("camera.control.test.hardware"); 1.59 + return test; 1.60 +} 1.61 + 1.62 +const nsCString 1.63 +TestGonkCameraHardware::GetExtraParameters() 1.64 +{ 1.65 + /** 1.66 + * The contents of this pref are appended to the flattened string of 1.67 + * parameters stuffed into GonkCameraParameters by the camera library. 1.68 + * It consists of semicolon-delimited key=value pairs, e.g. 1.69 + * 1.70 + * focus-mode=auto;flash-mode=auto;preview-size=1024x768 1.71 + * 1.72 + * The unflattening process breaks this string up on semicolon boundaries 1.73 + * and sets an entry in a hashtable of strings with the token before 1.74 + * the equals sign as the key, and the token after as the value. Because 1.75 + * the string is parsed in order, key=value pairs occuring later in the 1.76 + * string will replace value pairs appearing earlier, making it easy to 1.77 + * inject fake, testable values into the parameters table. 1.78 + * 1.79 + * One constraint of this approach is that neither the key nor the value 1.80 + * may contain equals signs or semicolons. We don't enforce that here 1.81 + * so that we can also test correct handling of improperly-formatted values. 1.82 + */ 1.83 + const nsCString parameters = Preferences::GetCString("camera.control.test.hardware.gonk.parameters"); 1.84 + DOM_CAMERA_LOGA("TestGonkCameraHardware : extra-parameters '%s'\n", 1.85 + parameters.get()); 1.86 + return parameters; 1.87 +} 1.88 + 1.89 +bool 1.90 +TestGonkCameraHardware::IsTestCaseInternal(const char* aTest, const char* aFile, int aLine) 1.91 +{ 1.92 + if (TestCase().EqualsASCII(aTest)) { 1.93 + DOM_CAMERA_LOGA("TestGonkCameraHardware : test-case '%s' (%s:%d)\n", 1.94 + aTest, aFile, aLine); 1.95 + return true; 1.96 + } 1.97 + 1.98 + return false; 1.99 +} 1.100 + 1.101 +int 1.102 +TestGonkCameraHardware::TestCaseError(int aDefaultError) 1.103 +{ 1.104 + // for now, just return the default error 1.105 + return aDefaultError; 1.106 +} 1.107 + 1.108 +int 1.109 +TestGonkCameraHardware::AutoFocus() 1.110 +{ 1.111 + class AutoFocusFailure : public nsRunnable 1.112 + { 1.113 + public: 1.114 + AutoFocusFailure(nsGonkCameraControl* aTarget) 1.115 + : mTarget(aTarget) 1.116 + { } 1.117 + 1.118 + NS_IMETHODIMP 1.119 + Run() 1.120 + { 1.121 + OnAutoFocusComplete(mTarget, false); 1.122 + return NS_OK; 1.123 + } 1.124 + 1.125 + protected: 1.126 + nsGonkCameraControl* mTarget; 1.127 + }; 1.128 + 1.129 + if (IsTestCase("auto-focus-failure")) { 1.130 + return TestCaseError(UNKNOWN_ERROR); 1.131 + } 1.132 + if (IsTestCase("auto-focus-process-failure")) { 1.133 + nsresult rv = NS_DispatchToCurrentThread(new AutoFocusFailure(mTarget)); 1.134 + if (NS_SUCCEEDED(rv)) { 1.135 + return OK; 1.136 + } 1.137 + DOM_CAMERA_LOGE("Failed to dispatch AutoFocusFailure runnable (0x%08x)\n", rv); 1.138 + return UNKNOWN_ERROR; 1.139 + } 1.140 + 1.141 + return GonkCameraHardware::AutoFocus(); 1.142 +} 1.143 + 1.144 +// These classes have to be external to StartFaceDetection(), at least 1.145 +// until we pick up gcc 4.5, which supports local classes as template 1.146 +// arguments. 1.147 +class FaceDetected : public nsRunnable 1.148 +{ 1.149 +public: 1.150 + FaceDetected(nsGonkCameraControl* aTarget) 1.151 + : mTarget(aTarget) 1.152 + { } 1.153 + 1.154 + ~FaceDetected() 1.155 + { 1.156 + ReleaseFacesArray(); 1.157 + } 1.158 + 1.159 + NS_IMETHODIMP 1.160 + Run() 1.161 + { 1.162 + InitMetaData(); 1.163 + OnFacesDetected(mTarget, &mMetaData); 1.164 + return NS_OK; 1.165 + } 1.166 + 1.167 +protected: 1.168 + virtual nsresult InitMetaData() = 0; 1.169 + 1.170 + nsresult 1.171 + AllocateFacesArray(uint32_t num) 1.172 + { 1.173 + mMetaData.faces = new camera_face_t[num]; 1.174 + return NS_OK; 1.175 + } 1.176 + 1.177 + nsresult 1.178 + ReleaseFacesArray() 1.179 + { 1.180 + delete [] mMetaData.faces; 1.181 + mMetaData.faces = nullptr; 1.182 + return NS_OK; 1.183 + } 1.184 + 1.185 + nsRefPtr<nsGonkCameraControl> mTarget; 1.186 + camera_frame_metadata_t mMetaData; 1.187 +}; 1.188 + 1.189 +class OneFaceDetected : public FaceDetected 1.190 +{ 1.191 +public: 1.192 + OneFaceDetected(nsGonkCameraControl* aTarget) 1.193 + : FaceDetected(aTarget) 1.194 + { } 1.195 + 1.196 + nsresult 1.197 + InitMetaData() MOZ_OVERRIDE 1.198 + { 1.199 + mMetaData.number_of_faces = 1; 1.200 + AllocateFacesArray(1); 1.201 + mMetaData.faces[0].id = 1; 1.202 + mMetaData.faces[0].score = 2; 1.203 + mMetaData.faces[0].rect[0] = 3; 1.204 + mMetaData.faces[0].rect[1] = 4; 1.205 + mMetaData.faces[0].rect[2] = 5; 1.206 + mMetaData.faces[0].rect[3] = 6; 1.207 + mMetaData.faces[0].left_eye[0] = 7; 1.208 + mMetaData.faces[0].left_eye[1] = 8; 1.209 + mMetaData.faces[0].right_eye[0] = 9; 1.210 + mMetaData.faces[0].right_eye[1] = 10; 1.211 + mMetaData.faces[0].mouth[0] = 11; 1.212 + mMetaData.faces[0].mouth[1] = 12; 1.213 + 1.214 + return NS_OK; 1.215 + } 1.216 +}; 1.217 + 1.218 +class TwoFacesDetected : public FaceDetected 1.219 +{ 1.220 +public: 1.221 + TwoFacesDetected(nsGonkCameraControl* aTarget) 1.222 + : FaceDetected(aTarget) 1.223 + { } 1.224 + 1.225 + nsresult 1.226 + InitMetaData() MOZ_OVERRIDE 1.227 + { 1.228 + mMetaData.number_of_faces = 2; 1.229 + AllocateFacesArray(2); 1.230 + mMetaData.faces[0].id = 1; 1.231 + mMetaData.faces[0].score = 2; 1.232 + mMetaData.faces[0].rect[0] = 3; 1.233 + mMetaData.faces[0].rect[1] = 4; 1.234 + mMetaData.faces[0].rect[2] = 5; 1.235 + mMetaData.faces[0].rect[3] = 6; 1.236 + mMetaData.faces[0].left_eye[0] = 7; 1.237 + mMetaData.faces[0].left_eye[1] = 8; 1.238 + mMetaData.faces[0].right_eye[0] = 9; 1.239 + mMetaData.faces[0].right_eye[1] = 10; 1.240 + mMetaData.faces[0].mouth[0] = 11; 1.241 + mMetaData.faces[0].mouth[1] = 12; 1.242 + mMetaData.faces[1].id = 13; 1.243 + mMetaData.faces[1].score = 14; 1.244 + mMetaData.faces[1].rect[0] = 15; 1.245 + mMetaData.faces[1].rect[1] = 16; 1.246 + mMetaData.faces[1].rect[2] = 17; 1.247 + mMetaData.faces[1].rect[3] = 18; 1.248 + mMetaData.faces[1].left_eye[0] = 19; 1.249 + mMetaData.faces[1].left_eye[1] = 20; 1.250 + mMetaData.faces[1].right_eye[0] = 21; 1.251 + mMetaData.faces[1].right_eye[1] = 22; 1.252 + mMetaData.faces[1].mouth[0] = 23; 1.253 + mMetaData.faces[1].mouth[1] = 24; 1.254 + 1.255 + return NS_OK; 1.256 + } 1.257 +}; 1.258 + 1.259 +class OneFaceNoFeaturesDetected : public FaceDetected 1.260 +{ 1.261 +public: 1.262 + OneFaceNoFeaturesDetected(nsGonkCameraControl* aTarget) 1.263 + : FaceDetected(aTarget) 1.264 + { } 1.265 + 1.266 + nsresult 1.267 + InitMetaData() MOZ_OVERRIDE 1.268 + { 1.269 + mMetaData.number_of_faces = 1; 1.270 + AllocateFacesArray(1); 1.271 + mMetaData.faces[0].id = 1; 1.272 + // Test clamping 'score' to 100. 1.273 + mMetaData.faces[0].score = 1000; 1.274 + mMetaData.faces[0].rect[0] = 3; 1.275 + mMetaData.faces[0].rect[1] = 4; 1.276 + mMetaData.faces[0].rect[2] = 5; 1.277 + mMetaData.faces[0].rect[3] = 6; 1.278 + // Nullable values set to 'not-supported' specific values 1.279 + mMetaData.faces[0].left_eye[0] = -2000; 1.280 + mMetaData.faces[0].left_eye[1] = -2000; 1.281 + // Test other 'not-supported' values as well. We treat 1.282 + // anything outside the range [-1000, 1000] as invalid. 1.283 + mMetaData.faces[0].right_eye[0] = 1001; 1.284 + mMetaData.faces[0].right_eye[1] = -1001; 1.285 + mMetaData.faces[0].mouth[0] = -2000; 1.286 + mMetaData.faces[0].mouth[1] = 2000; 1.287 + 1.288 + return NS_OK; 1.289 + } 1.290 +}; 1.291 + 1.292 +class NoFacesDetected : public FaceDetected 1.293 +{ 1.294 +public: 1.295 + NoFacesDetected(nsGonkCameraControl* aTarget) 1.296 + : FaceDetected(aTarget) 1.297 + { } 1.298 + 1.299 + nsresult 1.300 + InitMetaData() MOZ_OVERRIDE 1.301 + { 1.302 + mMetaData.number_of_faces = 0; 1.303 + mMetaData.faces = nullptr; 1.304 + 1.305 + return NS_OK; 1.306 + } 1.307 +}; 1.308 + 1.309 +int 1.310 +TestGonkCameraHardware::StartFaceDetection() 1.311 +{ 1.312 + nsRefPtr<FaceDetected> faceDetected; 1.313 + 1.314 + if (IsTestCase("face-detection-detected-one-face")) { 1.315 + faceDetected = new OneFaceDetected(mTarget); 1.316 + } else if (IsTestCase("face-detection-detected-two-faces")) { 1.317 + faceDetected = new TwoFacesDetected(mTarget); 1.318 + } else if (IsTestCase("face-detection-detected-one-face-no-features")) { 1.319 + faceDetected = new OneFaceNoFeaturesDetected(mTarget); 1.320 + } else if (IsTestCase("face-detection-no-faces-detected")) { 1.321 + faceDetected = new NoFacesDetected(mTarget); 1.322 + } 1.323 + 1.324 + if (!faceDetected) { 1.325 + return GonkCameraHardware::StartFaceDetection(); 1.326 + } 1.327 + 1.328 + nsresult rv = NS_DispatchToCurrentThread(faceDetected); 1.329 + if (NS_FAILED(rv)) { 1.330 + DOM_CAMERA_LOGE("Failed to dispatch FaceDetected runnable (0x%08x)\n", rv); 1.331 + return UNKNOWN_ERROR; 1.332 + } 1.333 + 1.334 + return OK; 1.335 +} 1.336 + 1.337 +int 1.338 +TestGonkCameraHardware::StopFaceDetection() 1.339 +{ 1.340 + if (IsTestCase("face-detection-detected-one-face") || 1.341 + IsTestCase("face-detection-detected-two-faces") || 1.342 + IsTestCase("face-detection-detected-one-face-no-features") || 1.343 + IsTestCase("face-detection-no-faces-detected")) 1.344 + { 1.345 + return OK; 1.346 + } 1.347 + 1.348 + return GonkCameraHardware::StopFaceDetection(); 1.349 +} 1.350 + 1.351 +int 1.352 +TestGonkCameraHardware::TakePicture() 1.353 +{ 1.354 + class TakePictureFailure : public nsRunnable 1.355 + { 1.356 + public: 1.357 + TakePictureFailure(nsGonkCameraControl* aTarget) 1.358 + : mTarget(aTarget) 1.359 + { } 1.360 + 1.361 + NS_IMETHODIMP 1.362 + Run() 1.363 + { 1.364 + OnTakePictureError(mTarget); 1.365 + return NS_OK; 1.366 + } 1.367 + 1.368 + protected: 1.369 + nsGonkCameraControl* mTarget; 1.370 + }; 1.371 + 1.372 + if (IsTestCase("take-picture-failure")) { 1.373 + return TestCaseError(UNKNOWN_ERROR); 1.374 + } 1.375 + if (IsTestCase("take-picture-process-failure")) { 1.376 + nsresult rv = NS_DispatchToCurrentThread(new TakePictureFailure(mTarget)); 1.377 + if (NS_SUCCEEDED(rv)) { 1.378 + return OK; 1.379 + } 1.380 + DOM_CAMERA_LOGE("Failed to dispatch TakePictureFailure runnable (0x%08x)\n", rv); 1.381 + return UNKNOWN_ERROR; 1.382 + } 1.383 + 1.384 + return GonkCameraHardware::TakePicture(); 1.385 +} 1.386 + 1.387 +int 1.388 +TestGonkCameraHardware::StartPreview() 1.389 +{ 1.390 + if (IsTestCase("start-preview-failure")) { 1.391 + return TestCaseError(UNKNOWN_ERROR); 1.392 + } 1.393 + 1.394 + return GonkCameraHardware::StartPreview(); 1.395 +} 1.396 + 1.397 +int 1.398 +TestGonkCameraHardware::StartAutoFocusMoving(bool aIsMoving) 1.399 +{ 1.400 + class AutoFocusMoving : public nsRunnable 1.401 + { 1.402 + public: 1.403 + AutoFocusMoving(nsGonkCameraControl* aTarget, bool aIsMoving) 1.404 + : mTarget(aTarget) 1.405 + , mIsMoving(aIsMoving) 1.406 + { } 1.407 + 1.408 + NS_IMETHODIMP 1.409 + Run() 1.410 + { 1.411 + OnAutoFocusMoving(mTarget, mIsMoving); 1.412 + return NS_OK; 1.413 + } 1.414 + 1.415 + protected: 1.416 + nsGonkCameraControl* mTarget; 1.417 + bool mIsMoving; 1.418 + }; 1.419 + 1.420 + nsresult rv = NS_DispatchToCurrentThread(new AutoFocusMoving(mTarget, aIsMoving)); 1.421 + if (NS_SUCCEEDED(rv)) { 1.422 + return OK; 1.423 + } 1.424 + DOM_CAMERA_LOGE("Failed to dispatch AutoFocusMoving runnable (0x%08x)\n", rv); 1.425 + return UNKNOWN_ERROR; 1.426 +} 1.427 + 1.428 +int 1.429 +TestGonkCameraHardware::PushParameters(const GonkCameraParameters& aParams) 1.430 +{ 1.431 + if (IsTestCase("push-parameters-failure")) { 1.432 + return TestCaseError(UNKNOWN_ERROR); 1.433 + } 1.434 + 1.435 + nsString focusMode; 1.436 + GonkCameraParameters& params = const_cast<GonkCameraParameters&>(aParams); 1.437 + params.Get(CAMERA_PARAM_FOCUSMODE, focusMode); 1.438 + if (focusMode.EqualsASCII("continuous-picture") || 1.439 + focusMode.EqualsASCII("continuous-video")) 1.440 + { 1.441 + if (IsTestCase("autofocus-moving-true")) { 1.442 + return StartAutoFocusMoving(true); 1.443 + } else if (IsTestCase("autofocus-moving-false")) { 1.444 + return StartAutoFocusMoving(false); 1.445 + } 1.446 + } 1.447 + 1.448 + return GonkCameraHardware::PushParameters(aParams); 1.449 +} 1.450 + 1.451 +nsresult 1.452 +TestGonkCameraHardware::PullParameters(GonkCameraParameters& aParams) 1.453 +{ 1.454 + if (IsTestCase("pull-parameters-failure")) { 1.455 + return static_cast<nsresult>(TestCaseError(UNKNOWN_ERROR)); 1.456 + } 1.457 + 1.458 + String8 s = mCamera->getParameters(); 1.459 + nsCString extra = GetExtraParameters(); 1.460 + if (!extra.IsEmpty()) { 1.461 + s += ";"; 1.462 + s += extra.get(); 1.463 + } 1.464 + 1.465 + return aParams.Unflatten(s); 1.466 +} 1.467 + 1.468 +int 1.469 +TestGonkCameraHardware::StartRecording() 1.470 +{ 1.471 + if (IsTestCase("start-recording-failure")) { 1.472 + return TestCaseError(UNKNOWN_ERROR); 1.473 + } 1.474 + 1.475 + return GonkCameraHardware::StartRecording(); 1.476 +} 1.477 + 1.478 +int 1.479 +TestGonkCameraHardware::StopRecording() 1.480 +{ 1.481 + if (IsTestCase("stop-recording-failure")) { 1.482 + return TestCaseError(UNKNOWN_ERROR); 1.483 + } 1.484 + 1.485 + return GonkCameraHardware::StopRecording(); 1.486 +} 1.487 + 1.488 +int 1.489 +TestGonkCameraHardware::SetListener(const sp<GonkCameraListener>& aListener) 1.490 +{ 1.491 + if (IsTestCase("set-listener-failure")) { 1.492 + return TestCaseError(UNKNOWN_ERROR); 1.493 + } 1.494 + 1.495 + return GonkCameraHardware::SetListener(aListener); 1.496 +} 1.497 + 1.498 +int 1.499 +TestGonkCameraHardware::StoreMetaDataInBuffers(bool aEnabled) 1.500 +{ 1.501 + if (IsTestCase("store-metadata-in-buffers-failure")) { 1.502 + return TestCaseError(UNKNOWN_ERROR); 1.503 + } 1.504 + 1.505 + return GonkCameraHardware::StoreMetaDataInBuffers(aEnabled); 1.506 +}