mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-31 14:15:30 +00:00
539 lines
13 KiB
C++
539 lines
13 KiB
C++
/*
|
|
* Copyright (C) 2013-2014 Mozilla Foundation
|
|
*
|
|
* 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 "TestGonkCameraHardware.h"
|
|
|
|
#include "CameraPreferences.h"
|
|
#include "nsThreadUtils.h"
|
|
|
|
using namespace android;
|
|
using namespace mozilla;
|
|
|
|
TestGonkCameraHardware::TestGonkCameraHardware(nsGonkCameraControl* aTarget,
|
|
uint32_t aCameraId,
|
|
const sp<Camera>& aCamera)
|
|
: GonkCameraHardware(aTarget, aCameraId, aCamera)
|
|
{
|
|
DOM_CAMERA_LOGA("v===== Created TestGonkCameraHardware =====v\n");
|
|
DOM_CAMERA_LOGT("%s:%d : this=%p (aTarget=%p)\n",
|
|
__func__, __LINE__, this, aTarget);
|
|
MOZ_COUNT_CTOR(TestGonkCameraHardware);
|
|
}
|
|
|
|
TestGonkCameraHardware::~TestGonkCameraHardware()
|
|
{
|
|
MOZ_COUNT_DTOR(TestGonkCameraHardware);
|
|
DOM_CAMERA_LOGA("^===== Destroyed TestGonkCameraHardware =====^\n");
|
|
}
|
|
|
|
void
|
|
TestGonkCameraHardware::InjectFakeSystemFailure()
|
|
{
|
|
DOM_CAMERA_LOGA("====== Fake Camera Hardware Failure ======\n");
|
|
// The values '100' and '0' below seem to be what the AOSP layer
|
|
// throws back when the mediaserver process fails.
|
|
OnSystemError(mTarget, CameraControlListener::kSystemService, 100, 0);
|
|
}
|
|
|
|
nsresult
|
|
TestGonkCameraHardware::Init()
|
|
{
|
|
class DeferredSystemFailure : public nsRunnable
|
|
{
|
|
public:
|
|
DeferredSystemFailure(TestGonkCameraHardware* aCameraHw)
|
|
: mCameraHw(aCameraHw)
|
|
{ }
|
|
|
|
NS_IMETHODIMP
|
|
Run()
|
|
{
|
|
mCameraHw->InjectFakeSystemFailure();
|
|
return NS_OK;
|
|
}
|
|
|
|
protected:
|
|
android::sp<TestGonkCameraHardware> mCameraHw;
|
|
};
|
|
|
|
if (IsTestCase("init-failure")) {
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
}
|
|
if (IsTestCase("post-init-system-failure")) {
|
|
nsCOMPtr<nsIThread> me = NS_GetCurrentThread();
|
|
if (me) {
|
|
me->Dispatch(new DeferredSystemFailure(this), NS_DISPATCH_NORMAL);
|
|
}
|
|
}
|
|
|
|
return GonkCameraHardware::Init();
|
|
}
|
|
|
|
const nsCString
|
|
TestGonkCameraHardware::TestCase()
|
|
{
|
|
nsCString test;
|
|
CameraPreferences::GetPref("camera.control.test.hardware", test);
|
|
return test;
|
|
}
|
|
|
|
const nsCString
|
|
TestGonkCameraHardware::GetExtraParameters()
|
|
{
|
|
/**
|
|
* The contents of this pref are appended to the flattened string of
|
|
* parameters stuffed into GonkCameraParameters by the camera library.
|
|
* It consists of semicolon-delimited key=value pairs, e.g.
|
|
*
|
|
* focus-mode=auto;flash-mode=auto;preview-size=1024x768
|
|
*
|
|
* The unflattening process breaks this string up on semicolon boundaries
|
|
* and sets an entry in a hashtable of strings with the token before
|
|
* the equals sign as the key, and the token after as the value. Because
|
|
* the string is parsed in order, key=value pairs occuring later in the
|
|
* string will replace value pairs appearing earlier, making it easy to
|
|
* inject fake, testable values into the parameters table.
|
|
*
|
|
* One constraint of this approach is that neither the key nor the value
|
|
* may contain equals signs or semicolons. We don't enforce that here
|
|
* so that we can also test correct handling of improperly-formatted values.
|
|
*/
|
|
nsCString parameters;
|
|
CameraPreferences::GetPref("camera.control.test.hardware.gonk.parameters", parameters);
|
|
DOM_CAMERA_LOGA("TestGonkCameraHardware : extra-parameters '%s'\n",
|
|
parameters.get());
|
|
return parameters;
|
|
}
|
|
|
|
bool
|
|
TestGonkCameraHardware::IsTestCaseInternal(const char* aTest, const char* aFile, int aLine)
|
|
{
|
|
if (TestCase().EqualsASCII(aTest)) {
|
|
DOM_CAMERA_LOGA("TestGonkCameraHardware : test-case '%s' (%s:%d)\n",
|
|
aTest, aFile, aLine);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int
|
|
TestGonkCameraHardware::TestCaseError(int aDefaultError)
|
|
{
|
|
// for now, just return the default error
|
|
return aDefaultError;
|
|
}
|
|
|
|
int
|
|
TestGonkCameraHardware::AutoFocus()
|
|
{
|
|
class AutoFocusFailure : public nsRunnable
|
|
{
|
|
public:
|
|
AutoFocusFailure(nsGonkCameraControl* aTarget)
|
|
: mTarget(aTarget)
|
|
{ }
|
|
|
|
NS_IMETHODIMP
|
|
Run()
|
|
{
|
|
OnAutoFocusComplete(mTarget, false);
|
|
return NS_OK;
|
|
}
|
|
|
|
protected:
|
|
nsGonkCameraControl* mTarget;
|
|
};
|
|
|
|
if (IsTestCase("auto-focus-failure")) {
|
|
return TestCaseError(UNKNOWN_ERROR);
|
|
}
|
|
if (IsTestCase("auto-focus-process-failure")) {
|
|
nsresult rv = NS_DispatchToCurrentThread(new AutoFocusFailure(mTarget));
|
|
if (NS_SUCCEEDED(rv)) {
|
|
return OK;
|
|
}
|
|
DOM_CAMERA_LOGE("Failed to dispatch AutoFocusFailure runnable (0x%08x)\n", rv);
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
return GonkCameraHardware::AutoFocus();
|
|
}
|
|
|
|
// These classes have to be external to StartFaceDetection(), at least
|
|
// until we pick up gcc 4.5, which supports local classes as template
|
|
// arguments.
|
|
class FaceDetected : public nsRunnable
|
|
{
|
|
public:
|
|
FaceDetected(nsGonkCameraControl* aTarget)
|
|
: mTarget(aTarget)
|
|
{ }
|
|
|
|
~FaceDetected()
|
|
{
|
|
ReleaseFacesArray();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Run()
|
|
{
|
|
InitMetaData();
|
|
OnFacesDetected(mTarget, &mMetaData);
|
|
return NS_OK;
|
|
}
|
|
|
|
protected:
|
|
virtual nsresult InitMetaData() = 0;
|
|
|
|
nsresult
|
|
AllocateFacesArray(uint32_t num)
|
|
{
|
|
mMetaData.faces = new camera_face_t[num];
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
ReleaseFacesArray()
|
|
{
|
|
delete [] mMetaData.faces;
|
|
mMetaData.faces = nullptr;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsRefPtr<nsGonkCameraControl> mTarget;
|
|
camera_frame_metadata_t mMetaData;
|
|
};
|
|
|
|
class OneFaceDetected : public FaceDetected
|
|
{
|
|
public:
|
|
OneFaceDetected(nsGonkCameraControl* aTarget)
|
|
: FaceDetected(aTarget)
|
|
{ }
|
|
|
|
nsresult
|
|
InitMetaData() MOZ_OVERRIDE
|
|
{
|
|
mMetaData.number_of_faces = 1;
|
|
AllocateFacesArray(1);
|
|
mMetaData.faces[0].id = 1;
|
|
mMetaData.faces[0].score = 2;
|
|
mMetaData.faces[0].rect[0] = 3;
|
|
mMetaData.faces[0].rect[1] = 4;
|
|
mMetaData.faces[0].rect[2] = 5;
|
|
mMetaData.faces[0].rect[3] = 6;
|
|
mMetaData.faces[0].left_eye[0] = 7;
|
|
mMetaData.faces[0].left_eye[1] = 8;
|
|
mMetaData.faces[0].right_eye[0] = 9;
|
|
mMetaData.faces[0].right_eye[1] = 10;
|
|
mMetaData.faces[0].mouth[0] = 11;
|
|
mMetaData.faces[0].mouth[1] = 12;
|
|
|
|
return NS_OK;
|
|
}
|
|
};
|
|
|
|
class TwoFacesDetected : public FaceDetected
|
|
{
|
|
public:
|
|
TwoFacesDetected(nsGonkCameraControl* aTarget)
|
|
: FaceDetected(aTarget)
|
|
{ }
|
|
|
|
nsresult
|
|
InitMetaData() MOZ_OVERRIDE
|
|
{
|
|
mMetaData.number_of_faces = 2;
|
|
AllocateFacesArray(2);
|
|
mMetaData.faces[0].id = 1;
|
|
mMetaData.faces[0].score = 2;
|
|
mMetaData.faces[0].rect[0] = 3;
|
|
mMetaData.faces[0].rect[1] = 4;
|
|
mMetaData.faces[0].rect[2] = 5;
|
|
mMetaData.faces[0].rect[3] = 6;
|
|
mMetaData.faces[0].left_eye[0] = 7;
|
|
mMetaData.faces[0].left_eye[1] = 8;
|
|
mMetaData.faces[0].right_eye[0] = 9;
|
|
mMetaData.faces[0].right_eye[1] = 10;
|
|
mMetaData.faces[0].mouth[0] = 11;
|
|
mMetaData.faces[0].mouth[1] = 12;
|
|
mMetaData.faces[1].id = 13;
|
|
mMetaData.faces[1].score = 14;
|
|
mMetaData.faces[1].rect[0] = 15;
|
|
mMetaData.faces[1].rect[1] = 16;
|
|
mMetaData.faces[1].rect[2] = 17;
|
|
mMetaData.faces[1].rect[3] = 18;
|
|
mMetaData.faces[1].left_eye[0] = 19;
|
|
mMetaData.faces[1].left_eye[1] = 20;
|
|
mMetaData.faces[1].right_eye[0] = 21;
|
|
mMetaData.faces[1].right_eye[1] = 22;
|
|
mMetaData.faces[1].mouth[0] = 23;
|
|
mMetaData.faces[1].mouth[1] = 24;
|
|
|
|
return NS_OK;
|
|
}
|
|
};
|
|
|
|
class OneFaceNoFeaturesDetected : public FaceDetected
|
|
{
|
|
public:
|
|
OneFaceNoFeaturesDetected(nsGonkCameraControl* aTarget)
|
|
: FaceDetected(aTarget)
|
|
{ }
|
|
|
|
nsresult
|
|
InitMetaData() MOZ_OVERRIDE
|
|
{
|
|
mMetaData.number_of_faces = 1;
|
|
AllocateFacesArray(1);
|
|
mMetaData.faces[0].id = 1;
|
|
// Test clamping 'score' to 100.
|
|
mMetaData.faces[0].score = 1000;
|
|
mMetaData.faces[0].rect[0] = 3;
|
|
mMetaData.faces[0].rect[1] = 4;
|
|
mMetaData.faces[0].rect[2] = 5;
|
|
mMetaData.faces[0].rect[3] = 6;
|
|
// Nullable values set to 'not-supported' specific values
|
|
mMetaData.faces[0].left_eye[0] = -2000;
|
|
mMetaData.faces[0].left_eye[1] = -2000;
|
|
// Test other 'not-supported' values as well. We treat
|
|
// anything outside the range [-1000, 1000] as invalid.
|
|
mMetaData.faces[0].right_eye[0] = 1001;
|
|
mMetaData.faces[0].right_eye[1] = -1001;
|
|
mMetaData.faces[0].mouth[0] = -2000;
|
|
mMetaData.faces[0].mouth[1] = 2000;
|
|
|
|
return NS_OK;
|
|
}
|
|
};
|
|
|
|
class NoFacesDetected : public FaceDetected
|
|
{
|
|
public:
|
|
NoFacesDetected(nsGonkCameraControl* aTarget)
|
|
: FaceDetected(aTarget)
|
|
{ }
|
|
|
|
nsresult
|
|
InitMetaData() MOZ_OVERRIDE
|
|
{
|
|
mMetaData.number_of_faces = 0;
|
|
mMetaData.faces = nullptr;
|
|
|
|
return NS_OK;
|
|
}
|
|
};
|
|
|
|
int
|
|
TestGonkCameraHardware::StartFaceDetection()
|
|
{
|
|
nsRefPtr<FaceDetected> faceDetected;
|
|
|
|
if (IsTestCase("face-detection-detected-one-face")) {
|
|
faceDetected = new OneFaceDetected(mTarget);
|
|
} else if (IsTestCase("face-detection-detected-two-faces")) {
|
|
faceDetected = new TwoFacesDetected(mTarget);
|
|
} else if (IsTestCase("face-detection-detected-one-face-no-features")) {
|
|
faceDetected = new OneFaceNoFeaturesDetected(mTarget);
|
|
} else if (IsTestCase("face-detection-no-faces-detected")) {
|
|
faceDetected = new NoFacesDetected(mTarget);
|
|
}
|
|
|
|
if (!faceDetected) {
|
|
return GonkCameraHardware::StartFaceDetection();
|
|
}
|
|
|
|
nsresult rv = NS_DispatchToCurrentThread(faceDetected);
|
|
if (NS_FAILED(rv)) {
|
|
DOM_CAMERA_LOGE("Failed to dispatch FaceDetected runnable (0x%08x)\n", rv);
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
int
|
|
TestGonkCameraHardware::StopFaceDetection()
|
|
{
|
|
if (IsTestCase("face-detection-detected-one-face") ||
|
|
IsTestCase("face-detection-detected-two-faces") ||
|
|
IsTestCase("face-detection-detected-one-face-no-features") ||
|
|
IsTestCase("face-detection-no-faces-detected"))
|
|
{
|
|
return OK;
|
|
}
|
|
|
|
return GonkCameraHardware::StopFaceDetection();
|
|
}
|
|
|
|
int
|
|
TestGonkCameraHardware::TakePicture()
|
|
{
|
|
class TakePictureFailure : public nsRunnable
|
|
{
|
|
public:
|
|
TakePictureFailure(nsGonkCameraControl* aTarget)
|
|
: mTarget(aTarget)
|
|
{ }
|
|
|
|
NS_IMETHODIMP
|
|
Run()
|
|
{
|
|
OnTakePictureError(mTarget);
|
|
return NS_OK;
|
|
}
|
|
|
|
protected:
|
|
nsGonkCameraControl* mTarget;
|
|
};
|
|
|
|
if (IsTestCase("take-picture-failure")) {
|
|
return TestCaseError(UNKNOWN_ERROR);
|
|
}
|
|
if (IsTestCase("take-picture-process-failure")) {
|
|
nsresult rv = NS_DispatchToCurrentThread(new TakePictureFailure(mTarget));
|
|
if (NS_SUCCEEDED(rv)) {
|
|
return OK;
|
|
}
|
|
DOM_CAMERA_LOGE("Failed to dispatch TakePictureFailure runnable (0x%08x)\n", rv);
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
return GonkCameraHardware::TakePicture();
|
|
}
|
|
|
|
int
|
|
TestGonkCameraHardware::StartPreview()
|
|
{
|
|
if (IsTestCase("start-preview-failure")) {
|
|
return TestCaseError(UNKNOWN_ERROR);
|
|
}
|
|
|
|
return GonkCameraHardware::StartPreview();
|
|
}
|
|
|
|
int
|
|
TestGonkCameraHardware::StartAutoFocusMoving(bool aIsMoving)
|
|
{
|
|
class AutoFocusMoving : public nsRunnable
|
|
{
|
|
public:
|
|
AutoFocusMoving(nsGonkCameraControl* aTarget, bool aIsMoving)
|
|
: mTarget(aTarget)
|
|
, mIsMoving(aIsMoving)
|
|
{ }
|
|
|
|
NS_IMETHODIMP
|
|
Run()
|
|
{
|
|
OnAutoFocusMoving(mTarget, mIsMoving);
|
|
return NS_OK;
|
|
}
|
|
|
|
protected:
|
|
nsGonkCameraControl* mTarget;
|
|
bool mIsMoving;
|
|
};
|
|
|
|
nsresult rv = NS_DispatchToCurrentThread(new AutoFocusMoving(mTarget, aIsMoving));
|
|
if (NS_SUCCEEDED(rv)) {
|
|
return OK;
|
|
}
|
|
DOM_CAMERA_LOGE("Failed to dispatch AutoFocusMoving runnable (0x%08x)\n", rv);
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
int
|
|
TestGonkCameraHardware::PushParameters(const GonkCameraParameters& aParams)
|
|
{
|
|
if (IsTestCase("push-parameters-failure")) {
|
|
return TestCaseError(UNKNOWN_ERROR);
|
|
}
|
|
|
|
nsString focusMode;
|
|
GonkCameraParameters& params = const_cast<GonkCameraParameters&>(aParams);
|
|
params.Get(CAMERA_PARAM_FOCUSMODE, focusMode);
|
|
if (focusMode.EqualsASCII("continuous-picture") ||
|
|
focusMode.EqualsASCII("continuous-video"))
|
|
{
|
|
if (IsTestCase("autofocus-moving-true")) {
|
|
return StartAutoFocusMoving(true);
|
|
} else if (IsTestCase("autofocus-moving-false")) {
|
|
return StartAutoFocusMoving(false);
|
|
}
|
|
}
|
|
|
|
return GonkCameraHardware::PushParameters(aParams);
|
|
}
|
|
|
|
nsresult
|
|
TestGonkCameraHardware::PullParameters(GonkCameraParameters& aParams)
|
|
{
|
|
if (IsTestCase("pull-parameters-failure")) {
|
|
return static_cast<nsresult>(TestCaseError(UNKNOWN_ERROR));
|
|
}
|
|
|
|
String8 s = mCamera->getParameters();
|
|
nsCString extra = GetExtraParameters();
|
|
if (!extra.IsEmpty()) {
|
|
s += ";";
|
|
s += extra.get();
|
|
}
|
|
|
|
return aParams.Unflatten(s);
|
|
}
|
|
|
|
int
|
|
TestGonkCameraHardware::StartRecording()
|
|
{
|
|
if (IsTestCase("start-recording-failure")) {
|
|
return TestCaseError(UNKNOWN_ERROR);
|
|
}
|
|
|
|
return GonkCameraHardware::StartRecording();
|
|
}
|
|
|
|
int
|
|
TestGonkCameraHardware::StopRecording()
|
|
{
|
|
if (IsTestCase("stop-recording-failure")) {
|
|
return TestCaseError(UNKNOWN_ERROR);
|
|
}
|
|
|
|
return GonkCameraHardware::StopRecording();
|
|
}
|
|
|
|
int
|
|
TestGonkCameraHardware::SetListener(const sp<GonkCameraListener>& aListener)
|
|
{
|
|
if (IsTestCase("set-listener-failure")) {
|
|
return TestCaseError(UNKNOWN_ERROR);
|
|
}
|
|
|
|
return GonkCameraHardware::SetListener(aListener);
|
|
}
|
|
|
|
int
|
|
TestGonkCameraHardware::StoreMetaDataInBuffers(bool aEnabled)
|
|
{
|
|
if (IsTestCase("store-metadata-in-buffers-failure")) {
|
|
return TestCaseError(UNKNOWN_ERROR);
|
|
}
|
|
|
|
return GonkCameraHardware::StoreMetaDataInBuffers(aEnabled);
|
|
}
|