Merge changes I1610beb9,Ibcf607d0
* changes:
Fix typo CELCIUS -> CELSIUS in Vehicle HAL
Fix config map in default Vehicle HAL impl
diff --git a/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
index a339f99..e50b912 100644
--- a/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
+++ b/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -49,6 +49,7 @@
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
+using ::android::hardware::MQDescriptorSync;
using ::android::hardware::audio::V2_0::DeviceAddress;
using ::android::hardware::audio::V2_0::IDevice;
using ::android::hardware::audio::V2_0::IPrimaryDevice;
@@ -56,7 +57,11 @@
using ::android::hardware::audio::V2_0::IDevicesFactory;
using ::android::hardware::audio::V2_0::IStream;
using ::android::hardware::audio::V2_0::IStreamIn;
+using ReadParameters = ::android::hardware::audio::V2_0::IStreamIn::ReadParameters;
+using ReadStatus = ::android::hardware::audio::V2_0::IStreamIn::ReadStatus;
using ::android::hardware::audio::V2_0::IStreamOut;
+using ::android::hardware::audio::V2_0::MmapBufferInfo;
+using ::android::hardware::audio::V2_0::MmapPosition;
using ::android::hardware::audio::V2_0::ParameterValue;
using ::android::hardware::audio::V2_0::Result;
using ::android::hardware::audio::common::V2_0::AudioChannelMask;
@@ -70,6 +75,7 @@
using ::android::hardware::audio::common::V2_0::AudioOffloadInfo;
using ::android::hardware::audio::common::V2_0::AudioOutputFlag;
using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::common::V2_0::ThreadInfo;
using utility::returnIn;
@@ -186,60 +192,7 @@
}
//////////////////////////////////////////////////////////////////////////////
-//////////////////////////// {set,get}MasterVolume ///////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-class MasterVolumeTest : public AudioPrimaryHidlTest {
-protected:
- void testSetGetConsistency(float volume, Result expectedSetResult, float expectedGetVolume) {
- SCOPED_TRACE("Test set/get consistency for " + to_string(volume));
- auto ret = device->setMasterVolume(volume);
- ASSERT_TRUE(ret.isOk());
- ASSERT_EQ(expectedSetResult, ret);
-
- float observedVolume;
- ASSERT_OK(device->getMasterVolume(returnIn(res, observedVolume)));
- ASSERT_OK(res);
-
- // Check that `get` returned the expected value
- EXPECT_EQ(expectedGetVolume, observedVolume);
- }
-};
-
-TEST_F(MasterVolumeTest, MasterVolumeTest) {
- doc::test("Test the master volume if supported");
- {
- SCOPED_TRACE("Check for master volume support");
- auto ret = device->setMasterVolume(1);
- ASSERT_TRUE(ret.isOk());
- if (ret == Result::NOT_SUPPORTED) {
- doc::partialTest("Master volume is not supported");
- return;
- }
- }
- // NOTE: this code has never been tested on a platform supporting MasterVolume
- float lastValidVolumeSet;
- using Volumes = float[];
- SCOPED_TRACE("As set/get master volume are supported...");
- {
- SCOPED_TRACE("...test them with valid values");
- for (float validVolume : Volumes{0, 0.5, 1}) {
- ASSERT_NO_FATAL_FAILURE(testSetGetConsistency(validVolume, Result::OK, validVolume));
- lastValidVolumeSet = validVolume;
- }
- }{
- SCOPED_TRACE("...test them with tricky values");
- for (float outOfBoundVolume :Volumes{-0.1, 1.1, NAN, INFINITY, -INFINITY,
- 1 + std::numeric_limits<float>::epsilon()}) {
- ASSERT_NO_FATAL_FAILURE(testSetGetConsistency(outOfBoundVolume,
- Result::INVALID_ARGUMENTS,
- lastValidVolumeSet));
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////
-////////////////////////// {set,get}{Master,Mic}Mute /////////////////////////
+///////////////////// {set,get}{Master,Mic}{Mute,Volume} /////////////////////
//////////////////////////////////////////////////////////////////////////////
template <class Property>
@@ -249,14 +202,16 @@
/** Test a property getter and setter. */
template <class Getter, class Setter>
void testAccessors(const string& propertyName, const vector<Property>& valuesToTest,
- Setter setter, Getter getter) {
+ Setter setter, Getter getter,
+ const vector<Property>& invalidValues = {}) {
Property initialValue; // Save initial value to restore it at the end of the test
ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
ASSERT_OK(res);
for (Property setValue : valuesToTest) {
- SCOPED_TRACE("Test " + propertyName + " getter and setter for " + testing::PrintToString(setValue));
+ SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
+ testing::PrintToString(setValue));
ASSERT_OK((device.get()->*setter)(setValue));
Property getValue;
// Make sure the getter returns the same value just set
@@ -265,13 +220,20 @@
EXPECT_EQ(setValue, getValue);
}
+ for (Property invalidValue : invalidValues) {
+ SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " +
+ testing::PrintToString(invalidValue));
+ EXPECT_RESULT(Result::INVALID_ARGUMENTS, (device.get()->*setter)(invalidValue));
+ }
+
ASSERT_OK((device.get()->*setter)(initialValue)); // restore initial value
}
/** Test the getter and setter of an optional feature. */
template <class Getter, class Setter>
void testOptionalAccessors(const string& propertyName, const vector<Property>& valuesToTest,
- Setter setter, Getter getter) {
+ Setter setter, Getter getter,
+ const vector<Property>& invalidValues = {}) {
doc::test("Test the optional " + propertyName + " getters and setter");
{
SCOPED_TRACE("Test feature support by calling the getter");
@@ -284,7 +246,7 @@
ASSERT_OK(res); // If it is supported it must succeed
}
// The feature is supported, test it
- testAccessors(propertyName, valuesToTest, setter, getter);
+ testAccessors(propertyName, valuesToTest, setter, getter, invalidValues);
}
};
@@ -303,6 +265,39 @@
// TODO: check that the master volume is really muted
}
+using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>;
+TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
+ doc::test("Test the master volume if supported");
+ testOptionalAccessors("master volume", {0, 0.5, 1},
+ &IDevice::setMasterVolume, &IDevice::getMasterVolume,
+ {-0.1, 1.1, NAN, INFINITY, -INFINITY,
+ 1 + std::numeric_limits<float>::epsilon()});
+ // TODO: check that the master volume is really changed
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////// AudioPatches ////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest {
+protected:
+ bool areAudioPatchesSupported() {
+ auto result = device->supportsAudioPatches();
+ EXPECT_TRUE(result.isOk());
+ return result;
+ }
+};
+
+TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {
+ doc::test("Test if audio patches are supported");
+ if (!areAudioPatchesSupported()) {
+ doc::partialTest("Audio patches are not supported");
+ return;
+ }
+ // TODO: test audio patches
+}
+
+
//////////////////////////////////////////////////////////////////////////////
//////////////// Required and recommended audio format support ///////////////
// From: https://source.android.com/compatibility/android-cdd.html#5_4_audio_recording
@@ -310,7 +305,7 @@
/////////// TODO: move to the beginning of the file for easier update ////////
//////////////////////////////////////////////////////////////////////////////
-class AudioConfigPrimaryTest : public AudioPrimaryHidlTest {
+class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest {
public:
// Cache result ?
static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() {
@@ -369,6 +364,20 @@
}
};
+/** Generate a test name based on an audio config.
+ *
+ * As the only parameter changing are channel mask and sample rate,
+ * only print those ones in the test name.
+ */
+static string generateTestName(const testing::TestParamInfo<AudioConfig>& info) {
+ const AudioConfig& config = info.param;
+ return to_string(info.index) + "__" + to_string(config.sampleRateHz)+ "_" +
+ // "MONO" is more clear than "FRONT_LEFT"
+ ((config.channelMask == AudioChannelMask::OUT_MONO ||
+ config.channelMask == AudioChannelMask::IN_MONO) ?
+ "MONO" : toString(config.channelMask));
+}
+
//////////////////////////////////////////////////////////////////////////////
///////////////////////////// getInputBufferSize /////////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -406,10 +415,12 @@
}
INSTANTIATE_TEST_CASE_P(
RequiredInputBufferSize, RequiredInputBufferSizeTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
+ &generateTestName);
INSTANTIATE_TEST_CASE_P(
SupportedInputBufferSize, RequiredInputBufferSizeTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
+ &generateTestName);
// Test that the recommended capture config are supported or lead to a INVALID_ARGUMENTS return
class OptionalInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {};
@@ -419,7 +430,8 @@
}
INSTANTIATE_TEST_CASE_P(
RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
+ &generateTestName);
//////////////////////////////////////////////////////////////////////////////
/////////////////////////////// setScreenState ///////////////////////////////
@@ -453,8 +465,8 @@
//////////////////////////////// debugDebug //////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
-TEST_F(AudioPrimaryHidlTest, debugDump) {
- doc::test("Check that the hal can dump its state without error");
+template <class DebugDump>
+static void testDebugDump(DebugDump debugDump) {
FILE* file = tmpfile();
ASSERT_NE(nullptr, file) << errno;
@@ -465,28 +477,23 @@
hidl_handle handle;
handle.setTo(nativeHandle, true /*take ownership*/);
- auto ret = device->debugDump(handle);
- ASSERT_TRUE(ret.isOk());
-
- // FIXME: debugDump does not return a Result.
+ // TODO: debugDump does not return a Result.
// This mean that the hal can not report that it not implementing the function.
- // As the default hal does not implement debugDump, the function can not be tested.
- /*
- res = ret;
- if (res == Result::NOT_SUPPORTED) {
- doc::partialTest("debugDump is not implemented");
- return;
- }
- ASSERT_OK(res);
- rewind(file);
+ ASSERT_OK(debugDump(handle));
+
+ rewind(file); // can not fail
// Check that at least one bit was written by the hal
char buff;
- ASSERT_EQ(1, fread(&buff, sizeof(buff), 1, file));
- */
+ ASSERT_EQ(size_t{1}, fread(&buff, sizeof(buff), 1, file));
EXPECT_EQ(0, fclose(file)) << errno;
}
+TEST_F(AudioPrimaryHidlTest, debugDump) {
+ doc::test("Check that the hal can dump its state without error");
+ testDebugDump([this](const auto& handle){ return device->debugDump(handle); });
+}
+
//////////////////////////////////////////////////////////////////////////////
////////////////////////// open{Output,Input}Stream //////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -526,6 +533,10 @@
open = true;
}
+ Return<Result> closeStream() {
+ open = false;
+ return stream->close();
+ }
private:
void TearDown() override {
if (open) {
@@ -536,6 +547,7 @@
protected:
AudioConfig audioConfig;
+ DeviceAddress address = {};
sp<Stream> stream;
bool open = false;
};
@@ -545,12 +557,11 @@
class OutputStreamTest : public OpenStreamTest<IStreamOut> {
virtual void SetUp() override {
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
-
+ address.device = AudioDevice::OUT_DEFAULT;
const AudioConfig& config = GetParam();
- DeviceAddress deviceAddr{}; // Ignored by primary hal
AudioOutputFlag flags = AudioOutputFlag::NONE; // TODO: test all flag combination
testOpen([&](AudioIoHandle handle, AudioConfig config, auto cb)
- { return device->openOutputStream(handle, deviceAddr, config, flags, cb); },
+ { return device->openOutputStream(handle, address, config, flags, cb); },
config);
}
};
@@ -560,14 +571,17 @@
}
INSTANTIATE_TEST_CASE_P(
RequiredOutputStreamConfigSupport, OutputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()),
+ &generateTestName);
INSTANTIATE_TEST_CASE_P(
SupportedOutputStreamConfig, OutputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()),
+ &generateTestName);
INSTANTIATE_TEST_CASE_P(
RecommendedOutputStreamConfigSupport, OutputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()),
+ &generateTestName);
////////////////////////////// openInputStream //////////////////////////////
@@ -575,13 +589,12 @@
virtual void SetUp() override {
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
-
+ address.device = AudioDevice::IN_DEFAULT;
const AudioConfig& config = GetParam();
- DeviceAddress deviceAddr{}; // TODO: test all devices
AudioInputFlag flags = AudioInputFlag::NONE; // TODO: test all flag combination
AudioSource source = AudioSource::DEFAULT; // TODO: test all flag combination
testOpen([&](AudioIoHandle handle, AudioConfig config, auto cb)
- { return device->openInputStream(handle, deviceAddr, config, flags, source, cb); },
+ { return device->openInputStream(handle, address, config, flags, source, cb); },
config);
}
};
@@ -592,14 +605,17 @@
}
INSTANTIATE_TEST_CASE_P(
RequiredInputStreamConfigSupport, InputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
+ &generateTestName);
INSTANTIATE_TEST_CASE_P(
SupportedInputStreamConfig, InputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
+ &generateTestName);
INSTANTIATE_TEST_CASE_P(
RecommendedInputStreamConfigSupport, InputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
+ &generateTestName);
//////////////////////////////////////////////////////////////////////////////
////////////////////////////// IStream getters ///////////////////////////////
@@ -616,8 +632,40 @@
return ret;
}
+/* Could not find a way to write a test for two parametrized class fixure
+ * thus use this macro do duplicate tests for Input and Output stream */
+#define TEST_IO_STREAM(test_name, documentation, code) \
+ TEST_P(InputStreamTest, test_name) { \
+ doc::test(documentation); \
+ code; \
+ } \
+ TEST_P(OutputStreamTest, test_name) { \
+ doc::test(documentation); \
+ code; \
+ }
+
+TEST_IO_STREAM(GetFrameCount, "Check that the stream frame count == the one it was opened with",
+ ASSERT_EQ(audioConfig.frameCount, extract(stream->getFrameCount())))
+
+TEST_IO_STREAM(GetSampleRate, "Check that the stream sample rate == the one it was opened with",
+ ASSERT_EQ(audioConfig.sampleRateHz, extract(stream->getSampleRate())))
+
+TEST_IO_STREAM(GetChannelMask, "Check that the stream channel mask == the one it was opened with",
+ ASSERT_EQ(audioConfig.channelMask, extract(stream->getChannelMask())))
+
+TEST_IO_STREAM(GetFormat, "Check that the stream format == the one it was opened with",
+ ASSERT_EQ(audioConfig.format, extract(stream->getFormat())))
+
+// TODO: for now only check that the framesize is not incoherent
+TEST_IO_STREAM(GetFrameSize, "Check that the stream frame size == the one it was opened with",
+ ASSERT_GT(extract(stream->getFrameSize()), 0U))
+
+TEST_IO_STREAM(GetBufferSize, "Check that the stream buffer size== the one it was opened with",
+ ASSERT_GE(extract(stream->getBufferSize()), \
+ extract(stream->getFrameSize())));
+
template <class Property, class CapabilityGetter, class Getter, class Setter>
-static void testCapabilityGetter(const string& name,IStream* stream, Property currentValue,
+static void testCapabilityGetter(const string& name, IStream* stream, Property currentValue,
CapabilityGetter capablityGetter, Getter getter, Setter setter) {
hidl_vec<Property> capabilities;
ASSERT_OK((stream->*capablityGetter)(returnIn(capabilities)));
@@ -640,6 +688,48 @@
}
}
+TEST_IO_STREAM(SupportedSampleRate, "Check that the stream sample rate is declared as supported",
+ testCapabilityGetter("getSupportedSampleRate", stream.get(), \
+ extract(stream->getSampleRate()), \
+ &IStream::getSupportedSampleRates, \
+ &IStream::getSampleRate, &IStream::setSampleRate))
+
+TEST_IO_STREAM(SupportedChannelMask, "Check that the stream channel mask is declared as supported",
+ testCapabilityGetter("getSupportedChannelMask", stream.get(), \
+ extract(stream->getChannelMask()), \
+ &IStream::getSupportedChannelMasks, \
+ &IStream::getChannelMask, &IStream::setChannelMask))
+
+TEST_IO_STREAM(SupportedFormat, "Check that the stream format is declared as supported",
+ testCapabilityGetter("getSupportedFormat", stream.get(), \
+ extract(stream->getFormat()), \
+ &IStream::getSupportedFormats, \
+ &IStream::getFormat, &IStream::setFormat))
+
+static void testGetDevice(IStream* stream, AudioDevice expectedDevice) {
+ auto ret = stream->getDevice();
+ ASSERT_TRUE(ret.isOk());
+ AudioDevice device = ret;
+ ASSERT_EQ(expectedDevice, device);
+}
+
+TEST_IO_STREAM(GetDevice, "Check that the stream device == the one it was opened with",
+ areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported") : \
+ testGetDevice(stream.get(), address.device))
+
+static void testSetDevice(IStream* stream, const DeviceAddress& address) {
+ DeviceAddress otherAddress = address;
+ otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ?
+ AudioDevice::OUT_SPEAKER : AudioDevice::IN_BUILTIN_MIC;
+ EXPECT_OK(stream->setDevice(otherAddress));
+
+ ASSERT_OK(stream->setDevice(address)); // Go back to the original value
+}
+
+TEST_IO_STREAM(SetDevice, "Check that the stream can be rerouted to SPEAKER or BUILTIN_MIC",
+ areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported") : \
+ testSetDevice(stream.get(), address))
+
static void testGetAudioProperties(IStream* stream, AudioConfig expectedConfig) {
uint32_t sampleRateHz;
AudioChannelMask mask;
@@ -653,90 +743,191 @@
EXPECT_EQ(expectedConfig.format, format);
}
-static void testAccessors(IStream* stream, AudioConfig audioConfig) {
- doc::test("Test IStream getters and setters that can be called in the stop state");
+TEST_IO_STREAM(GetAudioProperties,
+ "Check that the stream audio properties == the ones it was opened with",
+ testGetAudioProperties(stream.get(), audioConfig))
- auto frameCount = extract(stream->getFrameCount());
- ASSERT_EQ(audioConfig.frameCount, frameCount);
+static void testConnectedState(IStream* stream) {
+ DeviceAddress address = {};
+ using AD = AudioDevice;
+ for (auto device : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
+ address.device = device;
- auto sampleRate = extract(stream->getSampleRate());
- // FIXME: the qcom hal it does not currently negotiate the sampleRate
- ASSERT_EQ(audioConfig.sampleRateHz, sampleRate);
-
- auto channelMask = extract(stream->getChannelMask());
- // FIXME: the qcom hal it does not currently negotiate the channelMask
- ASSERT_EQ(audioConfig.channelMask, channelMask);
-
- auto frameSize = extract(stream->getFrameSize());
- ASSERT_GE(frameSize, 0U);
-
- auto bufferSize = extract(stream->getBufferSize());
- ASSERT_GE(bufferSize, frameSize);
-
- testCapabilityGetter("getSupportedsampleRate", stream, sampleRate,
- &IStream::getSupportedSampleRates,
- &IStream::getSampleRate, &IStream::setSampleRate);
-
- testCapabilityGetter("getSupportedChannelMask", stream, channelMask,
- &IStream::getSupportedChannelMasks,
- &IStream::getChannelMask, &IStream::setChannelMask);
-
- AudioFormat format = extract(stream->getFormat());
- ASSERT_EQ(audioConfig.format, format);
-
- testCapabilityGetter("getSupportedFormats", stream, format,
- &IStream::getSupportedFormats, &IStream::getFormat, &IStream::setFormat);
-
- testGetAudioProperties(stream, audioConfig);
-
- auto ret = stream->getDevice();
- ASSERT_TRUE(ret.isOk());
- AudioDevice device = ret;
- ASSERT_EQ(AudioDevice::OUT_DEFAULT, device);
-}
-
-TEST_P(InputStreamTest, GettersTest) {
- testAccessors(stream.get(), audioConfig);
-}
-TEST_P(OutputStreamTest, GettersTest) {
- testAccessors(stream.get(), audioConfig);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//////////////////////////////// AudioPatches ////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-
-TEST_F(AudioPrimaryHidlTest, AudioPatches) {
- doc::test("Test if audio patches are supported");
- auto result = device->supportsAudioPatches();
- ASSERT_TRUE(result.isOk());
- bool supportsAudioPatch = result;
- if (!supportsAudioPatch) {
- doc::partialTest("Audio patches are not supported");
- return;
+ ASSERT_OK(stream->setConnectedState(address, true));
+ ASSERT_OK(stream->setConnectedState(address, false));
}
- // TODO: test audio patches
+}
+TEST_IO_STREAM(SetConnectedState,
+ "Check that the stream can be notified of device connection and deconnection",
+ testConnectedState(stream.get()))
+
+
+static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED};
+TEST_IO_STREAM(SetHwAvSync, "Try to set hardware sync to an invalid value",
+ ASSERT_RESULT(invalidArgsOrNotSupported, stream->setHwAvSync(666)))
+
+static void checkGetParameter(IStream* stream, hidl_vec<hidl_string> keys,
+ vector<Result> expectedResults) {
+ hidl_vec<ParameterValue> parameters;
+ Result res;
+ ASSERT_OK(stream->getParameters(keys, returnIn(res, parameters)));
+ ASSERT_RESULT(expectedResults, res);
+ if (res == Result::OK) {
+ ASSERT_EQ(0U, parameters.size());
+ }
+}
+
+/* Get/Set parameter is intended to be an opaque channel between vendors app and their HALs.
+ * Thus can not be meaningfully tested.
+ * TODO: Doc missing. Should asking for an empty set of params raise an error ?
+ */
+TEST_IO_STREAM(getEmptySetParameter, "Retrieve the values of an empty set",
+ checkGetParameter(stream.get(), {} /* keys */,
+ {Result::OK, Result::INVALID_ARGUMENTS}))
+
+
+TEST_IO_STREAM(getNonExistingParameter, "Retrieve the values of an non existing parameter",
+ checkGetParameter(stream.get(), {"Non existing key"} /* keys */,
+ {Result::INVALID_ARGUMENTS}))
+
+static vector<Result> okOrNotSupported = {Result::OK, Result::INVALID_ARGUMENTS};
+TEST_IO_STREAM(setEmptySetParameter, "Set the values of an empty set of parameters",
+ ASSERT_RESULT(okOrNotSupported, stream->setParameters({})))
+
+TEST_IO_STREAM(setNonExistingParameter, "Set the values of an non existing parameter",
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS,
+ stream->setParameters({{"non existing key", "0"}})))
+
+TEST_IO_STREAM(DebugDump,
+ "Check that a stream can dump its state without error",
+ testDebugDump([this](const auto& handle){ return stream->debugDump(handle); }))
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////////// addRemoveEffect ///////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_IO_STREAM(AddNonExistingEffect, "Adding a non existing effect should fail",
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, stream->addEffect(666)))
+TEST_IO_STREAM(RemoveNonExistingEffect, "Removing a non existing effect should fail",
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, stream->removeEffect(666)))
+
+//TODO: positive tests
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Control ////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_IO_STREAM(standby, "Make sure the stream can be put in stanby",
+ ASSERT_OK(stream->standby())) // can not fail
+
+static vector<Result> invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUPPORTED};
+
+TEST_IO_STREAM(startNoMmap, "Starting a mmaped stream before mapping it should fail",
+ ASSERT_RESULT(invalidStateOrNotSupported, stream->start()))
+
+TEST_IO_STREAM(stopNoMmap, "Stopping a mmaped stream before mapping it should fail",
+ ASSERT_RESULT(invalidStateOrNotSupported, stream->stop()))
+
+TEST_IO_STREAM(getMmapPositionNoMmap, "Get a stream Mmap position before mapping it should fail",
+ ASSERT_RESULT(invalidStateOrNotSupported, stream->stop()))
+
+TEST_IO_STREAM(close, "Make sure a stream can be closed", ASSERT_OK(closeStream()))
+TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice",
+ ASSERT_OK(closeStream()); \
+ ASSERT_RESULT(Result::INVALID_STATE, closeStream()))
+
+static void testCreateTooBigMmapBuffer(IStream* stream) {
+ MmapBufferInfo info;
+ Result res;
+ // Assume that int max is a value too big to be allocated
+ // This is true currently with a 32bit media server, but might not when it will run in 64 bit
+ auto minSizeFrames = std::numeric_limits<int32_t>::max();
+ ASSERT_OK(stream->createMmapBuffer(minSizeFrames, returnIn(res, info)));
+ ASSERT_RESULT(invalidArgsOrNotSupported, res);
+}
+
+TEST_IO_STREAM(CreateTooBigMmapBuffer, "Create mmap buffer too big should fail",
+ testCreateTooBigMmapBuffer(stream.get()))
+
+
+static void testGetMmapPositionOfNonMmapedStream(IStream* stream) {
+ Result res;
+ MmapPosition position;
+ ASSERT_OK(stream->getMmapPosition(returnIn(res, position)));
+ ASSERT_RESULT(invalidArgsOrNotSupported, res);
+}
+
+TEST_IO_STREAM(GetMmapPositionOfNonMmapedStream,
+ "Retrieving the mmap position of a non mmaped stream should fail",
+ testGetMmapPositionOfNonMmapedStream(stream.get()))
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////////////////// StreamIn ///////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_P(InputStreamTest, GetAudioSource) {
+ doc::test("Retrieving the audio source of an input stream should always succeed");
+ AudioSource source;
+ ASSERT_OK(stream->getAudioSource(returnIn(res, source)));
+ ASSERT_OK(res);
+ ASSERT_EQ(AudioSource::DEFAULT, source);
+}
+
+static void testUnitaryGain(std::function<Return<Result> (float)> setGain) {
+ for (float value : {0.0, 0.01, 0.5, 0.09, 1.0}) {
+ SCOPED_TRACE("value=" + to_string(value));
+ ASSERT_OK(setGain(value));
+ }
+ for (float value : (float[]){-INFINITY,-1.0, -0.0,
+ 1.0 + std::numeric_limits<float>::epsilon(), 2.0, INFINITY,
+ NAN}) {
+ SCOPED_TRACE("value=" + to_string(value));
+ // FIXME: NAN should never be accepted
+ // FIXME: Missing api doc. What should the impl do if the volume is outside [0,1] ?
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, setGain(value));
+ }
+}
+
+TEST_P(InputStreamTest, SetGain) {
+ doc::test("The gain of an input stream should only be set between [0,1]");
+ testUnitaryGain([this](float volume) { return stream->setGain(volume); });
+}
+
+static void testPrepareForReading(IStreamIn* stream, uint32_t frameSize, uint32_t framesCount) {
+ Result res;
+ // Ignore output parameters as the call should fail
+ ASSERT_OK(stream->prepareForReading(frameSize, framesCount,
+ [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
+ EXPECT_RESULT(invalidArgsOrNotSupported, res);
+}
+
+TEST_P(InputStreamTest, PrepareForReadingWithHugeBuffer) {
+ doc::test("Preparing a stream for reading with a 2^32 sized buffer should fail");
+ testPrepareForReading(stream.get(), 1, std::numeric_limits<uint32_t>::max());
+}
+
+TEST_P(InputStreamTest, PrepareForReadingCheckOverflow) {
+ doc::test("Preparing a stream for reading with a overflowing sized buffer should fail");
+ auto uintMax = std::numeric_limits<uint32_t>::max();
+ testPrepareForReading(stream.get(), uintMax, uintMax);
+}
+
+TEST_P(InputStreamTest, getCapturePosition) {
+ doc::test("The capture position of a non prepared stream should not be retrievable");
+ uint64_t frames;
+ uint64_t time;
+ ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, time)));
+ ASSERT_RESULT(invalidStateOrNotSupported, res);
}
//////////////////////////////////////////////////////////////////////////////
/////////////////////////////// PrimaryDevice ////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
+
TEST_F(AudioPrimaryHidlTest, setVoiceVolume) {
doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]");
- for (float volume : {0.0, 0.01, 0.5, 0.09, 1.0}) {
- SCOPED_TRACE("volume=" + to_string(volume));
- ASSERT_OK(device->setVoiceVolume(volume));
- }
- for (float volume : (float[]){-INFINITY,-1.0, -0.0,
- 1.0 + std::numeric_limits<float>::epsilon(), 2.0, INFINITY,
- NAN}) {
- SCOPED_TRACE("volume=" + to_string(volume));
- // FIXME: NAN should never be accepted
- // FIXME: Missing api doc. What should the impl do if the volume is outside [0,1] ?
- ASSERT_INVALID_ARGUMENTS(device->setVoiceVolume(volume));
- }
+ testUnitaryGain([this](float volume) { return device->setVoiceVolume(volume); });
}
TEST_F(AudioPrimaryHidlTest, setMode) {
@@ -749,7 +940,7 @@
}
// FIXME: Missing api doc. What should the impl do if the mode is invalid ?
- ASSERT_INVALID_ARGUMENTS(device->setMode(AudioMode::INVALID));
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode::INVALID));
}
diff --git a/audio/2.0/vts/functional/utility/AssertOk.h b/audio/2.0/vts/functional/utility/AssertOk.h
index 16488ae..39c9a1d 100644
--- a/audio/2.0/vts/functional/utility/AssertOk.h
+++ b/audio/2.0/vts/functional/utility/AssertOk.h
@@ -13,38 +13,59 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+#include <vector>
+#include <algorithm>
+
#include <hidl/Status.h>
namespace detail {
-inline void assertOk(::android::hardware::Return<void> ret) {
+// This is a detail namespace, thus it is OK to import a class as nobody else is allowed to use it
+using ::android::hardware::Return;
+using ::android::hardware::audio::V2_0::Result;
+
+inline void assertResult(Result expected, Result result) {
+ ASSERT_EQ(expected, result);
+}
+
+inline void assertResult(Result expected, Return<Result> ret) {
+ ASSERT_TRUE(ret.isOk());
+ Result result = ret;
+ assertResult(expected, result);
+}
+
+inline void assertResult(std::vector<Result> expected, Result result) {
+ if (std::find(expected.begin(), expected.end(), result) != expected.end()) {
+ return; // result is in expected
+ }
+ FAIL() << "Expected result " << ::testing::PrintToString(result)
+ << " to be one of " << ::testing::PrintToString(expected);
+}
+
+inline void assertResult(std::vector<Result> expected, Return<Result> ret) {
+ ASSERT_TRUE(ret.isOk());
+ Result result = ret;
+ assertResult(expected, result);
+}
+
+inline void assertOk(Return<void> ret) {
ASSERT_TRUE(ret.isOk());
}
-inline void assertOk(::android::hardware::audio::V2_0::Result result) {
- ASSERT_EQ(decltype(result)::OK, result);
+inline void assertOk(Result result) {
+ assertResult(Result::OK, result);
}
-inline void assertOk(::android::hardware::Return<::android::hardware::audio::V2_0::Result> ret) {
- ASSERT_TRUE(ret.isOk());
- ::android::hardware::audio::V2_0::Result result = ret;
- assertOk(result);
+inline void assertOk(Return<Result> ret) {
+ assertResult(Result::OK, std::move(ret));
}
-inline void assertInvalidArguments(::android::hardware::audio::V2_0::Result result) {
- ASSERT_EQ(decltype(result)::INVALID_ARGUMENTS, result);
-}
-
-inline void assertInvalidArguments(
- ::android::hardware::Return<::android::hardware::audio::V2_0::Result> ret) {
- ASSERT_TRUE(ret.isOk());
- ::android::hardware::audio::V2_0::Result result = ret;
- assertInvalidArguments(result);
-}
}
// Test anything provided is and contains only OK
#define ASSERT_OK(ret) ASSERT_NO_FATAL_FAILURE(detail::assertOk(ret))
#define EXPECT_OK(ret) EXPECT_NO_FATAL_FAILURE(detail::assertOk(ret))
-#define ASSERT_INVALID_ARGUMENTS(ret) ASSERT_NO_FATAL_FAILURE(detail::assertInvalidArguments(ret))
+#define ASSERT_RESULT(expected, ret) ASSERT_NO_FATAL_FAILURE(detail::assertResult(expected, ret))
+#define EXPECT_RESULT(expected, ret) ASSERT_NO_FATAL_FAILURE(detail::assertResult(expected, ret))
diff --git a/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h b/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h
index 8dfcb29..025cd1c 100644
--- a/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h
+++ b/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h
@@ -13,23 +13,50 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <type_traits>
-// Use HIDL generated toString methods to pretty print gtest errors
+/** @file Use HIDL generated toString methods to pretty print gtest errors */
+
+namespace detail {
+
+// Print the value of an enum as hex
+template <class Enum>
+inline void printUnderlyingValue(Enum value, ::std::ostream* os) {
+ *os << std::hex << " (0x" << static_cast<std::underlying_type_t<Enum>>(value) << ")";
+}
+
+} // namespace detail
+
namespace android {
namespace hardware {
namespace audio {
namespace V2_0 {
+
inline void PrintTo(const Result& result, ::std::ostream* os) {
*os << toString(result);
+ detail::printUnderlyingValue(result, os);
}
+
} // namespace V2_0
namespace common {
namespace V2_0 {
+
inline void PrintTo(const AudioConfig& config, ::std::ostream* os) {
*os << toString(config);
}
+
+inline void PrintTo(const AudioDevice& device, ::std::ostream* os) {
+ *os << toString(device);
+ detail::printUnderlyingValue(device, os);
+}
+
+inline void PrintTo(const AudioChannelMask& channelMask, ::std::ostream* os) {
+ *os << toString(channelMask);
+ detail::printUnderlyingValue(channelMask, os);
+}
+
} // namespace V2_0
} // namespace common
-}
-}
-}
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/audio/effect/2.0/IEffect.hal b/audio/effect/2.0/IEffect.hal
index 9e10117..d254e8c 100644
--- a/audio/effect/2.0/IEffect.hal
+++ b/audio/effect/2.0/IEffect.hal
@@ -59,7 +59,7 @@
*
* @return retval operation completion status.
*/
- @callflow(next={"process"})
+ @callflow(next={"prepareForProcessing"})
enable() generates (Result retval);
/*
@@ -67,7 +67,7 @@
*
* @return retval operation completion status.
*/
- @exit
+ @callflow(next={"close"})
disable() generates (Result retval);
/*
@@ -75,6 +75,9 @@
* effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its
* descriptor to receive this command when the device changes.
*
+ * Note: this method is only supported for effects inserted into
+ * the output chain.
+ *
* @param device output device specification.
* @return retval operation completion status.
*/
@@ -145,6 +148,9 @@
* implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to
* receive this command when the device changes.
*
+ * Note: this method is only supported for effects inserted into
+ * the input chain.
+ *
* @param device input device specification.
* @return retval operation completion status.
*/
@@ -209,6 +215,9 @@
* Set the audio source the capture path is configured for (Camcorder, voice
* recognition...).
*
+ * Note: this method is only supported for effects inserted into
+ * the input chain.
+ *
* @param source source descriptor.
* @return retval operation completion status.
*/
@@ -258,6 +267,7 @@
* the queue.
* @return statusMQ a message queue used for passing status from the effect.
*/
+ @callflow(next={"setProcessBuffers"})
prepareForProcessing() generates (Result retval, fmq_sync<Result> statusMQ);
/*
@@ -275,6 +285,7 @@
* INVALID_ARGUMENTS if there was a problem with mapping
* any of the buffers.
*/
+ @callflow(next={"*"})
setProcessBuffers(AudioBuffer inBuffer, AudioBuffer outBuffer) generates (
Result retval);
@@ -423,5 +434,6 @@
* @return retval OK in case the success.
* INVALID_STATE if the effect was already closed.
*/
+ @exit
close() generates (Result retval);
};
diff --git a/audio/effect/2.0/IEqualizerEffect.hal b/audio/effect/2.0/IEqualizerEffect.hal
index afcc4b6..b8fa177 100644
--- a/audio/effect/2.0/IEqualizerEffect.hal
+++ b/audio/effect/2.0/IEqualizerEffect.hal
@@ -29,34 +29,36 @@
* Returns the minimum and maximum band levels supported.
*/
getLevelRange()
- generates (Result retval, uint16_t minLevel, uint16_t maxLevel);
+ generates (Result retval, int16_t minLevel, int16_t maxLevel);
/*
* Sets the gain for the given equalizer band.
*/
- setBandLevel(uint16_t band, uint16_t level) generates (Result retval);
+ setBandLevel(uint16_t band, int16_t level) generates (Result retval);
/*
* Gets the gain for the given equalizer band.
*/
- getBandLevel(uint16_t band) generates (Result retval, uint16_t level);
+ getBandLevel(uint16_t band) generates (Result retval, int16_t level);
/*
- * Gets the center frequency of the given band.
+ * Gets the center frequency of the given band, in milliHertz.
*/
getBandCenterFrequency(uint16_t band)
- generates (Result retval, uint32_t centerFreq);
+ generates (Result retval, uint32_t centerFreqmHz);
/*
- * Gets the frequency range of the given frequency band.
+ * Gets the frequency range of the given frequency band, in milliHertz.
*/
getBandFrequencyRange(uint16_t band)
- generates (Result retval, uint32_t minFreqHz, uint32_t maxFreqHz);
+ generates (Result retval, uint32_t minFreqmHz, uint32_t maxFreqmHz);
/*
- * Gets the band that has the most effect on the given frequency.
+ * Gets the band that has the most effect on the given frequency
+ * in milliHertz.
*/
- getBandForFrequency(uint32_t freq) generates (Result retval, uint16_t band);
+ getBandForFrequency(uint32_t freqmHz)
+ generates (Result retval, uint16_t band);
/*
* Gets the names of all presets the equalizer supports.
@@ -76,7 +78,7 @@
struct AllProperties {
uint16_t curPreset;
- vec<uint16_t> bandLevels;
+ vec<int16_t> bandLevels;
};
/*
diff --git a/audio/effect/2.0/default/Effect.cpp b/audio/effect/2.0/default/Effect.cpp
index 83c8e09..6704239 100644
--- a/audio/effect/2.0/default/Effect.cpp
+++ b/audio/effect/2.0/default/Effect.cpp
@@ -188,6 +188,8 @@
// static
void Effect::effectBufferConfigFromHal(
const buffer_config_t& halConfig, EffectBufferConfig* config) {
+ config->buffer.id = 0;
+ config->buffer.frameCount = 0;
config->samplingRateHz = halConfig.samplingRate;
config->channels = AudioChannelMask(halConfig.channels);
config->format = AudioFormat(halConfig.format);
@@ -282,7 +284,7 @@
void Effect::getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb) {
uint32_t halResultSize = sizeof(effect_config_t);
- effect_config_t halConfig;
+ effect_config_t halConfig{};
status_t status = (*mHandle)->command(
mHandle, commandCode, 0, NULL, &halResultSize, &halConfig);
EffectConfig config;
@@ -309,15 +311,16 @@
Result Effect::getParameterImpl(
uint32_t paramSize,
const void* paramData,
- uint32_t valueSize,
+ uint32_t requestValueSize,
+ uint32_t replyValueSize,
GetParameterSuccessCallback onSuccess) {
// As it is unknown what method HAL uses for copying the provided parameter data,
// it is safer to make sure that input and output buffers do not overlap.
std::vector<uint8_t> halCmdBuffer =
- parameterToHal(paramSize, paramData, valueSize, nullptr);
+ parameterToHal(paramSize, paramData, requestValueSize, nullptr);
const void *valueData = nullptr;
std::vector<uint8_t> halParamBuffer =
- parameterToHal(paramSize, paramData, valueSize, &valueData);
+ parameterToHal(paramSize, paramData, replyValueSize, &valueData);
uint32_t halParamBufferSize = halParamBuffer.size();
return sendCommandReturningStatusAndData(
diff --git a/audio/effect/2.0/default/Effect.h b/audio/effect/2.0/default/Effect.h
index 13faec4..0918cd8 100644
--- a/audio/effect/2.0/default/Effect.h
+++ b/audio/effect/2.0/default/Effect.h
@@ -60,6 +60,8 @@
struct Effect : public IEffect {
typedef MessageQueue<Result, kSynchronizedReadWrite> StatusMQ;
+ using GetParameterSuccessCallback =
+ std::function<void(uint32_t valueSize, const void* valueData)>;
explicit Effect(effect_handle_t handle);
@@ -163,6 +165,22 @@
return setParameterImpl(sizeof(params), params, sizeof(T), ¶mValue);
}
+ Result getParameterImpl(
+ uint32_t paramSize,
+ const void* paramData,
+ uint32_t valueSize,
+ GetParameterSuccessCallback onSuccess) {
+ return getParameterImpl(paramSize, paramData, valueSize, valueSize, onSuccess);
+ }
+ Result getParameterImpl(
+ uint32_t paramSize,
+ const void* paramData,
+ uint32_t requestValueSize,
+ uint32_t replyValueSize,
+ GetParameterSuccessCallback onSuccess);
+ Result setParameterImpl(
+ uint32_t paramSize, const void* paramData, uint32_t valueSize, const void* valueData);
+
private:
friend struct VirtualizerEffect; // for getParameterImpl
friend struct VisualizerEffect; // to allow executing commands
@@ -170,8 +188,6 @@
using CommandSuccessCallback = std::function<void()>;
using GetConfigCallback = std::function<void(Result retval, const EffectConfig& config)>;
using GetCurrentConfigSuccessCallback = std::function<void(void* configData)>;
- using GetParameterSuccessCallback =
- std::function<void(uint32_t valueSize, const void* valueData)>;
using GetSupportedConfigsSuccessCallback =
std::function<void(uint32_t supportedConfigs, void* configsData)>;
@@ -220,11 +236,6 @@
void getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb);
Result getCurrentConfigImpl(
uint32_t featureId, uint32_t configSize, GetCurrentConfigSuccessCallback onSuccess);
- Result getParameterImpl(
- uint32_t paramSize,
- const void* paramData,
- uint32_t valueSize,
- GetParameterSuccessCallback onSuccess);
Result getSupportedConfigsImpl(
uint32_t featureId,
uint32_t maxConfigs,
@@ -252,8 +263,6 @@
const EffectConfig& config,
const sp<IEffectBufferProviderCallback>& inputBufferProvider,
const sp<IEffectBufferProviderCallback>& outputBufferProvider);
- Result setParameterImpl(
- uint32_t paramSize, const void* paramData, uint32_t valueSize, const void* valueData);
};
} // namespace implementation
diff --git a/audio/effect/2.0/default/EffectsFactory.cpp b/audio/effect/2.0/default/EffectsFactory.cpp
index 572a428..08d92bd 100644
--- a/audio/effect/2.0/default/EffectsFactory.cpp
+++ b/audio/effect/2.0/default/EffectsFactory.cpp
@@ -95,7 +95,7 @@
status = EffectQueryNumberEffects(&numEffects);
if (status != OK) {
retval = Result::NOT_INITIALIZED;
- ALOGW("Error querying number of effects: %s", strerror(-status));
+ ALOGE("Error querying number of effects: %s", strerror(-status));
goto exit;
}
result.resize(numEffects);
@@ -105,7 +105,7 @@
if (status == OK) {
effectDescriptorFromHal(halDescriptor, &result[i]);
} else {
- ALOGW("Error querying effect at position %d / %d: %s",
+ ALOGE("Error querying effect at position %d / %d: %s",
i, numEffects, strerror(-status));
switch (status) {
case -ENOSYS: {
@@ -139,7 +139,7 @@
effectDescriptorFromHal(halDescriptor, &descriptor);
Result retval(Result::OK);
if (status != OK) {
- ALOGW("Error querying effect descriptor for %s: %s",
+ ALOGE("Error querying effect descriptor for %s: %s",
uuidToString(halUuid).c_str(), strerror(-status));
if (status == -ENOENT) {
retval = Result::INVALID_ARGUMENTS;
@@ -168,11 +168,13 @@
effect = dispatchEffectInstanceCreation(halDescriptor, handle);
effectId = EffectMap::getInstance().add(handle);
} else {
+ ALOGE("Error querying effect descriptor for %s: %s",
+ uuidToString(halUuid).c_str(), strerror(-status));
EffectRelease(handle);
}
}
if (status != OK) {
- ALOGW("Error creating effect %s: %s", uuidToString(halUuid).c_str(), strerror(-status));
+ ALOGE("Error creating effect %s: %s", uuidToString(halUuid).c_str(), strerror(-status));
if (status == -ENOENT) {
retval = Result::INVALID_ARGUMENTS;
} else {
diff --git a/audio/effect/2.0/default/EqualizerEffect.cpp b/audio/effect/2.0/default/EqualizerEffect.cpp
index 223716c..808d8eb 100644
--- a/audio/effect/2.0/default/EqualizerEffect.cpp
+++ b/audio/effect/2.0/default/EqualizerEffect.cpp
@@ -35,10 +35,15 @@
EqualizerEffect::~EqualizerEffect() {}
void EqualizerEffect::propertiesFromHal(
- t_equalizer_settings& halProperties,
+ const t_equalizer_settings& halProperties,
IEqualizerEffect::AllProperties* properties) {
properties->curPreset = halProperties.curPreset;
- properties->bandLevels.setToExternal(&halProperties.bandLevels[0], halProperties.numBands);
+ // t_equalizer_settings incorrectly defines bandLevels as uint16_t,
+ // whereas the actual type of values used by effects is int16_t.
+ const int16_t* signedBandLevels =
+ reinterpret_cast<const int16_t*>(&halProperties.bandLevels[0]);
+ properties->bandLevels.setToExternal(
+ const_cast<int16_t*>(signedBandLevels), halProperties.numBands);
}
std::vector<uint8_t> EqualizerEffect::propertiesToHal(
@@ -200,18 +205,18 @@
}
Return<void> EqualizerEffect::getLevelRange(getLevelRange_cb _hidl_cb) {
- uint16_t halLevels[2] = { 0, 0 };
+ int16_t halLevels[2] = { 0, 0 };
Result retval = mEffect->getParam(EQ_PARAM_LEVEL_RANGE, halLevels);
_hidl_cb(retval, halLevels[0], halLevels[1]);
return Void();
}
-Return<Result> EqualizerEffect::setBandLevel(uint16_t band, uint16_t level) {
+Return<Result> EqualizerEffect::setBandLevel(uint16_t band, int16_t level) {
return mEffect->setParam(EQ_PARAM_BAND_LEVEL, band, level);
}
Return<void> EqualizerEffect::getBandLevel(uint16_t band, getBandLevel_cb _hidl_cb) {
- uint16_t halLevel = 0;
+ int16_t halLevel = 0;
Result retval = mEffect->getParam(EQ_PARAM_BAND_LEVEL, band, halLevel);
_hidl_cb(retval, halLevel);
return Void();
@@ -272,14 +277,28 @@
const IEqualizerEffect::AllProperties& properties) {
t_equalizer_settings *halPropertiesPtr = nullptr;
std::vector<uint8_t> halBuffer = propertiesToHal(properties, &halPropertiesPtr);
- return mEffect->setParam(EQ_PARAM_PROPERTIES, *halPropertiesPtr);
+ uint32_t paramId = EQ_PARAM_PROPERTIES;
+ return mEffect->setParameterImpl(
+ sizeof(paramId), ¶mId, halBuffer.size(), halPropertiesPtr);
}
Return<void> EqualizerEffect::getAllProperties(getAllProperties_cb _hidl_cb) {
- t_equalizer_settings halProperties;
- Result retval = mEffect->getParam(EQ_PARAM_PROPERTIES, halProperties);
+ uint16_t numBands = 0;
+ Result retval = mEffect->getParam(EQ_PARAM_NUM_BANDS, numBands);
AllProperties properties;
- propertiesFromHal(halProperties, &properties);
+ if (retval != Result::OK) {
+ _hidl_cb(retval, properties);
+ return Void();
+ }
+ size_t valueSize = sizeof(t_equalizer_settings) + sizeof(int16_t) * numBands;
+ uint32_t paramId = EQ_PARAM_PROPERTIES;
+ retval = mEffect->getParameterImpl(
+ sizeof(paramId), ¶mId, valueSize,
+ [&] (uint32_t, const void* valueData) {
+ const t_equalizer_settings* halProperties =
+ reinterpret_cast<const t_equalizer_settings*>(valueData);
+ propertiesFromHal(*halProperties, &properties);
+ });
_hidl_cb(retval, properties);
return Void();
}
diff --git a/audio/effect/2.0/default/EqualizerEffect.h b/audio/effect/2.0/default/EqualizerEffect.h
index c9bed4f..9e8d75b 100644
--- a/audio/effect/2.0/default/EqualizerEffect.h
+++ b/audio/effect/2.0/default/EqualizerEffect.h
@@ -114,7 +114,7 @@
// Methods from ::android::hardware::audio::effect::V2_0::IEqualizerEffect follow.
Return<void> getNumBands(getNumBands_cb _hidl_cb) override;
Return<void> getLevelRange(getLevelRange_cb _hidl_cb) override;
- Return<Result> setBandLevel(uint16_t band, uint16_t level) override;
+ Return<Result> setBandLevel(uint16_t band, int16_t level) override;
Return<void> getBandLevel(uint16_t band, getBandLevel_cb _hidl_cb) override;
Return<void> getBandCenterFrequency(
uint16_t band, getBandCenterFrequency_cb _hidl_cb) override;
@@ -132,7 +132,7 @@
virtual ~EqualizerEffect();
void propertiesFromHal(
- t_equalizer_settings& halProperties,
+ const t_equalizer_settings& halProperties,
IEqualizerEffect::AllProperties* properties);
std::vector<uint8_t> propertiesToHal(
const IEqualizerEffect::AllProperties& properties,
diff --git a/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp b/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp
index e58b42c..fda5eb0 100644
--- a/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp
+++ b/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp
@@ -182,7 +182,18 @@
}
Return<void> LoudnessEnhancerEffect::getTargetGain(getTargetGain_cb _hidl_cb) {
- return mEffect->getIntegerParam(LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB, _hidl_cb);
+ // AOSP Loudness Enhancer expects the size of the request to not include the
+ // size of the parameter.
+ uint32_t paramId = LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB;
+ uint32_t targetGainMb = 0;
+ Result retval = mEffect->getParameterImpl(
+ sizeof(paramId), ¶mId,
+ 0, sizeof(targetGainMb),
+ [&] (uint32_t, const void* valueData) {
+ memcpy(&targetGainMb, valueData, sizeof(targetGainMb));
+ });
+ _hidl_cb(retval, targetGainMb);
+ return Void();
}
} // namespace implementation
diff --git a/audio/effect/2.0/vts/functional/Android.bp b/audio/effect/2.0/vts/functional/Android.bp
index 1bc3f39..8a370cd 100644
--- a/audio/effect/2.0/vts/functional/Android.bp
+++ b/audio/effect/2.0/vts/functional/Android.bp
@@ -26,7 +26,10 @@
"libhidltransport",
"libnativehelper",
"libutils",
+ "android.hardware.audio.common@2.0",
"android.hardware.audio.effect@2.0",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
],
static_libs: ["VtsHalHidlTargetTestBase"],
cflags: [
diff --git a/audio/effect/2.0/vts/functional/VtsHalAudioEffectV2_0TargetTest.cpp b/audio/effect/2.0/vts/functional/VtsHalAudioEffectV2_0TargetTest.cpp
index 063243b..f6da213 100644
--- a/audio/effect/2.0/vts/functional/VtsHalAudioEffectV2_0TargetTest.cpp
+++ b/audio/effect/2.0/vts/functional/VtsHalAudioEffectV2_0TargetTest.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -16,47 +16,67 @@
#define LOG_TAG "AudioEffectHidlHalTest"
#include <android-base/logging.h>
-#include <cutils/native_handle.h>
+#include <system/audio.h>
+#include <android/hardware/audio/effect/2.0/IEffect.h>
#include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
+#include <android/hardware/audio/effect/2.0/IEqualizerEffect.h>
+#include <android/hardware/audio/effect/2.0/ILoudnessEnhancerEffect.h>
#include <android/hardware/audio/effect/2.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
#include <VtsHalHidlTargetTestBase.h>
-using ::android::hardware::audio::common::V2_0::Uuid;
-using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
-using ::android::hardware::audio::effect::V2_0::IEffect;
-using ::android::hardware::audio::effect::V2_0::IEffectsFactory;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Status;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::sp;
+using android::hardware::audio::common::V2_0::AudioDevice;
+using android::hardware::audio::common::V2_0::AudioHandleConsts;
+using android::hardware::audio::common::V2_0::AudioMode;
+using android::hardware::audio::common::V2_0::Uuid;
+using android::hardware::audio::effect::V2_0::AudioBuffer;
+using android::hardware::audio::effect::V2_0::EffectBufferConfig;
+using android::hardware::audio::effect::V2_0::EffectConfig;
+using android::hardware::audio::effect::V2_0::EffectDescriptor;
+using android::hardware::audio::effect::V2_0::EffectOffloadParameter;
+using android::hardware::audio::effect::V2_0::IEffect;
+using android::hardware::audio::effect::V2_0::IEffectsFactory;
+using android::hardware::audio::effect::V2_0::IEqualizerEffect;
+using android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect;
+using android::hardware::audio::effect::V2_0::Result;
+using android::hardware::MQDescriptorSync;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::hidl_memory;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hidl::allocator::V1_0::IAllocator;
+using android::hidl::memory::V1_0::IMemory;
+using android::sp;
-// The main test class for Audio Effect HIDL HAL.
-class AudioEffectHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+#endif
+
+// The main test class for Audio Effects Factory HIDL HAL.
+class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
- virtual void SetUp() override {
- effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>();
+ void SetUp() override {
+ effectsFactory =
+ ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>();
ASSERT_NE(effectsFactory, nullptr);
}
- virtual void TearDown() override {}
+ void TearDown() override { effectsFactory.clear(); }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
sp<IEffectsFactory> effectsFactory;
};
-// A class for test environment setup (kept since this file is a template).
-class AudioEffectHidlEnvironment : public ::testing::Environment {
- public:
- virtual void SetUp() {}
- virtual void TearDown() {}
-
- private:
-};
-
-TEST_F(AudioEffectHidlTest, EnumerateEffects) {
+TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) {
+ description("Verify that EnumerateEffects returns at least one effect");
Result retval = Result::NOT_INITIALIZED;
size_t effectCount = 0;
Return<void> ret = effectsFactory->getAllDescriptors(
@@ -65,11 +85,12 @@
effectCount = result.size();
});
EXPECT_TRUE(ret.isOk());
- EXPECT_EQ(retval, Result::OK);
+ EXPECT_EQ(Result::OK, retval);
EXPECT_GT(effectCount, 0u);
}
-TEST_F(AudioEffectHidlTest, CreateEffect) {
+TEST_F(AudioEffectsFactoryHidlTest, CreateEffect) {
+ description("Verify that an effect can be created via CreateEffect");
bool gotEffect = false;
Uuid effectUuid;
Return<void> ret = effectsFactory->getAllDescriptors(
@@ -84,7 +105,7 @@
Result retval = Result::NOT_INITIALIZED;
sp<IEffect> effect;
ret = effectsFactory->createEffect(
- effectUuid, 1 /* session */, 1 /* ioHandle */,
+ effectUuid, 1 /*session*/, 1 /*ioHandle*/,
[&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) {
retval = r;
if (r == Result::OK) {
@@ -92,11 +113,14 @@
}
});
EXPECT_TRUE(ret.isOk());
- EXPECT_EQ(retval, Result::OK);
- EXPECT_NE(effect, nullptr);
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_NE(nullptr, effect.get());
}
-TEST_F(AudioEffectHidlTest, GetDescriptor) {
+TEST_F(AudioEffectsFactoryHidlTest, GetDescriptor) {
+ description(
+ "Verify that effects factory can provide an effect descriptor via "
+ "GetDescriptor");
hidl_vec<EffectDescriptor> allDescriptors;
Return<void> ret = effectsFactory->getAllDescriptors(
[&](Result r, const hidl_vec<EffectDescriptor>& result) {
@@ -116,10 +140,602 @@
EXPECT_TRUE(ret.isOk());
}
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(new AudioEffectHidlEnvironment);
- ::testing::InitGoogleTest(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
+// Equalizer effect is required by CDD, but only the type is fixed.
+// This is the same UUID as AudioEffect.EFFECT_TYPE_EQUALIZER in Java.
+static const Uuid EQUALIZER_EFFECT_TYPE = {
+ 0x0bed4300, 0xddd6, 0x11db, 0x8f34,
+ std::array<uint8_t, 6>{{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}};
+// Loudness Enhancer effect is required by CDD, but only the type is fixed.
+// This is the same UUID as AudioEffect.EFFECT_TYPE_LOUDNESS_ENHANCER in Java.
+static const Uuid LOUDNESS_ENHANCER_EFFECT_TYPE = {
+ 0xfe3199be, 0xaed0, 0x413f, 0x87bb,
+ std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}};
+
+// The main test class for Audio Effect HIDL HAL.
+class AudioEffectHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ void SetUp() override {
+ effectsFactory =
+ ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>();
+ ASSERT_NE(nullptr, effectsFactory.get());
+
+ findAndCreateEffect(getEffectType());
+ ASSERT_NE(nullptr, effect.get());
+
+ Return<Result> ret = effect->init();
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, ret);
+ }
+
+ void TearDown() override {
+ effect.clear();
+ effectsFactory.clear();
+ }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ virtual Uuid getEffectType() { return EQUALIZER_EFFECT_TYPE; }
+
+ void findAndCreateEffect(const Uuid& type);
+ void findEffectInstance(const Uuid& type, Uuid* uuid);
+ void getChannelCount(uint32_t* channelCount);
+
+ sp<IEffectsFactory> effectsFactory;
+ sp<IEffect> effect;
+};
+
+void AudioEffectHidlTest::findAndCreateEffect(const Uuid& type) {
+ Uuid effectUuid;
+ findEffectInstance(type, &effectUuid);
+ Return<void> ret = effectsFactory->createEffect(
+ effectUuid, 1 /*session*/, 1 /*ioHandle*/,
+ [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) {
+ if (r == Result::OK) {
+ effect = result;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+}
+
+void AudioEffectHidlTest::findEffectInstance(const Uuid& type, Uuid* uuid) {
+ bool effectFound = false;
+ Return<void> ret = effectsFactory->getAllDescriptors(
+ [&](Result r, const hidl_vec<EffectDescriptor>& result) {
+ if (r == Result::OK) {
+ for (const auto& desc : result) {
+ if (desc.type == type) {
+ effectFound = true;
+ *uuid = desc.uuid;
+ break;
+ }
+ }
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_TRUE(effectFound);
+}
+
+void AudioEffectHidlTest::getChannelCount(uint32_t* channelCount) {
+ Result retval;
+ EffectConfig currentConfig;
+ Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
+ retval = r;
+ if (r == Result::OK) {
+ currentConfig = conf;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+ ASSERT_TRUE(audio_channel_mask_is_valid(
+ static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels)));
+ *channelCount = audio_channel_count_from_out_mask(
+ static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels));
+}
+
+TEST_F(AudioEffectHidlTest, Close) {
+ description("Verify that an effect can be closed");
+ Return<Result> ret = effect->close();
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, GetDescriptor) {
+ description(
+ "Verify that an effect can return its own descriptor via GetDescriptor");
+ Result retval = Result::NOT_INITIALIZED;
+ Uuid actualType;
+ Return<void> ret =
+ effect->getDescriptor([&](Result r, const EffectDescriptor& desc) {
+ retval = r;
+ if (r == Result::OK) {
+ actualType = desc.type;
+ }
+ });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(getEffectType(), actualType);
+}
+
+TEST_F(AudioEffectHidlTest, GetSetConfig) {
+ description(
+ "Verify that it is possible to manipulate effect config via Get / "
+ "SetConfig");
+ Result retval = Result::NOT_INITIALIZED;
+ EffectConfig currentConfig;
+ Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
+ retval = r;
+ if (r == Result::OK) {
+ currentConfig = conf;
+ }
+ });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ Return<Result> ret2 = effect->setConfig(currentConfig, nullptr, nullptr);
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, ret2);
+}
+
+// Not generated automatically because AudioBuffer contains
+// instances of hidl_memory which can't be compared properly
+// in general case due to presence of handles.
+//
+// However, in this particular case, handles must not present
+// thus comparison is possible.
+//
+// operator== must be defined in the same namespace as the structures.
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+inline bool operator==(const AudioBuffer& lhs, const AudioBuffer& rhs) {
+ return lhs.id == rhs.id && lhs.frameCount == rhs.frameCount &&
+ lhs.data.handle() == nullptr && rhs.data.handle() == nullptr;
+}
+
+inline bool operator==(const EffectBufferConfig& lhs,
+ const EffectBufferConfig& rhs) {
+ return lhs.buffer == rhs.buffer && lhs.samplingRateHz == rhs.samplingRateHz &&
+ lhs.channels == rhs.channels && lhs.format == rhs.format &&
+ lhs.accessMode == rhs.accessMode && lhs.mask == rhs.mask;
+}
+
+inline bool operator==(const EffectConfig& lhs, const EffectConfig& rhs) {
+ return lhs.inputCfg == rhs.inputCfg && lhs.outputCfg == rhs.outputCfg;
+}
+} // namespace V2_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+TEST_F(AudioEffectHidlTest, Reset) {
+ description("Verify that Reset preserves effect configuration");
+ Result retval = Result::NOT_INITIALIZED;
+ EffectConfig originalConfig;
+ Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
+ retval = r;
+ if (r == Result::OK) {
+ originalConfig = conf;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+ Return<Result> ret2 = effect->reset();
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, ret2);
+ EffectConfig configAfterReset;
+ ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
+ retval = r;
+ if (r == Result::OK) {
+ configAfterReset = conf;
+ }
+ });
+ EXPECT_EQ(originalConfig, configAfterReset);
+}
+
+TEST_F(AudioEffectHidlTest, DisableEnableDisable) {
+ description("Verify Disable -> Enable -> Disable sequence for an effect");
+ Return<Result> ret = effect->disable();
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, ret);
+ ret = effect->enable();
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ ret = effect->disable();
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, SetDevice) {
+ description("Verify that SetDevice works for an output chain effect");
+ Return<Result> ret = effect->setDevice(AudioDevice::OUT_SPEAKER);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, SetAndGetVolume) {
+ description("Verify that SetAndGetVolume method works for an effect");
+ uint32_t channelCount;
+ getChannelCount(&channelCount);
+ hidl_vec<uint32_t> volumes;
+ volumes.resize(channelCount);
+ for (uint32_t i = 0; i < channelCount; ++i) {
+ volumes[i] = 0;
+ }
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = effect->setAndGetVolume(
+ volumes, [&](Result r, const hidl_vec<uint32_t>&) { retval = r; });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+}
+
+TEST_F(AudioEffectHidlTest, VolumeChangeNotification) {
+ description("Verify that effect accepts VolumeChangeNotification");
+ uint32_t channelCount;
+ getChannelCount(&channelCount);
+ hidl_vec<uint32_t> volumes;
+ volumes.resize(channelCount);
+ for (uint32_t i = 0; i < channelCount; ++i) {
+ volumes[i] = 0;
+ }
+ Return<Result> ret = effect->volumeChangeNotification(volumes);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, SetAudioMode) {
+ description("Verify that SetAudioMode works for an effect");
+ Return<Result> ret = effect->setAudioMode(AudioMode::NORMAL);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, Offload) {
+ description("Verify that calling Offload methods works for an effect");
+ EffectOffloadParameter offloadParam;
+ offloadParam.isOffload = false;
+ offloadParam.ioHandle =
+ static_cast<int>(AudioHandleConsts::AUDIO_IO_HANDLE_NONE);
+ Return<Result> ret = effect->offload(offloadParam);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, PrepareForProcessing) {
+ description("Verify that PrepareForProcessing method works for an effect");
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = effect->prepareForProcessing(
+ [&](Result r, const MQDescriptorSync<Result>&) { retval = r; });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+}
+
+TEST_F(AudioEffectHidlTest, SetProcessBuffers) {
+ description("Verify that SetProcessBuffers works for an effect");
+ sp<IAllocator> ashmem = IAllocator::getService("ashmem");
+ ASSERT_NE(nullptr, ashmem.get());
+ bool success = false;
+ AudioBuffer buffer;
+ Return<void> ret =
+ ashmem->allocate(1024, [&](bool s, const hidl_memory& memory) {
+ success = s;
+ if (s) {
+ buffer.data = memory;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_TRUE(success);
+ Return<Result> ret2 = effect->setProcessBuffers(buffer, buffer);
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, ret2);
+}
+
+// Testing getConfigReverse, getAuxChannelsConfig,
+// getSupportedAuxChannelsConfigs, setAudioSource, setConfigReverse,
+// setInputDevice doesn't make sense, because normally they are not supported by
+// the Equalizer, but it wouldn't be a problem if some vendor implementation
+// supports them, thus we can't test these methods neither for success, nor for
+// failure.
+
+// command, getParameter, getSupportedConfigsForFeature,
+// getCurrentConfigForFeature, setCurrentConfigForFeature, setParameter are
+// opaque channels between vendor apps and HALs, and can't be meaningfully
+// tested with effects that don't support them.
+
+// The main test class for Equalizer Audio Effect HIDL HAL.
+class EqualizerAudioEffectHidlTest : public AudioEffectHidlTest {
+ public:
+ void SetUp() override {
+ AudioEffectHidlTest::SetUp();
+ equalizer = IEqualizerEffect::castFrom(effect);
+ ASSERT_NE(nullptr, equalizer.get());
+ }
+
+ protected:
+ Uuid getEffectType() override { return EQUALIZER_EFFECT_TYPE; }
+ void getNumBands(uint16_t* numBands);
+ void getLevelRange(int16_t* minLevel, int16_t* maxLevel);
+ void getBandFrequencyRange(uint16_t band, uint32_t* minFreq,
+ uint32_t* centerFreq, uint32_t* maxFreq);
+ void getPresetCount(size_t* count);
+
+ sp<IEqualizerEffect> equalizer;
+};
+
+void EqualizerAudioEffectHidlTest::getNumBands(uint16_t* numBands) {
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = equalizer->getNumBands([&](Result r, uint16_t b) {
+ retval = r;
+ if (retval == Result::OK) {
+ *numBands = b;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+}
+
+void EqualizerAudioEffectHidlTest::getLevelRange(int16_t* minLevel,
+ int16_t* maxLevel) {
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret =
+ equalizer->getLevelRange([&](Result r, int16_t min, int16_t max) {
+ retval = r;
+ if (retval == Result::OK) {
+ *minLevel = min;
+ *maxLevel = max;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+}
+
+void EqualizerAudioEffectHidlTest::getBandFrequencyRange(uint16_t band,
+ uint32_t* minFreq,
+ uint32_t* centerFreq,
+ uint32_t* maxFreq) {
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = equalizer->getBandFrequencyRange(
+ band, [&](Result r, uint32_t min, uint32_t max) {
+ retval = r;
+ if (retval == Result::OK) {
+ *minFreq = min;
+ *maxFreq = max;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+ ret = equalizer->getBandCenterFrequency(band, [&](Result r, uint32_t center) {
+ retval = r;
+ if (retval == Result::OK) {
+ *centerFreq = center;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+}
+
+void EqualizerAudioEffectHidlTest::getPresetCount(size_t* count) {
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = equalizer->getPresetNames(
+ [&](Result r, const hidl_vec<hidl_string>& names) {
+ retval = r;
+ if (retval == Result::OK) {
+ *count = names.size();
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetNumBands) {
+ description("Verify that Equalizer effect reports at least one band");
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ EXPECT_GT(numBands, 0);
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetLevelRange) {
+ description("Verify that Equalizer effect reports adequate band level range");
+ int16_t minLevel = 0x7fff, maxLevel = 0;
+ getLevelRange(&minLevel, &maxLevel);
+ EXPECT_GT(maxLevel, minLevel);
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetSetBandLevel) {
+ description(
+ "Verify that manipulating band levels works for Equalizer effect");
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ ASSERT_GT(numBands, 0);
+ int16_t levels[3]{0x7fff, 0, 0};
+ getLevelRange(&levels[0], &levels[2]);
+ ASSERT_GT(levels[2], levels[0]);
+ levels[1] = (levels[2] + levels[0]) / 2;
+ for (uint16_t i = 0; i < numBands; ++i) {
+ for (size_t j = 0; j < ARRAY_SIZE(levels); ++j) {
+ Return<Result> ret = equalizer->setBandLevel(i, levels[j]);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ Result retval = Result::NOT_INITIALIZED;
+ int16_t actualLevel;
+ Return<void> ret2 = equalizer->getBandLevel(i, [&](Result r, int16_t l) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualLevel = l;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(levels[j], actualLevel);
+ }
+ }
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) {
+ description(
+ "Verify that Equalizer effect reports adequate band frequency range");
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ ASSERT_GT(numBands, 0);
+ for (uint16_t i = 0; i < numBands; ++i) {
+ uint32_t minFreq = 0xffffffff, centerFreq = 0xffffffff,
+ maxFreq = 0xffffffff;
+ getBandFrequencyRange(i, &minFreq, ¢erFreq, &maxFreq);
+ // Note: NXP legacy implementation reports "1" as upper bound for last band,
+ // so this check fails.
+ EXPECT_GE(maxFreq, centerFreq);
+ EXPECT_GE(centerFreq, minFreq);
+ }
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetBandForFrequency) {
+ description(
+ "Verify that Equalizer effect supports GetBandForFrequency correctly");
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ ASSERT_GT(numBands, 0);
+ for (uint16_t i = 0; i < numBands; ++i) {
+ uint32_t freqs[3]{0, 0, 0};
+ getBandFrequencyRange(i, &freqs[0], &freqs[1], &freqs[2]);
+ // NXP legacy implementation reports "1" as upper bound for last band, some
+ // of the checks fail.
+ for (size_t j = 0; j < ARRAY_SIZE(freqs); ++j) {
+ if (j == 0) {
+ freqs[j]++;
+ } // Min frequency is an open interval.
+ Result retval = Result::NOT_INITIALIZED;
+ uint16_t actualBand = numBands + 1;
+ Return<void> ret =
+ equalizer->getBandForFrequency(freqs[j], [&](Result r, uint16_t b) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualBand = b;
+ }
+ });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(i, actualBand) << "Frequency: " << freqs[j];
+ }
+ }
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetPresetNames) {
+ description("Verify that Equalizer effect reports at least one preset");
+ size_t presetCount;
+ getPresetCount(&presetCount);
+ EXPECT_GT(presetCount, 0u);
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) {
+ description(
+ "Verify that manipulating the current preset for Equalizer effect");
+ size_t presetCount;
+ getPresetCount(&presetCount);
+ ASSERT_GT(presetCount, 0u);
+ for (uint16_t i = 0; i < presetCount; ++i) {
+ Return<Result> ret = equalizer->setCurrentPreset(i);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ Result retval = Result::NOT_INITIALIZED;
+ uint16_t actualPreset = 0xffff;
+ Return<void> ret2 = equalizer->getCurrentPreset([&](Result r, uint16_t p) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualPreset = p;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(i, actualPreset);
+ }
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetSetAllProperties) {
+ description(
+ "Verify that setting band levels and presets works via Get / "
+ "SetAllProperties for Equalizer effect");
+ using AllProperties =
+ android::hardware::audio::effect::V2_0::IEqualizerEffect::AllProperties;
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ ASSERT_GT(numBands, 0);
+ AllProperties props;
+ props.bandLevels.resize(numBands);
+ for (size_t i = 0; i < numBands; ++i) {
+ props.bandLevels[i] = 0;
+ }
+
+ AllProperties actualProps;
+ Result retval = Result::NOT_INITIALIZED;
+
+ // Verify setting of the band levels via properties.
+ props.curPreset = -1;
+ Return<Result> ret = equalizer->setAllProperties(props);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ Return<void> ret2 =
+ equalizer->getAllProperties([&](Result r, AllProperties p) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualProps = p;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(props.bandLevels, actualProps.bandLevels);
+
+ // Verify setting of the current preset via properties.
+ props.curPreset = 0; // Assuming there is at least one preset.
+ ret = equalizer->setAllProperties(props);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ ret2 = equalizer->getAllProperties([&](Result r, AllProperties p) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualProps = p;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(props.curPreset, actualProps.curPreset);
+}
+
+// The main test class for Equalizer Audio Effect HIDL HAL.
+class LoudnessEnhancerAudioEffectHidlTest : public AudioEffectHidlTest {
+ public:
+ void SetUp() override {
+ AudioEffectHidlTest::SetUp();
+ enhancer = ILoudnessEnhancerEffect::castFrom(effect);
+ ASSERT_NE(nullptr, enhancer.get());
+ }
+
+ protected:
+ Uuid getEffectType() override { return LOUDNESS_ENHANCER_EFFECT_TYPE; }
+
+ sp<ILoudnessEnhancerEffect> enhancer;
+};
+
+TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) {
+ description(
+ "Verify that manipulating the target gain works for Loudness Enhancer "
+ "effect");
+ const int32_t gain = 100;
+ Return<Result> ret = enhancer->setTargetGain(gain);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ int32_t actualGain = 0;
+ Result retval;
+ Return<void> ret2 = enhancer->getTargetGain([&](Result r, int32_t g) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualGain = g;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(gain, actualGain);
}
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index a6507dd..e6575b0 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -215,11 +215,9 @@
ALOGD("%s vendor library loaded", __func__);
- // Power cycle chip
+ // Power on the controller
- int power_state = BT_VND_PWR_OFF;
- lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
- power_state = BT_VND_PWR_ON;
+ int power_state = BT_VND_PWR_ON;
lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
// Get the UART socket(s)
@@ -250,10 +248,9 @@
new hci::MctProtocol(fd_list, intercept_events, acl_cb);
fd_watcher_.WatchFdForNonBlockingReads(
fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
- if (fd_count >= CH_ACL_IN)
- fd_watcher_.WatchFdForNonBlockingReads(
- fd_list[CH_ACL_IN],
- [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
+ fd_watcher_.WatchFdForNonBlockingReads(
+ fd_list[CH_ACL_IN],
+ [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
hci_ = mct_hci;
}
@@ -268,13 +265,6 @@
}
void VendorInterface::Close() {
- // These callbacks may send HCI events (vendor-dependent), so make sure to
- // StopWatching the file descriptor after this.
- if (lib_interface_ != nullptr) {
- bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE;
- lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
- }
-
fd_watcher_.StopWatchingFileDescriptors();
if (hci_ != nullptr) {
diff --git a/camera/device/1.0/default/Android.bp b/camera/device/1.0/default/Android.bp
index eec641a..5688fc1 100644
--- a/camera/device/1.0/default/Android.bp
+++ b/camera/device/1.0/default/Android.bp
@@ -1,6 +1,7 @@
cc_library_shared {
name: "camera.device@1.0-impl",
defaults: ["hidl_defaults"],
+ proprietary: true,
srcs: [
"CameraDevice.cpp",
],
diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp
index 3767e09..e0dc5ff 100644
--- a/camera/device/3.2/default/Android.bp
+++ b/camera/device/3.2/default/Android.bp
@@ -1,6 +1,7 @@
cc_library_shared {
name: "camera.device@3.2-impl",
defaults: ["hidl_defaults"],
+ proprietary: true,
srcs: ["CameraDevice.cpp",
"CameraDeviceSession.cpp",
"convert.cpp"],
diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp
index ad9f0b8..8701ec1 100644
--- a/camera/provider/2.4/default/CameraProvider.cpp
+++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -183,6 +183,12 @@
}
ALOGI("Loaded \"%s\" camera module", mModule->getModuleName());
+ // Setup vendor tags here so HAL can setup vendor keys in camera characteristics
+ VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+ if (!setUpVendorTags()) {
+ ALOGE("%s: Vendor tag setup failed, will not be available.", __FUNCTION__);
+ }
+
// Setup callback now because we are going to try openLegacy next
err = mModule->setCallbacks(this);
if (err != OK) {
@@ -225,11 +231,6 @@
}
}
- // Setup vendor tags here so HAL can setup vendor keys in camera characteristics
- VendorTagDescriptor::clearGlobalVendorTagDescriptor();
- if (!setUpVendorTags()) {
- ALOGE("%s: Vendor tag setup failed, will not be available.", __FUNCTION__);
- }
return false; // mInitFailed
}
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index f1215b8..a0be5cb 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -17,7 +17,8 @@
cc_test {
name: "VtsHalCameraProviderV2_4TargetTest",
defaults: ["hidl_defaults"],
- srcs: ["VtsHalCameraProviderV2_4TargetTest.cpp"],
+ srcs: ["VtsHalCameraProviderV2_4TargetTest.cpp",
+ "CameraParameters.cpp" ],
shared_libs: [
"liblog",
"libhidlbase",
@@ -26,7 +27,10 @@
"libutils",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@1.0",
"libcamera_metadata",
+ "libbinder",
+ "libgui",
"libui"
],
static_libs: ["VtsHalHidlTargetTestBase"],
diff --git a/camera/provider/2.4/vts/functional/CameraParameters.cpp b/camera/provider/2.4/vts/functional/CameraParameters.cpp
new file mode 100644
index 0000000..0285154
--- /dev/null
+++ b/camera/provider/2.4/vts/functional/CameraParameters.cpp
@@ -0,0 +1,537 @@
+/*
+**
+** Copyright 2008, 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.
+*/
+
+#define LOG_TAG "CameraParams"
+#include <utils/Log.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include "CameraParameters.h"
+#include <system/graphics.h>
+
+namespace android {
+// Parameter keys to communicate between camera application and driver.
+const char CameraParameters::KEY_PREVIEW_SIZE[] = "preview-size";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES[] = "preview-size-values";
+const char CameraParameters::KEY_PREVIEW_FORMAT[] = "preview-format";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS[] = "preview-format-values";
+const char CameraParameters::KEY_PREVIEW_FRAME_RATE[] = "preview-frame-rate";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES[] = "preview-frame-rate-values";
+const char CameraParameters::KEY_PREVIEW_FPS_RANGE[] = "preview-fps-range";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE[] = "preview-fps-range-values";
+const char CameraParameters::KEY_PICTURE_SIZE[] = "picture-size";
+const char CameraParameters::KEY_SUPPORTED_PICTURE_SIZES[] = "picture-size-values";
+const char CameraParameters::KEY_PICTURE_FORMAT[] = "picture-format";
+const char CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS[] = "picture-format-values";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH[] = "jpeg-thumbnail-width";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT[] = "jpeg-thumbnail-height";
+const char CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[] = "jpeg-thumbnail-size-values";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY[] = "jpeg-thumbnail-quality";
+const char CameraParameters::KEY_JPEG_QUALITY[] = "jpeg-quality";
+const char CameraParameters::KEY_ROTATION[] = "rotation";
+const char CameraParameters::KEY_GPS_LATITUDE[] = "gps-latitude";
+const char CameraParameters::KEY_GPS_LONGITUDE[] = "gps-longitude";
+const char CameraParameters::KEY_GPS_ALTITUDE[] = "gps-altitude";
+const char CameraParameters::KEY_GPS_TIMESTAMP[] = "gps-timestamp";
+const char CameraParameters::KEY_GPS_PROCESSING_METHOD[] = "gps-processing-method";
+const char CameraParameters::KEY_WHITE_BALANCE[] = "whitebalance";
+const char CameraParameters::KEY_SUPPORTED_WHITE_BALANCE[] = "whitebalance-values";
+const char CameraParameters::KEY_EFFECT[] = "effect";
+const char CameraParameters::KEY_SUPPORTED_EFFECTS[] = "effect-values";
+const char CameraParameters::KEY_ANTIBANDING[] = "antibanding";
+const char CameraParameters::KEY_SUPPORTED_ANTIBANDING[] = "antibanding-values";
+const char CameraParameters::KEY_SCENE_MODE[] = "scene-mode";
+const char CameraParameters::KEY_SUPPORTED_SCENE_MODES[] = "scene-mode-values";
+const char CameraParameters::KEY_FLASH_MODE[] = "flash-mode";
+const char CameraParameters::KEY_SUPPORTED_FLASH_MODES[] = "flash-mode-values";
+const char CameraParameters::KEY_FOCUS_MODE[] = "focus-mode";
+const char CameraParameters::KEY_SUPPORTED_FOCUS_MODES[] = "focus-mode-values";
+const char CameraParameters::KEY_MAX_NUM_FOCUS_AREAS[] = "max-num-focus-areas";
+const char CameraParameters::KEY_FOCUS_AREAS[] = "focus-areas";
+const char CameraParameters::KEY_FOCAL_LENGTH[] = "focal-length";
+const char CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE[] = "horizontal-view-angle";
+const char CameraParameters::KEY_VERTICAL_VIEW_ANGLE[] = "vertical-view-angle";
+const char CameraParameters::KEY_EXPOSURE_COMPENSATION[] = "exposure-compensation";
+const char CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION[] = "max-exposure-compensation";
+const char CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION[] = "min-exposure-compensation";
+const char CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP[] = "exposure-compensation-step";
+const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK[] = "auto-exposure-lock";
+const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[] = "auto-exposure-lock-supported";
+const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK[] = "auto-whitebalance-lock";
+const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[] = "auto-whitebalance-lock-supported";
+const char CameraParameters::KEY_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas";
+const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas";
+const char CameraParameters::KEY_ZOOM[] = "zoom";
+const char CameraParameters::KEY_MAX_ZOOM[] = "max-zoom";
+const char CameraParameters::KEY_ZOOM_RATIOS[] = "zoom-ratios";
+const char CameraParameters::KEY_ZOOM_SUPPORTED[] = "zoom-supported";
+const char CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED[] = "smooth-zoom-supported";
+const char CameraParameters::KEY_FOCUS_DISTANCES[] = "focus-distances";
+const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format";
+const char CameraParameters::KEY_VIDEO_SIZE[] = "video-size";
+const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values";
+const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video";
+const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW[] = "max-num-detected-faces-hw";
+const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW[] = "max-num-detected-faces-sw";
+const char CameraParameters::KEY_RECORDING_HINT[] = "recording-hint";
+const char CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED[] = "video-snapshot-supported";
+const char CameraParameters::KEY_VIDEO_STABILIZATION[] = "video-stabilization";
+const char CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED[] = "video-stabilization-supported";
+const char CameraParameters::KEY_LIGHTFX[] = "light-fx";
+
+const char CameraParameters::TRUE[] = "true";
+const char CameraParameters::FALSE[] = "false";
+const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity";
+
+// Values for white balance settings.
+const char CameraParameters::WHITE_BALANCE_AUTO[] = "auto";
+const char CameraParameters::WHITE_BALANCE_INCANDESCENT[] = "incandescent";
+const char CameraParameters::WHITE_BALANCE_FLUORESCENT[] = "fluorescent";
+const char CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT[] = "warm-fluorescent";
+const char CameraParameters::WHITE_BALANCE_DAYLIGHT[] = "daylight";
+const char CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT[] = "cloudy-daylight";
+const char CameraParameters::WHITE_BALANCE_TWILIGHT[] = "twilight";
+const char CameraParameters::WHITE_BALANCE_SHADE[] = "shade";
+
+// Values for effect settings.
+const char CameraParameters::EFFECT_NONE[] = "none";
+const char CameraParameters::EFFECT_MONO[] = "mono";
+const char CameraParameters::EFFECT_NEGATIVE[] = "negative";
+const char CameraParameters::EFFECT_SOLARIZE[] = "solarize";
+const char CameraParameters::EFFECT_SEPIA[] = "sepia";
+const char CameraParameters::EFFECT_POSTERIZE[] = "posterize";
+const char CameraParameters::EFFECT_WHITEBOARD[] = "whiteboard";
+const char CameraParameters::EFFECT_BLACKBOARD[] = "blackboard";
+const char CameraParameters::EFFECT_AQUA[] = "aqua";
+
+// Values for antibanding settings.
+const char CameraParameters::ANTIBANDING_AUTO[] = "auto";
+const char CameraParameters::ANTIBANDING_50HZ[] = "50hz";
+const char CameraParameters::ANTIBANDING_60HZ[] = "60hz";
+const char CameraParameters::ANTIBANDING_OFF[] = "off";
+
+// Values for flash mode settings.
+const char CameraParameters::FLASH_MODE_OFF[] = "off";
+const char CameraParameters::FLASH_MODE_AUTO[] = "auto";
+const char CameraParameters::FLASH_MODE_ON[] = "on";
+const char CameraParameters::FLASH_MODE_RED_EYE[] = "red-eye";
+const char CameraParameters::FLASH_MODE_TORCH[] = "torch";
+
+// Values for scene mode settings.
+const char CameraParameters::SCENE_MODE_AUTO[] = "auto";
+const char CameraParameters::SCENE_MODE_ACTION[] = "action";
+const char CameraParameters::SCENE_MODE_PORTRAIT[] = "portrait";
+const char CameraParameters::SCENE_MODE_LANDSCAPE[] = "landscape";
+const char CameraParameters::SCENE_MODE_NIGHT[] = "night";
+const char CameraParameters::SCENE_MODE_NIGHT_PORTRAIT[] = "night-portrait";
+const char CameraParameters::SCENE_MODE_THEATRE[] = "theatre";
+const char CameraParameters::SCENE_MODE_BEACH[] = "beach";
+const char CameraParameters::SCENE_MODE_SNOW[] = "snow";
+const char CameraParameters::SCENE_MODE_SUNSET[] = "sunset";
+const char CameraParameters::SCENE_MODE_STEADYPHOTO[] = "steadyphoto";
+const char CameraParameters::SCENE_MODE_FIREWORKS[] = "fireworks";
+const char CameraParameters::SCENE_MODE_SPORTS[] = "sports";
+const char CameraParameters::SCENE_MODE_PARTY[] = "party";
+const char CameraParameters::SCENE_MODE_CANDLELIGHT[] = "candlelight";
+const char CameraParameters::SCENE_MODE_BARCODE[] = "barcode";
+const char CameraParameters::SCENE_MODE_HDR[] = "hdr";
+
+const char CameraParameters::PIXEL_FORMAT_YUV422SP[] = "yuv422sp";
+const char CameraParameters::PIXEL_FORMAT_YUV420SP[] = "yuv420sp";
+const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv";
+const char CameraParameters::PIXEL_FORMAT_YUV420P[] = "yuv420p";
+const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565";
+const char CameraParameters::PIXEL_FORMAT_RGBA8888[] = "rgba8888";
+const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg";
+const char CameraParameters::PIXEL_FORMAT_BAYER_RGGB[] = "bayer-rggb";
+const char CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE[] = "android-opaque";
+
+// Values for focus mode settings.
+const char CameraParameters::FOCUS_MODE_AUTO[] = "auto";
+const char CameraParameters::FOCUS_MODE_INFINITY[] = "infinity";
+const char CameraParameters::FOCUS_MODE_MACRO[] = "macro";
+const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed";
+const char CameraParameters::FOCUS_MODE_EDOF[] = "edof";
+const char CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO[] = "continuous-video";
+const char CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE[] = "continuous-picture";
+
+// Values for light fx settings
+const char CameraParameters::LIGHTFX_LOWLIGHT[] = "low-light";
+const char CameraParameters::LIGHTFX_HDR[] = "high-dynamic-range";
+
+CameraParameters::CameraParameters()
+ : mMap()
+{
+}
+
+CameraParameters::~CameraParameters()
+{
+}
+
+String8 CameraParameters::flatten() const
+{
+ String8 flattened("");
+ size_t size = mMap.size();
+
+ for (size_t i = 0; i < size; i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+
+ flattened += k;
+ flattened += "=";
+ flattened += v;
+ if (i != size-1)
+ flattened += ";";
+ }
+
+ return flattened;
+}
+
+void CameraParameters::unflatten(const String8 ¶ms)
+{
+ const char *a = params.string();
+ const char *b;
+
+ mMap.clear();
+
+ for (;;) {
+ // Find the bounds of the key name.
+ b = strchr(a, '=');
+ if (b == 0)
+ break;
+
+ // Create the key string.
+ String8 k(a, (size_t)(b-a));
+
+ // Find the value.
+ a = b+1;
+ b = strchr(a, ';');
+ if (b == 0) {
+ // If there's no semicolon, this is the last item.
+ String8 v(a);
+ mMap.add(k, v);
+ break;
+ }
+
+ String8 v(a, (size_t)(b-a));
+ mMap.add(k, v);
+ a = b+1;
+ }
+}
+
+
+void CameraParameters::set(const char *key, const char *value)
+{
+ // i think i can do this with strspn()
+ if (strchr(key, '=') || strchr(key, ';')) {
+ // ALOGE("Key \"%s\"contains invalid character (= or ;)", key);
+ return;
+ }
+
+ if (strchr(value, '=') || strchr(value, ';')) {
+ // ALOGE("Value \"%s\"contains invalid character (= or ;)", value);
+ return;
+ }
+
+ mMap.replaceValueFor(String8(key), String8(value));
+}
+
+void CameraParameters::set(const char *key, int value)
+{
+ char str[16];
+ sprintf(str, "%d", value);
+ set(key, str);
+}
+
+void CameraParameters::setFloat(const char *key, float value)
+{
+ char str[16]; // 14 should be enough. We overestimate to be safe.
+ snprintf(str, sizeof(str), "%g", value);
+ set(key, str);
+}
+
+const char *CameraParameters::get(const char *key) const
+{
+ String8 v = mMap.valueFor(String8(key));
+ if (v.length() == 0)
+ return 0;
+ return v.string();
+}
+
+int CameraParameters::getInt(const char *key) const
+{
+ const char *v = get(key);
+ if (v == 0)
+ return -1;
+ return strtol(v, 0, 0);
+}
+
+float CameraParameters::getFloat(const char *key) const
+{
+ const char *v = get(key);
+ if (v == 0) return -1;
+ return strtof(v, 0);
+}
+
+void CameraParameters::remove(const char *key)
+{
+ mMap.removeItem(String8(key));
+}
+
+// Parse string like "640x480" or "10000,20000"
+static int parse_pair(const char *str, int *first, int *second, char delim,
+ char **endptr = NULL)
+{
+ // Find the first integer.
+ char *end;
+ int w = (int)strtol(str, &end, 10);
+ // If a delimeter does not immediately follow, give up.
+ if (*end != delim) {
+ ALOGE("Cannot find delimeter (%c) in str=%s", delim, str);
+ return -1;
+ }
+
+ // Find the second integer, immediately after the delimeter.
+ int h = (int)strtol(end+1, &end, 10);
+
+ *first = w;
+ *second = h;
+
+ if (endptr) {
+ *endptr = end;
+ }
+
+ return 0;
+}
+
+static void parseSizesList(const char *sizesStr, Vector<Size> &sizes)
+{
+ if (sizesStr == 0) {
+ return;
+ }
+
+ char *sizeStartPtr = (char *)sizesStr;
+
+ while (true) {
+ int width, height;
+ int success = parse_pair(sizeStartPtr, &width, &height, 'x',
+ &sizeStartPtr);
+ if (success == -1 || (*sizeStartPtr != ',' && *sizeStartPtr != '\0')) {
+ ALOGE("Picture sizes string \"%s\" contains invalid character.", sizesStr);
+ return;
+ }
+ sizes.push(Size(width, height));
+
+ if (*sizeStartPtr == '\0') {
+ return;
+ }
+ sizeStartPtr++;
+ }
+}
+
+void CameraParameters::setPreviewSize(int width, int height)
+{
+ char str[32];
+ sprintf(str, "%dx%d", width, height);
+ set(KEY_PREVIEW_SIZE, str);
+}
+
+void CameraParameters::getPreviewSize(int *width, int *height) const
+{
+ *width = *height = -1;
+ // Get the current string, if it doesn't exist, leave the -1x-1
+ const char *p = get(KEY_PREVIEW_SIZE);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters::getPreferredPreviewSizeForVideo(int *width, int *height) const
+{
+ *width = *height = -1;
+ const char *p = get(KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters::getSupportedPreviewSizes(Vector<Size> &sizes) const
+{
+ const char *previewSizesStr = get(KEY_SUPPORTED_PREVIEW_SIZES);
+ parseSizesList(previewSizesStr, sizes);
+}
+
+void CameraParameters::setVideoSize(int width, int height)
+{
+ char str[32];
+ sprintf(str, "%dx%d", width, height);
+ set(KEY_VIDEO_SIZE, str);
+}
+
+void CameraParameters::getVideoSize(int *width, int *height) const
+{
+ *width = *height = -1;
+ const char *p = get(KEY_VIDEO_SIZE);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters::getSupportedVideoSizes(Vector<Size> &sizes) const
+{
+ const char *videoSizesStr = get(KEY_SUPPORTED_VIDEO_SIZES);
+ parseSizesList(videoSizesStr, sizes);
+}
+
+void CameraParameters::setPreviewFrameRate(int fps)
+{
+ set(KEY_PREVIEW_FRAME_RATE, fps);
+}
+
+int CameraParameters::getPreviewFrameRate() const
+{
+ return getInt(KEY_PREVIEW_FRAME_RATE);
+}
+
+void CameraParameters::getPreviewFpsRange(int *min_fps, int *max_fps) const
+{
+ *min_fps = *max_fps = -1;
+ const char *p = get(KEY_PREVIEW_FPS_RANGE);
+ if (p == 0) return;
+ parse_pair(p, min_fps, max_fps, ',');
+}
+
+void CameraParameters::setPreviewFormat(const char *format)
+{
+ set(KEY_PREVIEW_FORMAT, format);
+}
+
+const char *CameraParameters::getPreviewFormat() const
+{
+ return get(KEY_PREVIEW_FORMAT);
+}
+
+void CameraParameters::setPictureSize(int width, int height)
+{
+ char str[32];
+ sprintf(str, "%dx%d", width, height);
+ set(KEY_PICTURE_SIZE, str);
+}
+
+void CameraParameters::getPictureSize(int *width, int *height) const
+{
+ *width = *height = -1;
+ // Get the current string, if it doesn't exist, leave the -1x-1
+ const char *p = get(KEY_PICTURE_SIZE);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters::getSupportedPictureSizes(Vector<Size> &sizes) const
+{
+ const char *pictureSizesStr = get(KEY_SUPPORTED_PICTURE_SIZES);
+ parseSizesList(pictureSizesStr, sizes);
+}
+
+void CameraParameters::setPictureFormat(const char *format)
+{
+ set(KEY_PICTURE_FORMAT, format);
+}
+
+const char *CameraParameters::getPictureFormat() const
+{
+ return get(KEY_PICTURE_FORMAT);
+}
+
+void CameraParameters::dump() const
+{
+ ALOGD("dump: mMap.size = %zu", mMap.size());
+ for (size_t i = 0; i < mMap.size(); i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+ ALOGD("%s: %s\n", k.string(), v.string());
+ }
+}
+
+status_t CameraParameters::dump(int fd, const Vector<String16>& /*args*/) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, 255, "CameraParameters::dump: mMap.size = %zu\n", mMap.size());
+ result.append(buffer);
+ for (size_t i = 0; i < mMap.size(); i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+ snprintf(buffer, 255, "\t%s: %s\n", k.string(), v.string());
+ result.append(buffer);
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+void CameraParameters::getSupportedPreviewFormats(Vector<int>& formats) const {
+ const char* supportedPreviewFormats =
+ get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS);
+
+ if (supportedPreviewFormats == NULL) {
+ ALOGW("%s: No supported preview formats.", __FUNCTION__);
+ return;
+ }
+
+ String8 fmtStr(supportedPreviewFormats);
+ char* prevFmts = fmtStr.lockBuffer(fmtStr.size());
+
+ char* savePtr;
+ char* fmt = strtok_r(prevFmts, ",", &savePtr);
+ while (fmt) {
+ int actual = previewFormatToEnum(fmt);
+ if (actual != -1) {
+ formats.add(actual);
+ }
+ fmt = strtok_r(NULL, ",", &savePtr);
+ }
+ fmtStr.unlockBuffer(fmtStr.size());
+}
+
+
+int CameraParameters::previewFormatToEnum(const char* format) {
+ return
+ !format ?
+ HAL_PIXEL_FORMAT_YCrCb_420_SP :
+ !strcmp(format, PIXEL_FORMAT_YUV422SP) ?
+ HAL_PIXEL_FORMAT_YCbCr_422_SP : // NV16
+ !strcmp(format, PIXEL_FORMAT_YUV420SP) ?
+ HAL_PIXEL_FORMAT_YCrCb_420_SP : // NV21
+ !strcmp(format, PIXEL_FORMAT_YUV422I) ?
+ HAL_PIXEL_FORMAT_YCbCr_422_I : // YUY2
+ !strcmp(format, PIXEL_FORMAT_YUV420P) ?
+ HAL_PIXEL_FORMAT_YV12 : // YV12
+ !strcmp(format, PIXEL_FORMAT_RGB565) ?
+ HAL_PIXEL_FORMAT_RGB_565 : // RGB565
+ !strcmp(format, PIXEL_FORMAT_RGBA8888) ?
+ HAL_PIXEL_FORMAT_RGBA_8888 : // RGB8888
+ !strcmp(format, PIXEL_FORMAT_BAYER_RGGB) ?
+ HAL_PIXEL_FORMAT_RAW16 : // Raw sensor data
+ -1;
+}
+
+bool CameraParameters::isEmpty() const {
+ return mMap.isEmpty();
+}
+
+}; // namespace android
diff --git a/camera/provider/2.4/vts/functional/CameraParameters.h b/camera/provider/2.4/vts/functional/CameraParameters.h
new file mode 100644
index 0000000..ba33ffe
--- /dev/null
+++ b/camera/provider/2.4/vts/functional/CameraParameters.h
@@ -0,0 +1,699 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_PARAMETERS_H
+#define ANDROID_HARDWARE_CAMERA_PARAMETERS_H
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
+namespace android {
+
+struct Size {
+ int width;
+ int height;
+
+ Size() {
+ width = 0;
+ height = 0;
+ }
+
+ Size(int w, int h) {
+ width = w;
+ height = h;
+ }
+};
+
+class CameraParameters
+{
+public:
+ CameraParameters();
+ CameraParameters(const String8 ¶ms) { unflatten(params); }
+ ~CameraParameters();
+
+ String8 flatten() const;
+ void unflatten(const String8 ¶ms);
+
+ void set(const char *key, const char *value);
+ void set(const char *key, int value);
+ void setFloat(const char *key, float value);
+ const char *get(const char *key) const;
+ int getInt(const char *key) const;
+ float getFloat(const char *key) const;
+
+ void remove(const char *key);
+
+ void setPreviewSize(int width, int height);
+ void getPreviewSize(int *width, int *height) const;
+ void getSupportedPreviewSizes(Vector<Size> &sizes) const;
+
+ // Set the dimensions in pixels to the given width and height
+ // for video frames. The given width and height must be one
+ // of the supported dimensions returned from
+ // getSupportedVideoSizes(). Must not be called if
+ // getSupportedVideoSizes() returns an empty Vector of Size.
+ void setVideoSize(int width, int height);
+ // Retrieve the current dimensions (width and height)
+ // in pixels for video frames, which must be one of the
+ // supported dimensions returned from getSupportedVideoSizes().
+ // Must not be called if getSupportedVideoSizes() returns an
+ // empty Vector of Size.
+ void getVideoSize(int *width, int *height) const;
+ // Retrieve a Vector of supported dimensions (width and height)
+ // in pixels for video frames. If sizes returned from the method
+ // is empty, the camera does not support calls to setVideoSize()
+ // or getVideoSize(). In adddition, it also indicates that
+ // the camera only has a single output, and does not have
+ // separate output for video frames and preview frame.
+ void getSupportedVideoSizes(Vector<Size> &sizes) const;
+ // Retrieve the preferred preview size (width and height) in pixels
+ // for video recording. The given width and height must be one of
+ // supported preview sizes returned from getSupportedPreviewSizes().
+ // Must not be called if getSupportedVideoSizes() returns an empty
+ // Vector of Size. If getSupportedVideoSizes() returns an empty
+ // Vector of Size, the width and height returned from this method
+ // is invalid, and is "-1x-1".
+ void getPreferredPreviewSizeForVideo(int *width, int *height) const;
+
+ void setPreviewFrameRate(int fps);
+ int getPreviewFrameRate() const;
+ void getPreviewFpsRange(int *min_fps, int *max_fps) const;
+ void setPreviewFormat(const char *format);
+ const char *getPreviewFormat() const;
+ void setPictureSize(int width, int height);
+ void getPictureSize(int *width, int *height) const;
+ void getSupportedPictureSizes(Vector<Size> &sizes) const;
+ void setPictureFormat(const char *format);
+ const char *getPictureFormat() const;
+
+ void dump() const;
+ status_t dump(int fd, const Vector<String16>& args) const;
+
+ /**
+ * Returns a Vector containing the supported preview formats
+ * as enums given in graphics.h.
+ */
+ void getSupportedPreviewFormats(Vector<int>& formats) const;
+
+ // Returns true if no keys are present
+ bool isEmpty() const;
+
+ // Parameter keys to communicate between camera application and driver.
+ // The access (read/write, read only, or write only) is viewed from the
+ // perspective of applications, not driver.
+
+ // Preview frame size in pixels (width x height).
+ // Example value: "480x320". Read/Write.
+ static const char KEY_PREVIEW_SIZE[];
+ // Supported preview frame sizes in pixels.
+ // Example value: "800x600,480x320". Read only.
+ static const char KEY_SUPPORTED_PREVIEW_SIZES[];
+ // The current minimum and maximum preview fps. This controls the rate of
+ // preview frames received (CAMERA_MSG_PREVIEW_FRAME). The minimum and
+ // maximum fps must be one of the elements from
+ // KEY_SUPPORTED_PREVIEW_FPS_RANGE parameter.
+ // Example value: "10500,26623"
+ static const char KEY_PREVIEW_FPS_RANGE[];
+ // The supported preview fps (frame-per-second) ranges. Each range contains
+ // a minimum fps and maximum fps. If minimum fps equals to maximum fps, the
+ // camera outputs frames in fixed frame rate. If not, the camera outputs
+ // frames in auto frame rate. The actual frame rate fluctuates between the
+ // minimum and the maximum. The list has at least one element. The list is
+ // sorted from small to large (first by maximum fps and then minimum fps).
+ // Example value: "(10500,26623),(15000,26623),(30000,30000)"
+ static const char KEY_SUPPORTED_PREVIEW_FPS_RANGE[];
+ // The image format for preview frames. See CAMERA_MSG_PREVIEW_FRAME in
+ // frameworks/av/include/camera/Camera.h. The default is
+ // PIXEL_FORMAT_YUV420SP. Example value: "yuv420sp" or PIXEL_FORMAT_XXX
+ // constants. Read/write.
+ static const char KEY_PREVIEW_FORMAT[];
+ // Supported image formats for preview frames.
+ // Example value: "yuv420sp,yuv422i-yuyv". Read only.
+ static const char KEY_SUPPORTED_PREVIEW_FORMATS[];
+ // Number of preview frames per second. This is the target frame rate. The
+ // actual frame rate depends on the driver.
+ // Example value: "15". Read/write.
+ static const char KEY_PREVIEW_FRAME_RATE[];
+ // Supported number of preview frames per second.
+ // Example value: "24,15,10". Read.
+ static const char KEY_SUPPORTED_PREVIEW_FRAME_RATES[];
+ // The dimensions for captured pictures in pixels (width x height).
+ // Example value: "1024x768". Read/write.
+ static const char KEY_PICTURE_SIZE[];
+ // Supported dimensions for captured pictures in pixels.
+ // Example value: "2048x1536,1024x768". Read only.
+ static const char KEY_SUPPORTED_PICTURE_SIZES[];
+ // The image format for captured pictures. See CAMERA_MSG_COMPRESSED_IMAGE
+ // in frameworks/base/include/camera/Camera.h.
+ // Example value: "jpeg" or PIXEL_FORMAT_XXX constants. Read/write.
+ static const char KEY_PICTURE_FORMAT[];
+ // Supported image formats for captured pictures.
+ // Example value: "jpeg,rgb565". Read only.
+ static const char KEY_SUPPORTED_PICTURE_FORMATS[];
+ // The width (in pixels) of EXIF thumbnail in Jpeg picture.
+ // Example value: "512". Read/write.
+ static const char KEY_JPEG_THUMBNAIL_WIDTH[];
+ // The height (in pixels) of EXIF thumbnail in Jpeg picture.
+ // Example value: "384". Read/write.
+ static const char KEY_JPEG_THUMBNAIL_HEIGHT[];
+ // Supported EXIF thumbnail sizes (width x height). 0x0 means not thumbnail
+ // in EXIF.
+ // Example value: "512x384,320x240,0x0". Read only.
+ static const char KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[];
+ // The quality of the EXIF thumbnail in Jpeg picture. The range is 1 to 100,
+ // with 100 being the best.
+ // Example value: "90". Read/write.
+ static const char KEY_JPEG_THUMBNAIL_QUALITY[];
+ // Jpeg quality of captured picture. The range is 1 to 100, with 100 being
+ // the best.
+ // Example value: "90". Read/write.
+ static const char KEY_JPEG_QUALITY[];
+ // The rotation angle in degrees relative to the orientation of the camera.
+ // This affects the pictures returned from CAMERA_MSG_COMPRESSED_IMAGE. The
+ // camera driver may set orientation in the EXIF header without rotating the
+ // picture. Or the driver may rotate the picture and the EXIF thumbnail. If
+ // the Jpeg picture is rotated, the orientation in the EXIF header will be
+ // missing or 1 (row #0 is top and column #0 is left side).
+ //
+ // Note that the JPEG pictures of front-facing cameras are not mirrored
+ // as in preview display.
+ //
+ // For example, suppose the natural orientation of the device is portrait.
+ // The device is rotated 270 degrees clockwise, so the device orientation is
+ // 270. Suppose a back-facing camera sensor is mounted in landscape and the
+ // top side of the camera sensor is aligned with the right edge of the
+ // display in natural orientation. So the camera orientation is 90. The
+ // rotation should be set to 0 (270 + 90).
+ //
+ // Example value: "0" or "90" or "180" or "270". Write only.
+ static const char KEY_ROTATION[];
+ // GPS latitude coordinate. GPSLatitude and GPSLatitudeRef will be stored in
+ // JPEG EXIF header.
+ // Example value: "25.032146" or "-33.462809". Write only.
+ static const char KEY_GPS_LATITUDE[];
+ // GPS longitude coordinate. GPSLongitude and GPSLongitudeRef will be stored
+ // in JPEG EXIF header.
+ // Example value: "121.564448" or "-70.660286". Write only.
+ static const char KEY_GPS_LONGITUDE[];
+ // GPS altitude. GPSAltitude and GPSAltitudeRef will be stored in JPEG EXIF
+ // header.
+ // Example value: "21.0" or "-5". Write only.
+ static const char KEY_GPS_ALTITUDE[];
+ // GPS timestamp (UTC in seconds since January 1, 1970). This should be
+ // stored in JPEG EXIF header.
+ // Example value: "1251192757". Write only.
+ static const char KEY_GPS_TIMESTAMP[];
+ // GPS Processing Method
+ // Example value: "GPS" or "NETWORK". Write only.
+ static const char KEY_GPS_PROCESSING_METHOD[];
+ // Current white balance setting.
+ // Example value: "auto" or WHITE_BALANCE_XXX constants. Read/write.
+ static const char KEY_WHITE_BALANCE[];
+ // Supported white balance settings.
+ // Example value: "auto,incandescent,daylight". Read only.
+ static const char KEY_SUPPORTED_WHITE_BALANCE[];
+ // Current color effect setting.
+ // Example value: "none" or EFFECT_XXX constants. Read/write.
+ static const char KEY_EFFECT[];
+ // Supported color effect settings.
+ // Example value: "none,mono,sepia". Read only.
+ static const char KEY_SUPPORTED_EFFECTS[];
+ // Current antibanding setting.
+ // Example value: "auto" or ANTIBANDING_XXX constants. Read/write.
+ static const char KEY_ANTIBANDING[];
+ // Supported antibanding settings.
+ // Example value: "auto,50hz,60hz,off". Read only.
+ static const char KEY_SUPPORTED_ANTIBANDING[];
+ // Current scene mode.
+ // Example value: "auto" or SCENE_MODE_XXX constants. Read/write.
+ static const char KEY_SCENE_MODE[];
+ // Supported scene mode settings.
+ // Example value: "auto,night,fireworks". Read only.
+ static const char KEY_SUPPORTED_SCENE_MODES[];
+ // Current flash mode.
+ // Example value: "auto" or FLASH_MODE_XXX constants. Read/write.
+ static const char KEY_FLASH_MODE[];
+ // Supported flash modes.
+ // Example value: "auto,on,off". Read only.
+ static const char KEY_SUPPORTED_FLASH_MODES[];
+ // Current focus mode. This will not be empty. Applications should call
+ // CameraHardwareInterface.autoFocus to start the focus if focus mode is
+ // FOCUS_MODE_AUTO or FOCUS_MODE_MACRO.
+ // Example value: "auto" or FOCUS_MODE_XXX constants. Read/write.
+ static const char KEY_FOCUS_MODE[];
+ // Supported focus modes.
+ // Example value: "auto,macro,fixed". Read only.
+ static const char KEY_SUPPORTED_FOCUS_MODES[];
+ // The maximum number of focus areas supported. This is the maximum length
+ // of KEY_FOCUS_AREAS.
+ // Example value: "0" or "2". Read only.
+ static const char KEY_MAX_NUM_FOCUS_AREAS[];
+ // Current focus areas.
+ //
+ // Before accessing this parameter, apps should check
+ // KEY_MAX_NUM_FOCUS_AREAS first to know the maximum number of focus areas
+ // first. If the value is 0, focus area is not supported.
+ //
+ // Each focus area is a five-element int array. The first four elements are
+ // the rectangle of the area (left, top, right, bottom). The direction is
+ // relative to the sensor orientation, that is, what the sensor sees. The
+ // direction is not affected by the rotation or mirroring of
+ // CAMERA_CMD_SET_DISPLAY_ORIENTATION. Coordinates range from -1000 to 1000.
+ // (-1000,-1000) is the upper left point. (1000, 1000) is the lower right
+ // point. The width and height of focus areas cannot be 0 or negative.
+ //
+ // The fifth element is the weight. Values for weight must range from 1 to
+ // 1000. The weight should be interpreted as a per-pixel weight - all
+ // pixels in the area have the specified weight. This means a small area
+ // with the same weight as a larger area will have less influence on the
+ // focusing than the larger area. Focus areas can partially overlap and the
+ // driver will add the weights in the overlap region.
+ //
+ // A special case of single focus area (0,0,0,0,0) means driver to decide
+ // the focus area. For example, the driver may use more signals to decide
+ // focus areas and change them dynamically. Apps can set (0,0,0,0,0) if they
+ // want the driver to decide focus areas.
+ //
+ // Focus areas are relative to the current field of view (KEY_ZOOM). No
+ // matter what the zoom level is, (-1000,-1000) represents the top of the
+ // currently visible camera frame. The focus area cannot be set to be
+ // outside the current field of view, even when using zoom.
+ //
+ // Focus area only has effect if the current focus mode is FOCUS_MODE_AUTO,
+ // FOCUS_MODE_MACRO, FOCUS_MODE_CONTINUOUS_VIDEO, or
+ // FOCUS_MODE_CONTINUOUS_PICTURE.
+ // Example value: "(-10,-10,0,0,300),(0,0,10,10,700)". Read/write.
+ static const char KEY_FOCUS_AREAS[];
+ // Focal length in millimeter.
+ // Example value: "4.31". Read only.
+ static const char KEY_FOCAL_LENGTH[];
+ // Horizontal angle of view in degrees.
+ // Example value: "54.8". Read only.
+ static const char KEY_HORIZONTAL_VIEW_ANGLE[];
+ // Vertical angle of view in degrees.
+ // Example value: "42.5". Read only.
+ static const char KEY_VERTICAL_VIEW_ANGLE[];
+ // Exposure compensation index. 0 means exposure is not adjusted.
+ // Example value: "-5" or "5". Read/write.
+ static const char KEY_EXPOSURE_COMPENSATION[];
+ // The maximum exposure compensation index (>=0).
+ // Example value: "6". Read only.
+ static const char KEY_MAX_EXPOSURE_COMPENSATION[];
+ // The minimum exposure compensation index (<=0).
+ // Example value: "-6". Read only.
+ static const char KEY_MIN_EXPOSURE_COMPENSATION[];
+ // The exposure compensation step. Exposure compensation index multiply by
+ // step eqals to EV. Ex: if exposure compensation index is -6 and step is
+ // 0.3333, EV is -2.
+ // Example value: "0.333333333" or "0.5". Read only.
+ static const char KEY_EXPOSURE_COMPENSATION_STEP[];
+ // The state of the auto-exposure lock. "true" means that
+ // auto-exposure is locked to its current value and will not
+ // change. "false" means the auto-exposure routine is free to
+ // change exposure values. If auto-exposure is already locked,
+ // setting this to true again has no effect (the driver will not
+ // recalculate exposure values). Changing exposure compensation
+ // settings will still affect the exposure settings while
+ // auto-exposure is locked. Stopping preview or taking a still
+ // image will not change the lock. In conjunction with
+ // exposure compensation, this allows for capturing multi-exposure
+ // brackets with known relative exposure values. Locking
+ // auto-exposure after open but before the first call to
+ // startPreview may result in severely over- or under-exposed
+ // images. The driver will not change the AE lock after
+ // auto-focus completes.
+ static const char KEY_AUTO_EXPOSURE_LOCK[];
+ // Whether locking the auto-exposure is supported. "true" means it is, and
+ // "false" or this key not existing means it is not supported.
+ static const char KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[];
+ // The state of the auto-white balance lock. "true" means that
+ // auto-white balance is locked to its current value and will not
+ // change. "false" means the auto-white balance routine is free to
+ // change white balance values. If auto-white balance is already
+ // locked, setting this to true again has no effect (the driver
+ // will not recalculate white balance values). Stopping preview or
+ // taking a still image will not change the lock. In conjunction
+ // with exposure compensation, this allows for capturing
+ // multi-exposure brackets with fixed white balance. Locking
+ // auto-white balance after open but before the first call to
+ // startPreview may result in severely incorrect color. The
+ // driver will not change the AWB lock after auto-focus
+ // completes.
+ static const char KEY_AUTO_WHITEBALANCE_LOCK[];
+ // Whether locking the auto-white balance is supported. "true"
+ // means it is, and "false" or this key not existing means it is
+ // not supported.
+ static const char KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[];
+
+ // The maximum number of metering areas supported. This is the maximum
+ // length of KEY_METERING_AREAS.
+ // Example value: "0" or "2". Read only.
+ static const char KEY_MAX_NUM_METERING_AREAS[];
+ // Current metering areas. Camera driver uses these areas to decide
+ // exposure.
+ //
+ // Before accessing this parameter, apps should check
+ // KEY_MAX_NUM_METERING_AREAS first to know the maximum number of metering
+ // areas first. If the value is 0, metering area is not supported.
+ //
+ // Each metering area is a rectangle with specified weight. The direction is
+ // relative to the sensor orientation, that is, what the sensor sees. The
+ // direction is not affected by the rotation or mirroring of
+ // CAMERA_CMD_SET_DISPLAY_ORIENTATION. Coordinates of the rectangle range
+ // from -1000 to 1000. (-1000, -1000) is the upper left point. (1000, 1000)
+ // is the lower right point. The width and height of metering areas cannot
+ // be 0 or negative.
+ //
+ // The fifth element is the weight. Values for weight must range from 1 to
+ // 1000. The weight should be interpreted as a per-pixel weight - all
+ // pixels in the area have the specified weight. This means a small area
+ // with the same weight as a larger area will have less influence on the
+ // metering than the larger area. Metering areas can partially overlap and
+ // the driver will add the weights in the overlap region.
+ //
+ // A special case of all-zero single metering area means driver to decide
+ // the metering area. For example, the driver may use more signals to decide
+ // metering areas and change them dynamically. Apps can set all-zero if they
+ // want the driver to decide metering areas.
+ //
+ // Metering areas are relative to the current field of view (KEY_ZOOM).
+ // No matter what the zoom level is, (-1000,-1000) represents the top of the
+ // currently visible camera frame. The metering area cannot be set to be
+ // outside the current field of view, even when using zoom.
+ //
+ // No matter what metering areas are, the final exposure are compensated
+ // by KEY_EXPOSURE_COMPENSATION.
+ // Example value: "(-10,-10,0,0,300),(0,0,10,10,700)". Read/write.
+ static const char KEY_METERING_AREAS[];
+ // Current zoom value.
+ // Example value: "0" or "6". Read/write.
+ static const char KEY_ZOOM[];
+ // Maximum zoom value.
+ // Example value: "6". Read only.
+ static const char KEY_MAX_ZOOM[];
+ // The zoom ratios of all zoom values. The zoom ratio is in 1/100
+ // increments. Ex: a zoom of 3.2x is returned as 320. The number of list
+ // elements is KEY_MAX_ZOOM + 1. The first element is always 100. The last
+ // element is the zoom ratio of zoom value KEY_MAX_ZOOM.
+ // Example value: "100,150,200,250,300,350,400". Read only.
+ static const char KEY_ZOOM_RATIOS[];
+ // Whether zoom is supported. Zoom is supported if the value is "true". Zoom
+ // is not supported if the value is not "true" or the key does not exist.
+ // Example value: "true". Read only.
+ static const char KEY_ZOOM_SUPPORTED[];
+ // Whether if smooth zoom is supported. Smooth zoom is supported if the
+ // value is "true". It is not supported if the value is not "true" or the
+ // key does not exist.
+ // See CAMERA_CMD_START_SMOOTH_ZOOM, CAMERA_CMD_STOP_SMOOTH_ZOOM, and
+ // CAMERA_MSG_ZOOM in frameworks/base/include/camera/Camera.h.
+ // Example value: "true". Read only.
+ static const char KEY_SMOOTH_ZOOM_SUPPORTED[];
+
+ // The distances (in meters) from the camera to where an object appears to
+ // be in focus. The object is sharpest at the optimal focus distance. The
+ // depth of field is the far focus distance minus near focus distance.
+ //
+ // Focus distances may change after starting auto focus, canceling auto
+ // focus, or starting the preview. Applications can read this anytime to get
+ // the latest focus distances. If the focus mode is FOCUS_MODE_CONTINUOUS,
+ // focus distances may change from time to time.
+ //
+ // This is intended to estimate the distance between the camera and the
+ // subject. After autofocus, the subject distance may be within near and far
+ // focus distance. However, the precision depends on the camera hardware,
+ // autofocus algorithm, the focus area, and the scene. The error can be
+ // large and it should be only used as a reference.
+ //
+ // Far focus distance > optimal focus distance > near focus distance. If
+ // the far focus distance is infinity, the value should be "Infinity" (case
+ // sensitive). The format is three float values separated by commas. The
+ // first is near focus distance. The second is optimal focus distance. The
+ // third is far focus distance.
+ // Example value: "0.95,1.9,Infinity" or "0.049,0.05,0.051". Read only.
+ static const char KEY_FOCUS_DISTANCES[];
+
+ // The current dimensions in pixels (width x height) for video frames.
+ // The width and height must be one of the supported sizes retrieved
+ // via KEY_SUPPORTED_VIDEO_SIZES.
+ // Example value: "1280x720". Read/write.
+ static const char KEY_VIDEO_SIZE[];
+ // A list of the supported dimensions in pixels (width x height)
+ // for video frames. See CAMERA_MSG_VIDEO_FRAME for details in
+ // frameworks/base/include/camera/Camera.h.
+ // Example: "176x144,1280x720". Read only.
+ static const char KEY_SUPPORTED_VIDEO_SIZES[];
+
+ // The maximum number of detected faces supported by hardware face
+ // detection. If the value is 0, hardware face detection is not supported.
+ // Example: "5". Read only
+ static const char KEY_MAX_NUM_DETECTED_FACES_HW[];
+
+ // The maximum number of detected faces supported by software face
+ // detection. If the value is 0, software face detection is not supported.
+ // Example: "5". Read only
+ static const char KEY_MAX_NUM_DETECTED_FACES_SW[];
+
+ // Preferred preview frame size in pixels for video recording.
+ // The width and height must be one of the supported sizes retrieved
+ // via KEY_SUPPORTED_PREVIEW_SIZES. This key can be used only when
+ // getSupportedVideoSizes() does not return an empty Vector of Size.
+ // Camcorder applications are recommended to set the preview size
+ // to a value that is not larger than the preferred preview size.
+ // In other words, the product of the width and height of the
+ // preview size should not be larger than that of the preferred
+ // preview size. In addition, we recommend to choos a preview size
+ // that has the same aspect ratio as the resolution of video to be
+ // recorded.
+ // Example value: "800x600". Read only.
+ static const char KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[];
+
+ // The image format for video frames. See CAMERA_MSG_VIDEO_FRAME in
+ // frameworks/base/include/camera/Camera.h.
+ // Example value: "yuv420sp" or PIXEL_FORMAT_XXX constants. Read only.
+ static const char KEY_VIDEO_FRAME_FORMAT[];
+
+ // Sets the hint of the recording mode. If this is true, MediaRecorder.start
+ // may be faster or has less glitches. This should be called before starting
+ // the preview for the best result. But it is allowed to change the hint
+ // while the preview is active. The default value is false.
+ //
+ // The apps can still call Camera.takePicture when the hint is true. The
+ // apps can call MediaRecorder.start when the hint is false. But the
+ // performance may be worse.
+ // Example value: "true" or "false". Read/write.
+ static const char KEY_RECORDING_HINT[];
+
+ // Returns true if video snapshot is supported. That is, applications
+ // can call Camera.takePicture during recording. Applications do not need to
+ // call Camera.startPreview after taking a picture. The preview will be
+ // still active. Other than that, taking a picture during recording is
+ // identical to taking a picture normally. All settings and methods related
+ // to takePicture work identically. Ex: KEY_PICTURE_SIZE,
+ // KEY_SUPPORTED_PICTURE_SIZES, KEY_JPEG_QUALITY, KEY_ROTATION, and etc.
+ // The picture will have an EXIF header. FLASH_MODE_AUTO and FLASH_MODE_ON
+ // also still work, but the video will record the flash.
+ //
+ // Applications can set shutter callback as null to avoid the shutter
+ // sound. It is also recommended to set raw picture and post view callbacks
+ // to null to avoid the interrupt of preview display.
+ //
+ // Field-of-view of the recorded video may be different from that of the
+ // captured pictures.
+ // Example value: "true" or "false". Read only.
+ static const char KEY_VIDEO_SNAPSHOT_SUPPORTED[];
+
+ // The state of the video stabilization. If set to true, both the
+ // preview stream and the recorded video stream are stabilized by
+ // the camera. Only valid to set if KEY_VIDEO_STABILIZATION_SUPPORTED is
+ // set to true.
+ //
+ // The value of this key can be changed any time the camera is
+ // open. If preview or recording is active, it is acceptable for
+ // there to be a slight video glitch when video stabilization is
+ // toggled on and off.
+ //
+ // This only stabilizes video streams (between-frames stabilization), and
+ // has no effect on still image capture.
+ static const char KEY_VIDEO_STABILIZATION[];
+
+ // Returns true if video stabilization is supported. That is, applications
+ // can set KEY_VIDEO_STABILIZATION to true and have a stabilized preview
+ // stream and record stabilized videos.
+ static const char KEY_VIDEO_STABILIZATION_SUPPORTED[];
+
+ // Supported modes for special effects with light.
+ // Example values: "lowlight,hdr".
+ static const char KEY_LIGHTFX[];
+
+ // Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED.
+ static const char TRUE[];
+ static const char FALSE[];
+
+ // Value for KEY_FOCUS_DISTANCES.
+ static const char FOCUS_DISTANCE_INFINITY[];
+
+ // Values for white balance settings.
+ static const char WHITE_BALANCE_AUTO[];
+ static const char WHITE_BALANCE_INCANDESCENT[];
+ static const char WHITE_BALANCE_FLUORESCENT[];
+ static const char WHITE_BALANCE_WARM_FLUORESCENT[];
+ static const char WHITE_BALANCE_DAYLIGHT[];
+ static const char WHITE_BALANCE_CLOUDY_DAYLIGHT[];
+ static const char WHITE_BALANCE_TWILIGHT[];
+ static const char WHITE_BALANCE_SHADE[];
+
+ // Values for effect settings.
+ static const char EFFECT_NONE[];
+ static const char EFFECT_MONO[];
+ static const char EFFECT_NEGATIVE[];
+ static const char EFFECT_SOLARIZE[];
+ static const char EFFECT_SEPIA[];
+ static const char EFFECT_POSTERIZE[];
+ static const char EFFECT_WHITEBOARD[];
+ static const char EFFECT_BLACKBOARD[];
+ static const char EFFECT_AQUA[];
+
+ // Values for antibanding settings.
+ static const char ANTIBANDING_AUTO[];
+ static const char ANTIBANDING_50HZ[];
+ static const char ANTIBANDING_60HZ[];
+ static const char ANTIBANDING_OFF[];
+
+ // Values for flash mode settings.
+ // Flash will not be fired.
+ static const char FLASH_MODE_OFF[];
+ // Flash will be fired automatically when required. The flash may be fired
+ // during preview, auto-focus, or snapshot depending on the driver.
+ static const char FLASH_MODE_AUTO[];
+ // Flash will always be fired during snapshot. The flash may also be
+ // fired during preview or auto-focus depending on the driver.
+ static const char FLASH_MODE_ON[];
+ // Flash will be fired in red-eye reduction mode.
+ static const char FLASH_MODE_RED_EYE[];
+ // Constant emission of light during preview, auto-focus and snapshot.
+ // This can also be used for video recording.
+ static const char FLASH_MODE_TORCH[];
+
+ // Values for scene mode settings.
+ static const char SCENE_MODE_AUTO[];
+ static const char SCENE_MODE_ACTION[];
+ static const char SCENE_MODE_PORTRAIT[];
+ static const char SCENE_MODE_LANDSCAPE[];
+ static const char SCENE_MODE_NIGHT[];
+ static const char SCENE_MODE_NIGHT_PORTRAIT[];
+ static const char SCENE_MODE_THEATRE[];
+ static const char SCENE_MODE_BEACH[];
+ static const char SCENE_MODE_SNOW[];
+ static const char SCENE_MODE_SUNSET[];
+ static const char SCENE_MODE_STEADYPHOTO[];
+ static const char SCENE_MODE_FIREWORKS[];
+ static const char SCENE_MODE_SPORTS[];
+ static const char SCENE_MODE_PARTY[];
+ static const char SCENE_MODE_CANDLELIGHT[];
+ // Applications are looking for a barcode. Camera driver will be optimized
+ // for barcode reading.
+ static const char SCENE_MODE_BARCODE[];
+ // A high-dynamic range mode. In this mode, the HAL module will use a
+ // capture strategy that extends the dynamic range of the captured
+ // image in some fashion. Only the final image is returned.
+ static const char SCENE_MODE_HDR[];
+
+ // Pixel color formats for KEY_PREVIEW_FORMAT, KEY_PICTURE_FORMAT,
+ // and KEY_VIDEO_FRAME_FORMAT
+ static const char PIXEL_FORMAT_YUV422SP[];
+ static const char PIXEL_FORMAT_YUV420SP[]; // NV21
+ static const char PIXEL_FORMAT_YUV422I[]; // YUY2
+ static const char PIXEL_FORMAT_YUV420P[]; // YV12
+ static const char PIXEL_FORMAT_RGB565[];
+ static const char PIXEL_FORMAT_RGBA8888[];
+ static const char PIXEL_FORMAT_JPEG[];
+ // Raw bayer format used for images, which is 10 bit precision samples
+ // stored in 16 bit words. The filter pattern is RGGB.
+ static const char PIXEL_FORMAT_BAYER_RGGB[];
+ // Pixel format is not known to the framework
+ static const char PIXEL_FORMAT_ANDROID_OPAQUE[];
+
+ // Values for focus mode settings.
+ // Auto-focus mode. Applications should call
+ // CameraHardwareInterface.autoFocus to start the focus in this mode.
+ static const char FOCUS_MODE_AUTO[];
+ // Focus is set at infinity. Applications should not call
+ // CameraHardwareInterface.autoFocus in this mode.
+ static const char FOCUS_MODE_INFINITY[];
+ // Macro (close-up) focus mode. Applications should call
+ // CameraHardwareInterface.autoFocus to start the focus in this mode.
+ static const char FOCUS_MODE_MACRO[];
+ // Focus is fixed. The camera is always in this mode if the focus is not
+ // adjustable. If the camera has auto-focus, this mode can fix the
+ // focus, which is usually at hyperfocal distance. Applications should
+ // not call CameraHardwareInterface.autoFocus in this mode.
+ static const char FOCUS_MODE_FIXED[];
+ // Extended depth of field (EDOF). Focusing is done digitally and
+ // continuously. Applications should not call
+ // CameraHardwareInterface.autoFocus in this mode.
+ static const char FOCUS_MODE_EDOF[];
+ // Continuous auto focus mode intended for video recording. The camera
+ // continuously tries to focus. This is the best choice for video
+ // recording because the focus changes smoothly . Applications still can
+ // call CameraHardwareInterface.takePicture in this mode but the subject may
+ // not be in focus. Auto focus starts when the parameter is set.
+ //
+ // Applications can call CameraHardwareInterface.autoFocus in this mode. The
+ // focus callback will immediately return with a boolean that indicates
+ // whether the focus is sharp or not. The focus position is locked after
+ // autoFocus call. If applications want to resume the continuous focus,
+ // cancelAutoFocus must be called. Restarting the preview will not resume
+ // the continuous autofocus. To stop continuous focus, applications should
+ // change the focus mode to other modes.
+ static const char FOCUS_MODE_CONTINUOUS_VIDEO[];
+ // Continuous auto focus mode intended for taking pictures. The camera
+ // continuously tries to focus. The speed of focus change is more aggressive
+ // than FOCUS_MODE_CONTINUOUS_VIDEO. Auto focus starts when the parameter is
+ // set.
+ //
+ // Applications can call CameraHardwareInterface.autoFocus in this mode. If
+ // the autofocus is in the middle of scanning, the focus callback will
+ // return when it completes. If the autofocus is not scanning, focus
+ // callback will immediately return with a boolean that indicates whether
+ // the focus is sharp or not. The apps can then decide if they want to take
+ // a picture immediately or to change the focus mode to auto, and run a full
+ // autofocus cycle. The focus position is locked after autoFocus call. If
+ // applications want to resume the continuous focus, cancelAutoFocus must be
+ // called. Restarting the preview will not resume the continuous autofocus.
+ // To stop continuous focus, applications should change the focus mode to
+ // other modes.
+ static const char FOCUS_MODE_CONTINUOUS_PICTURE[];
+
+ // Values for light special effects
+ // Low-light enhancement mode
+ static const char LIGHTFX_LOWLIGHT[];
+ // High-dynamic range mode
+ static const char LIGHTFX_HDR[];
+
+ /**
+ * Returns the the supported preview formats as an enum given in graphics.h
+ * corrsponding to the format given in the input string or -1 if no such
+ * conversion exists.
+ */
+ static int previewFormatToEnum(const char* format);
+
+private:
+ DefaultKeyedVector<String8,String8> mMap;
+};
+
+}; // namespace android
+
+#endif
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index ce195f8..598127f 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -17,9 +17,16 @@
#define LOG_TAG "camera_hidl_hal_test"
#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/hardware/camera/device/1.0/ICameraDevice.h>
+#include "CameraParameters.h"
+#include <system/camera.h>
#include <android/log.h>
#include <ui/GraphicBuffer.h>
#include <VtsHalHidlTargetTestBase.h>
+#include <gui/BufferQueue.h>
+#include <gui/Surface.h>
+#include <gui/BufferItemConsumer.h>
+#include <binder/MemoryHeapBase.h>
#include <regex>
#include "system/camera_metadata.h"
#include <hardware/gralloc.h>
@@ -29,6 +36,7 @@
#include <condition_variable>
#include <chrono>
#include <inttypes.h>
+#include <utils/Errors.h>
using ::android::hardware::Return;
using ::android::hardware::Void;
@@ -36,14 +44,23 @@
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::sp;
+using ::android::wp;
using ::android::GraphicBuffer;
+using ::android::IGraphicBufferProducer;
+using ::android::IGraphicBufferConsumer;
+using ::android::BufferQueue;
+using ::android::BufferItemConsumer;
+using ::android::Surface;
+using ::android::CameraParameters;
using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::graphics::allocator::V2_0::ProducerUsage;
using ::android::hardware::camera::common::V1_0::Status;
using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
using ::android::hardware::camera::common::V1_0::TorchMode;
using ::android::hardware::camera::common::V1_0::TorchModeStatus;
using ::android::hardware::camera::provider::V2_4::ICameraProvider;
using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
+using ::android::hardware::camera::device::V3_2::ICameraDevice;
using ::android::hardware::camera::device::V3_2::CaptureRequest;
using ::android::hardware::camera::device::V3_2::CaptureResult;
using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback;
@@ -59,14 +76,27 @@
using ::android::hardware::camera::device::V3_2::HalStreamConfiguration;
using ::android::hardware::camera::device::V3_2::BufferStatus;
using ::android::hardware::camera::device::V3_2::StreamBuffer;
+using ::android::hardware::camera::device::V3_2::MsgType;
+using ::android::hardware::camera::device::V3_2::ErrorMsg;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
+using ::android::hardware::camera::device::V1_0::CameraFacing;
+using ::android::hardware::camera::device::V1_0::NotifyCallbackMsg;
+using ::android::hardware::camera::device::V1_0::CommandType;
+using ::android::hardware::camera::device::V1_0::DataCallbackMsg;
+using ::android::hardware::camera::device::V1_0::CameraFrameMetadata;
+using ::android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback;
+using ::android::hardware::camera::device::V1_0::FrameCallbackFlag;
-#define CAMERA_PASSTHROUGH_SERVICE_NAME "legacy/0"
-#define MAX_PREVIEW_WIDTH 1920
-#define MAX_PREVIEW_HEIGHT 1080
-#define MAX_VIDEO_WIDTH 4096
-#define MAX_VIDEO_HEIGHT 2160
-#define STREAM_BUFFER_TIMEOUT 3 // sec.
-#define DUMP_OUTPUT "/dev/null"
+const char kCameraPassthroughServiceName[] = "legacy/0";
+const uint32_t kMaxPreviewWidth = 1920;
+const uint32_t kMaxPreviewHeight = 1080;
+const uint32_t kMaxVideoWidth = 4096;
+const uint32_t kMaxVideoHeight = 2160;
+const int64_t kStreamBufferTimeoutSec = 3;
+const int64_t kAutoFocusTimeoutSec = 5;
+const int64_t kTorchTimeoutSec = 1;
+const int64_t kEmptyFlushTimeoutMSec = 200;
+const char kDumpOutput[] = "/dev/null";
struct AvailableStream {
int32_t width;
@@ -99,14 +129,36 @@
if (!match) {
return -1;
}
- if (sm[1].compare(kHAL3_2) == 0) {
+ std::string version = sm[1].str();
+ if (version.compare(kHAL3_2) == 0) {
// maybe switched to 3.4 or define the hidl version enumlater
return CAMERA_DEVICE_API_VERSION_3_2;
- } else if (sm[1].compare(kHAL1_0) == 0) {
+ } else if (version.compare(kHAL1_0) == 0) {
return CAMERA_DEVICE_API_VERSION_1_0;
}
return 0;
}
+
+ Status mapToStatus(::android::status_t s) {
+ switch(s) {
+ case ::android::OK:
+ return Status::OK ;
+ case ::android::BAD_VALUE:
+ return Status::ILLEGAL_ARGUMENT ;
+ case -EBUSY:
+ return Status::CAMERA_IN_USE;
+ case -EUSERS:
+ return Status::MAX_CAMERAS_IN_USE;
+ case ::android::UNKNOWN_TRANSACTION:
+ return Status::METHOD_NOT_SUPPORTED;
+ case ::android::INVALID_OPERATION:
+ return Status::OPERATION_NOT_SUPPORTED;
+ case ::android::DEAD_OBJECT:
+ return Status::CAMERA_DISCONNECTED;
+ }
+ ALOGW("Unexpected HAL status code %d", s);
+ return Status::OPERATION_NOT_SUPPORTED;
+ }
}
// Test environment for camera
@@ -131,7 +183,7 @@
void CameraHidlEnvironment::SetUp() {
// TODO: test the binderized mode
- mProvider = ::testing::VtsHalHidlTargetTestBase::getService<ICameraProvider>(CAMERA_PASSTHROUGH_SERVICE_NAME);
+ mProvider = ::testing::VtsHalHidlTargetTestBase::getService<ICameraProvider>(kCameraPassthroughServiceName);
// TODO: handle the device doesn't have any camera case
ALOGI_IF(mProvider, "provider is not nullptr, %p", mProvider.get());
ASSERT_NE(mProvider, nullptr);
@@ -141,6 +193,249 @@
ALOGI("TearDown CameraHidlEnvironment");
}
+struct BufferItemHander: public BufferItemConsumer::FrameAvailableListener {
+ BufferItemHander(wp<BufferItemConsumer> consumer) : mConsumer(consumer) {}
+
+ void onFrameAvailable(const android::BufferItem&) override {
+ sp<BufferItemConsumer> consumer = mConsumer.promote();
+ ASSERT_NE(nullptr, consumer.get());
+
+ android::BufferItem buffer;
+ ASSERT_EQ(android::OK, consumer->acquireBuffer(&buffer, 0));
+ ASSERT_EQ(android::OK, consumer->releaseBuffer(buffer));
+ }
+
+ private:
+ wp<BufferItemConsumer> mConsumer;
+};
+
+struct PreviewWindowCb : public ICameraDevicePreviewCallback {
+ PreviewWindowCb(sp<ANativeWindow> anw) : mPreviewWidth(0),
+ mPreviewHeight(0), mFormat(0), mPreviewUsage(0),
+ mPreviewSwapInterval(-1), mCrop{-1, -1, -1, -1}, mAnw(anw) {}
+
+ using dequeueBuffer_cb =
+ std::function<void(Status status, uint64_t bufferId,
+ const hidl_handle& buffer, uint32_t stride)>;
+ Return<void> dequeueBuffer(dequeueBuffer_cb _hidl_cb) override;
+
+ Return<Status> enqueueBuffer(uint64_t bufferId) override;
+
+ Return<Status> cancelBuffer(uint64_t bufferId) override;
+
+ Return<Status> setBufferCount(uint32_t count) override;
+
+ Return<Status> setBuffersGeometry(uint32_t w,
+ uint32_t h, PixelFormat format) override;
+
+ Return<Status> setCrop(int32_t left, int32_t top,
+ int32_t right, int32_t bottom) override;
+
+ Return<Status> setUsage(ProducerUsage usage) override;
+
+ Return<Status> setSwapInterval(int32_t interval) override;
+
+ using getMinUndequeuedBufferCount_cb =
+ std::function<void(Status status, uint32_t count)>;
+ Return<void> getMinUndequeuedBufferCount(
+ getMinUndequeuedBufferCount_cb _hidl_cb) override;
+
+ Return<Status> setTimestamp(int64_t timestamp) override;
+
+ private:
+ struct BufferHasher {
+ size_t operator()(const buffer_handle_t& buf) const {
+ if (buf == nullptr)
+ return 0;
+
+ size_t result = 1;
+ result = 31 * result + buf->numFds;
+ result = 31 * result + buf->numInts;
+ int length = buf->numFds + buf->numInts;
+ for (int i = 0; i < length; i++) {
+ result = 31 * result + buf->data[i];
+ }
+ return result;
+ }
+ };
+
+ struct BufferComparator {
+ bool operator()(const buffer_handle_t& buf1,
+ const buffer_handle_t& buf2) const {
+ if ((buf1->numFds == buf2->numFds) &&
+ (buf1->numInts == buf2->numInts)) {
+ int length = buf1->numFds + buf1->numInts;
+ for (int i = 0; i < length; i++) {
+ if (buf1->data[i] != buf2->data[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ };
+
+ std::pair<bool, uint64_t> getBufferId(ANativeWindowBuffer* anb);
+ void cleanupCirculatingBuffers();
+
+ std::mutex mBufferIdMapLock; // protecting mBufferIdMap and mNextBufferId
+ typedef std::unordered_map<const buffer_handle_t, uint64_t,
+ BufferHasher, BufferComparator> BufferIdMap;
+
+ BufferIdMap mBufferIdMap; // stream ID -> per stream buffer ID map
+ std::unordered_map<uint64_t, ANativeWindowBuffer*> mReversedBufMap;
+ uint64_t mNextBufferId = 1;
+
+ uint32_t mPreviewWidth, mPreviewHeight;
+ int mFormat, mPreviewUsage;
+ int32_t mPreviewSwapInterval;
+ android_native_rect_t mCrop;
+ sp<ANativeWindow> mAnw; //Native window reference
+};
+
+std::pair<bool, uint64_t> PreviewWindowCb::getBufferId(
+ ANativeWindowBuffer* anb) {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+
+ buffer_handle_t& buf = anb->handle;
+ auto it = mBufferIdMap.find(buf);
+ if (it == mBufferIdMap.end()) {
+ uint64_t bufId = mNextBufferId++;
+ mBufferIdMap[buf] = bufId;
+ mReversedBufMap[bufId] = anb;
+ return std::make_pair(true, bufId);
+ } else {
+ return std::make_pair(false, it->second);
+ }
+}
+
+void PreviewWindowCb::cleanupCirculatingBuffers() {
+ std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+ mBufferIdMap.clear();
+ mReversedBufMap.clear();
+}
+
+Return<void> PreviewWindowCb::dequeueBuffer(dequeueBuffer_cb _hidl_cb) {
+ ANativeWindowBuffer* anb;
+ auto rc = native_window_dequeue_buffer_and_wait(mAnw.get(), &anb);
+ uint64_t bufferId = 0;
+ uint32_t stride = 0;
+ hidl_handle buf = nullptr;
+ if (rc == ::android::OK) {
+ auto pair = getBufferId(anb);
+ buf = (pair.first) ? anb->handle : nullptr;
+ bufferId = pair.second;
+ stride = anb->stride;
+ }
+
+ _hidl_cb(mapToStatus(rc), bufferId, buf, stride);
+ return Void();
+}
+
+Return<Status> PreviewWindowCb::enqueueBuffer(uint64_t bufferId) {
+ if (mReversedBufMap.count(bufferId) == 0) {
+ ALOGE("%s: bufferId %" PRIu64 " not found", __FUNCTION__, bufferId);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ return mapToStatus(mAnw->queueBuffer(mAnw.get(),
+ mReversedBufMap.at(bufferId), -1));
+}
+
+Return<Status> PreviewWindowCb::cancelBuffer(uint64_t bufferId) {
+ if (mReversedBufMap.count(bufferId) == 0) {
+ ALOGE("%s: bufferId %" PRIu64 " not found", __FUNCTION__, bufferId);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ return mapToStatus(mAnw->cancelBuffer(mAnw.get(),
+ mReversedBufMap.at(bufferId), -1));
+}
+
+Return<Status> PreviewWindowCb::setBufferCount(uint32_t count) {
+ if (mAnw.get() != nullptr) {
+ // WAR for b/27039775
+ native_window_api_disconnect(mAnw.get(), NATIVE_WINDOW_API_CAMERA);
+ native_window_api_connect(mAnw.get(), NATIVE_WINDOW_API_CAMERA);
+ if (mPreviewWidth != 0) {
+ native_window_set_buffers_dimensions(mAnw.get(),
+ mPreviewWidth, mPreviewHeight);
+ native_window_set_buffers_format(mAnw.get(), mFormat);
+ }
+ if (mPreviewUsage != 0) {
+ native_window_set_usage(mAnw.get(), mPreviewUsage);
+ }
+ if (mPreviewSwapInterval >= 0) {
+ mAnw->setSwapInterval(mAnw.get(), mPreviewSwapInterval);
+ }
+ if (mCrop.left >= 0) {
+ native_window_set_crop(mAnw.get(), &(mCrop));
+ }
+ }
+
+ auto rc = native_window_set_buffer_count(mAnw.get(), count);
+ if (rc == ::android::OK) {
+ cleanupCirculatingBuffers();
+ }
+
+ return mapToStatus(rc);
+}
+
+Return<Status> PreviewWindowCb::setBuffersGeometry(uint32_t w, uint32_t h,
+ PixelFormat format) {
+ auto rc = native_window_set_buffers_dimensions(mAnw.get(), w, h);
+ if (rc == ::android::OK) {
+ mPreviewWidth = w;
+ mPreviewHeight = h;
+ rc = native_window_set_buffers_format(mAnw.get(),
+ static_cast<int>(format));
+ if (rc == ::android::OK) {
+ mFormat = static_cast<int>(format);
+ }
+ }
+
+ return mapToStatus(rc);
+}
+
+Return<Status> PreviewWindowCb::setCrop(int32_t left, int32_t top,
+ int32_t right, int32_t bottom) {
+ android_native_rect_t crop = { left, top, right, bottom };
+ auto rc = native_window_set_crop(mAnw.get(), &crop);
+ if (rc == ::android::OK) {
+ mCrop = crop;
+ }
+ return mapToStatus(rc);
+}
+
+Return<Status> PreviewWindowCb::setUsage(ProducerUsage usage) {
+ auto rc = native_window_set_usage(mAnw.get(), static_cast<int>(usage));
+ if (rc == ::android::OK) {
+ mPreviewUsage = static_cast<int>(usage);
+ }
+ return mapToStatus(rc);
+}
+
+Return<Status> PreviewWindowCb::setSwapInterval(int32_t interval) {
+ auto rc = mAnw->setSwapInterval(mAnw.get(), interval);
+ if (rc == ::android::OK) {
+ mPreviewSwapInterval = interval;
+ }
+ return mapToStatus(rc);
+}
+
+Return<void> PreviewWindowCb::getMinUndequeuedBufferCount(
+ getMinUndequeuedBufferCount_cb _hidl_cb) {
+ int count = 0;
+ auto rc = mAnw->query(mAnw.get(),
+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &count);
+ _hidl_cb(mapToStatus(rc), count);
+ return Void();
+}
+
+Return<Status> PreviewWindowCb::setTimestamp(int64_t timestamp) {
+ return mapToStatus(native_window_set_buffers_timestamp(mAnw.get(),
+ timestamp));
+}
+
// The main test class for camera HIDL HAL.
class CameraHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
@@ -172,9 +467,88 @@
CameraHidlTest *mParent; // Parent object
};
+ struct TorchProviderCb : public ICameraProviderCallback {
+ TorchProviderCb(CameraHidlTest *parent) : mParent(parent) {}
+ virtual Return<void> cameraDeviceStatusChange(
+ const hidl_string&, CameraDeviceStatus) override {
+ return Void();
+ }
+
+ virtual Return<void> torchModeStatusChange(
+ const hidl_string&, TorchModeStatus newStatus) override {
+ std::lock_guard<std::mutex> l(mParent->mTorchLock);
+ mParent->mTorchStatus = newStatus;
+ mParent->mTorchCond.notify_one();
+ return Void();
+ }
+
+ private:
+ CameraHidlTest *mParent; // Parent object
+ };
+
+ struct Camera1DeviceCb :
+ public ::android::hardware::camera::device::V1_0::ICameraDeviceCallback {
+ Camera1DeviceCb(CameraHidlTest *parent) : mParent(parent) {}
+
+ Return<void> notifyCallback(NotifyCallbackMsg msgType,
+ int32_t ext1, int32_t ext2) override;
+
+ Return<uint32_t> registerMemory(const hidl_handle& descriptor,
+ uint32_t bufferSize, uint32_t bufferCount) override;
+
+ Return<void> unregisterMemory(uint32_t memId) override;
+
+ Return<void> dataCallback(DataCallbackMsg msgType,
+ uint32_t data, uint32_t bufferIndex,
+ const CameraFrameMetadata& metadata) override;
+
+ Return<void> dataCallbackTimestamp(DataCallbackMsg msgType,
+ uint32_t data, uint32_t bufferIndex,
+ int64_t timestamp) override;
+
+ Return<void> handleCallbackTimestamp(DataCallbackMsg msgType,
+ const hidl_handle& frameData,uint32_t data,
+ uint32_t bufferIndex, int64_t timestamp) override;
+
+ private:
+ CameraHidlTest *mParent; // Parent object
+ };
+
+ void openCameraDevice(const std::string &name,const CameraHidlEnvironment* env,
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> *device /*out*/);
+ void setupPreviewWindow(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
+ sp<BufferItemConsumer> *bufferItemConsumer /*out*/,
+ sp<BufferItemHander> *bufferHandler /*out*/);
+ void stopPreviewAndClose(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device);
+ void startPreview(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device);
+ void enableMsgType(unsigned int msgType,
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device);
+ void disableMsgType(unsigned int msgType,
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device);
+ void getParameters(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
+ CameraParameters *cameraParams /*out*/);
+ void setParameters(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
+ const CameraParameters &cameraParams);
+ void waitForFrameLocked(DataCallbackMsg msgFrame,
+ std::unique_lock<std::mutex> &l);
+ void openEmptyDeviceSession(const std::string &name,
+ const CameraHidlEnvironment* env,
+ sp<ICameraDeviceSession> *session /*out*/,
+ camera_metadata_t **staticMeta /*out*/);
+ void configurePreviewStream(const std::string &name,
+ const CameraHidlEnvironment* env,
+ const AvailableStream *previewThreshold,
+ sp<ICameraDeviceSession> *session /*out*/,
+ Stream *previewStream /*out*/,
+ HalStreamConfiguration *halStreamConfig /*out*/);
static Status getAvailableOutputStreams(camera_metadata_t *staticMeta,
std::vector<AvailableStream> &outputStreams,
- AvailableStream *threshold = nullptr);
+ const AvailableStream *threshold = nullptr);
static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta);
static Status pickConstrainedModeSize(camera_metadata_t *staticMeta,
AvailableStream &hfrStream);
@@ -184,14 +558,114 @@
static Status findLargestSize(
const std::vector<AvailableStream> &streamSizes,
int32_t format, AvailableStream &result);
+ static Status isAutoFocusModeAvailable(
+ ::android::CameraParameters &cameraParams, const char *mode) ;
protected:
std::mutex mLock; // Synchronize access to member variables
std::condition_variable mResultCondition; // Condition variable for incoming results
uint32_t mResultFrameNumber; // Expected result frame number
std::vector<StreamBuffer> mResultBuffers; // Holds stream buffers from capture result
+ std::vector<ErrorMsg> mErrors; // Holds incoming error notifications
+ DataCallbackMsg mDataMessageTypeReceived; // Most recent message type received through data callbacks
+ uint32_t mVideoBufferIndex; // Buffer index of the most recent video buffer
+ uint32_t mVideoData; // Buffer data of the most recent video buffer
+ hidl_handle mVideoNativeHandle; // Most recent video buffer native handle
+ NotifyCallbackMsg mNotifyMessage; // Current notification message
+
+ std::mutex mTorchLock; // Synchronize access to torch status
+ std::condition_variable mTorchCond; // Condition variable for torch status
+ TorchModeStatus mTorchStatus; // Current torch status
+
+ // Holds camera registered buffers
+ std::unordered_map<uint32_t, sp<::android::MemoryHeapBase> > mMemoryPool;
};
+Return<void> CameraHidlTest::Camera1DeviceCb::notifyCallback(
+ NotifyCallbackMsg msgType, int32_t ext1 __unused,
+ int32_t ext2 __unused) {
+ std::unique_lock<std::mutex> l(mParent->mLock);
+ mParent->mNotifyMessage = msgType;
+ mParent->mResultCondition.notify_one();
+
+ return Void();
+}
+
+Return<uint32_t> CameraHidlTest::Camera1DeviceCb::registerMemory(
+ const hidl_handle& descriptor, uint32_t bufferSize,
+ uint32_t bufferCount) {
+ if (descriptor->numFds != 1) {
+ ADD_FAILURE() << "camera memory descriptor has"
+ " numFds " << descriptor->numFds << " (expect 1)" ;
+ return 0;
+ }
+ if (descriptor->data[0] < 0) {
+ ADD_FAILURE() << "camera memory descriptor has"
+ " FD " << descriptor->data[0] << " (expect >= 0)";
+ return 0;
+ }
+
+ sp<::android::MemoryHeapBase> pool = new ::android::MemoryHeapBase(
+ descriptor->data[0], bufferSize*bufferCount, 0, 0);
+ mParent->mMemoryPool.emplace(pool->getHeapID(), pool);
+
+ return pool->getHeapID();
+}
+
+Return<void> CameraHidlTest::Camera1DeviceCb::unregisterMemory(uint32_t memId) {
+ if (mParent->mMemoryPool.count(memId) == 0) {
+ ALOGE("%s: memory pool ID %d not found", __FUNCTION__, memId);
+ ADD_FAILURE();
+ return Void();
+ }
+
+ mParent->mMemoryPool.erase(memId);
+ return Void();
+}
+
+Return<void> CameraHidlTest::Camera1DeviceCb::dataCallback(
+ DataCallbackMsg msgType __unused, uint32_t data __unused,
+ uint32_t bufferIndex __unused,
+ const CameraFrameMetadata& metadata __unused) {
+ std::unique_lock<std::mutex> l(mParent->mLock);
+ mParent->mDataMessageTypeReceived = msgType;
+ mParent->mResultCondition.notify_one();
+
+ return Void();
+}
+
+Return<void> CameraHidlTest::Camera1DeviceCb::dataCallbackTimestamp(
+ DataCallbackMsg msgType, uint32_t data,
+ uint32_t bufferIndex, int64_t timestamp __unused) {
+ std::unique_lock<std::mutex> l(mParent->mLock);
+ mParent->mDataMessageTypeReceived = msgType;
+ mParent->mVideoBufferIndex = bufferIndex;
+ if (mParent->mMemoryPool.count(data) == 0) {
+ ADD_FAILURE() << "memory pool ID " << data << "not found";
+ }
+ mParent->mVideoData = data;
+ mParent->mResultCondition.notify_one();
+
+ return Void();
+}
+
+Return<void> CameraHidlTest::Camera1DeviceCb::handleCallbackTimestamp(
+ DataCallbackMsg msgType, const hidl_handle& frameData,
+ uint32_t data __unused, uint32_t bufferIndex,
+ int64_t timestamp __unused) {
+ std::unique_lock<std::mutex> l(mParent->mLock);
+ mParent->mDataMessageTypeReceived = msgType;
+ mParent->mVideoBufferIndex = bufferIndex;
+ if (mParent->mMemoryPool.count(data) == 0) {
+ ADD_FAILURE() << "memory pool ID " << data << " not found";
+ }
+ mParent->mVideoData = data;
+ mParent->mVideoNativeHandle = frameData;
+ mParent->mResultCondition.notify_one();
+
+ return Void();
+}
+
Return<void> CameraHidlTest::DeviceCb::processCaptureResult(
const CaptureResult& result) {
if (nullptr == mParent) {
@@ -221,16 +695,28 @@
}
Return<void> CameraHidlTest::DeviceCb::notify(
- const NotifyMsg& /*msg*/) {
- // TODO(epeev): Pending implementation.
- ALOGI("notify callback");
+ const NotifyMsg& message) {
+
+ if (MsgType::ERROR == message.type) {
+ {
+ std::lock_guard<std::mutex> l(mParent->mLock);
+ mParent->mErrors.push_back(message.msg.error);
+ }
+
+ if ((ErrorCode::ERROR_REQUEST == message.msg.error.errorCode)
+ || (ErrorCode::ERROR_BUFFER == message.msg.error.errorCode)) {
+ mParent->mResultCondition.notify_one();
+ }
+ }
+
return Void();
}
hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames() {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames;
- env->mProvider->getCameraIdList(
+ Return<void> ret;
+ ret = env->mProvider->getCameraIdList(
[&](auto status, const auto& idList) {
ALOGI("getCameraIdList returns status:%d", (int)status);
for (size_t i = 0; i < idList.size(); i++) {
@@ -239,22 +725,28 @@
ASSERT_EQ(Status::OK, status);
cameraDeviceNames = idList;
});
+ if (!ret.isOk()) {
+ ADD_FAILURE();
+ }
return cameraDeviceNames;
}
// Test if ICameraProvider::isTorchModeSupported returns Status::OK
TEST_F(CameraHidlTest, isTorchModeSupported) {
- CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported(
+ Return<void> ret;
+ ret = CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported(
[&](auto status, bool support) {
ALOGI("isSetTorchModeSupported returns status:%d supported:%d",
(int)status, support);
ASSERT_EQ(Status::OK, status);
});
+ ASSERT_TRUE(ret.isOk());
}
// TODO: consider removing this test if getCameraDeviceNames() has the same coverage
TEST_F(CameraHidlTest, getCameraIdList) {
- CameraHidlEnvironment::Instance()->mProvider->getCameraIdList(
+ Return<void> ret;
+ ret = CameraHidlEnvironment::Instance()->mProvider->getCameraIdList(
[&](auto status, const auto& idList) {
ALOGI("getCameraIdList returns status:%d", (int)status);
for (size_t i = 0; i < idList.size(); i++) {
@@ -265,11 +757,13 @@
// Not necessary hold for external cameras providers
ASSERT_GT(idList.size(), 0u);
});
+ ASSERT_TRUE(ret.isOk());
}
// Test if ICameraProvider::getVendorTags returns Status::OK
TEST_F(CameraHidlTest, getVendorTags) {
- CameraHidlEnvironment::Instance()->mProvider->getVendorTags(
+ Return<void> ret;
+ ret = CameraHidlEnvironment::Instance()->mProvider->getVendorTags(
[&](auto status, const auto& vendorTagSecs) {
ALOGI("getVendorTags returns status:%d numSections %zu",
(int)status, vendorTagSecs.size());
@@ -286,6 +780,7 @@
}
ASSERT_EQ(Status::OK, status);
});
+ ASSERT_TRUE(ret.isOk());
}
// Test if ICameraProvider::setCallback returns Status::OK
@@ -310,25 +805,36 @@
};
sp<ProviderCb> cb = new ProviderCb;
auto status = env->mProvider->setCallback(cb);
+ ASSERT_TRUE(status.isOk());
ASSERT_EQ(Status::OK, status);
- // TODO: right now no callbacks are fired because there is no external camera
- // or torch mode change. Need to test torch API in CameraDevice test later.
}
-// Test if ICameraProvider::getCameraDeviceInterface_V3_x returns Status::OK and non-null device
-TEST_F(CameraHidlTest, getCameraDeviceInterface_V3_x) {
+// Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device
+TEST_F(CameraHidlTest, getCameraDeviceInterface) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
- env->mProvider->getCameraDeviceInterface_V3_x(
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device3_2) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device3_2, nullptr);
});
+ ASSERT_TRUE(ret.isOk());
+ } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V1_x(
+ name,
+ [&](auto status, const auto& device1) {
+ ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device1, nullptr);
+ });
+ ASSERT_TRUE(ret.isOk());
}
}
}
@@ -343,7 +849,8 @@
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
ALOGI("getResourceCost: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
@@ -351,8 +858,9 @@
ASSERT_NE(device, nullptr);
device3_2 = device;
});
+ ASSERT_TRUE(ret.isOk());
- device3_2->getResourceCost(
+ ret = device3_2->getResourceCost(
[&](auto status, const auto& resourceCost) {
ALOGI("getResourceCost returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
@@ -362,6 +870,759 @@
ALOGI(" Conflicting device: %s", name.c_str());
}
});
+ ASSERT_TRUE(ret.isOk());
+ } else {
+ ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ ALOGI("getResourceCost: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V1_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device1 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ ret = device1->getResourceCost(
+ [&](auto status, const auto& resourceCost) {
+ ALOGI("getResourceCost returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ALOGI(" Resource cost is %d", resourceCost.resourceCost);
+ ASSERT_LE(resourceCost.resourceCost, 100u);
+ for (const auto& name : resourceCost.conflictingDevices) {
+ ALOGI(" Conflicting device: %s", name.c_str());
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Verify that the static camera info can be retrieved
+// successfully.
+TEST_F(CameraHidlTest, getCameraInfo) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V1_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device1 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ ret = device1->getCameraInfo(
+ [&](auto status, const auto& info) {
+ ALOGI("getCameraInfo returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ switch(info.orientation) {
+ case 0:
+ case 90:
+ case 180:
+ case 270:
+ //Expected cases
+ ALOGI("camera orientation: %d", info.orientation);
+ break;
+ default:
+ FAIL() << "Unexpected camera orientation:" << info.orientation;
+ }
+ switch(info.facing) {
+ case CameraFacing::BACK:
+ case CameraFacing::FRONT:
+ case CameraFacing::EXTERNAL:
+ //Expected cases
+ ALOGI("camera facing: %d", info.facing);
+ break;
+ default:
+ FAIL() << "Unexpected camera facing:" << static_cast<uint32_t> (info.facing);
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Check whether preview window can be configured
+TEST_F(CameraHidlTest, setPreviewWindow) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1,
+ &bufferItemConsumer /*out*/, &bufferHandler /*out*/);
+
+ Return<void> ret;
+ ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Verify that setting preview window fails in case device is not open
+TEST_F(CameraHidlTest, setPreviewWindowInvalid) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V1_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device1 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ Return<Status> returnStatus = device1->setPreviewWindow(nullptr);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OPERATION_NOT_SUPPORTED, returnStatus);
+ }
+ }
+}
+
+// Start and stop preview checking whether it gets enabled in between.
+TEST_F(CameraHidlTest, startStopPreview) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1,
+ &bufferItemConsumer /*out*/, &bufferHandler /*out*/);
+
+ startPreview(device1);
+
+ Return<bool> returnBoolStatus = device1->previewEnabled();
+ ASSERT_TRUE(returnBoolStatus.isOk());
+ ASSERT_TRUE(returnBoolStatus);
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Start preview without active preview window. Preview should start as soon
+// as a valid active window gets configured.
+TEST_F(CameraHidlTest, startStopPreviewDelayed) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ Return<Status> returnStatus = device1->setPreviewWindow(nullptr);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ startPreview(device1);
+
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+
+ //Preview should get enabled now
+ Return<bool> returnBoolStatus = device1->previewEnabled();
+ ASSERT_TRUE(returnBoolStatus.isOk());
+ ASSERT_TRUE(returnBoolStatus);
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Verify that image capture behaves as expected along with preview callbacks.
+TEST_F(CameraHidlTest, takePicture) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
+ }
+
+ enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1);
+ startPreview(device1);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l);
+ }
+
+ disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME,
+ device1);
+ enableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE,
+ device1);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
+ }
+
+ Return<Status> returnStatus = device1->takePicture();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ waitForFrameLocked(DataCallbackMsg::COMPRESSED_IMAGE, l);
+ }
+
+ disableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE,
+ device1);
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Image capture should fail in case preview didn't get enabled first.
+TEST_F(CameraHidlTest, takePictureFail) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ Return<Status> returnStatus = device1->takePicture();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_NE(Status::OK, returnStatus);
+
+ Return<void> ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Verify that image capture can be cancelled.
+TEST_F(CameraHidlTest, cancelPicture) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+ startPreview(device1);
+
+ Return<Status> returnStatus = device1->takePicture();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ returnStatus = device1->cancelPicture();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Image capture cancel should fail when image capture is not running.
+TEST_F(CameraHidlTest, cancelPictureFail) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+ startPreview(device1);
+
+ Return<Status> returnStatus = device1->cancelPicture();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_NE(Status::OK, returnStatus);
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Test basic video recording.
+TEST_F(CameraHidlTest, startStopRecording) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
+ }
+
+ enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1);
+ startPreview(device1);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l);
+ mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
+ mVideoBufferIndex = UINT32_MAX;
+ }
+
+ disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1);
+
+ bool videoMetaEnabled = false;
+ Return<Status> returnStatus = device1->storeMetaDataInBuffers(true);
+ ASSERT_TRUE(returnStatus.isOk());
+ // It is allowed for devices to not support this feature
+ ASSERT_TRUE((Status::OK == returnStatus) ||
+ (Status::OPERATION_NOT_SUPPORTED == returnStatus));
+ if (Status::OK == returnStatus) {
+ videoMetaEnabled = true;
+ }
+
+ enableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME, device1);
+ Return<bool> returnBoolStatus = device1->recordingEnabled();
+ ASSERT_TRUE(returnBoolStatus.isOk());
+ ASSERT_FALSE(returnBoolStatus);
+
+ returnStatus = device1->startRecording();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ waitForFrameLocked(DataCallbackMsg::VIDEO_FRAME, l);
+ ASSERT_NE(UINT32_MAX, mVideoBufferIndex);
+ disableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME,
+ device1);
+ }
+
+ returnBoolStatus = device1->recordingEnabled();
+ ASSERT_TRUE(returnBoolStatus.isOk());
+ ASSERT_TRUE(returnBoolStatus);
+
+ Return<void> ret;
+ if (videoMetaEnabled) {
+ ret = device1->releaseRecordingFrameHandle(mVideoData,
+ mVideoBufferIndex, mVideoNativeHandle);
+ ASSERT_TRUE(ret.isOk());
+ } else {
+ ret = device1->releaseRecordingFrame(mVideoData, mVideoBufferIndex);
+ ASSERT_TRUE(ret.isOk());
+ }
+
+ ret = device1->stopRecording();
+ ASSERT_TRUE(ret.isOk());
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// It shouldn't be possible to start recording without enabling preview first.
+TEST_F(CameraHidlTest, startRecordingFail) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ Return<bool> returnBoolStatus = device1->recordingEnabled();
+ ASSERT_TRUE(returnBoolStatus.isOk());
+ ASSERT_FALSE(returnBoolStatus);
+
+ Return<Status> returnStatus = device1->startRecording();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_NE(Status::OK, returnStatus);
+
+ Return<void> ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Check autofocus support if available.
+TEST_F(CameraHidlTest, autoFocus) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ std::vector<const char *> focusModes = {CameraParameters::FOCUS_MODE_AUTO,
+ CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE,
+ CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO};
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ ::android::CameraParameters cameraParams;
+ getParameters(device1, &cameraParams /*out*/);
+
+ if (Status::OK != isAutoFocusModeAvailable(cameraParams,
+ CameraParameters::FOCUS_MODE_AUTO)) {
+ Return<void> ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+ startPreview(device1);
+ enableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1);
+
+ for (auto &iter : focusModes) {
+ if (Status::OK != isAutoFocusModeAvailable(cameraParams,
+ iter)) {
+ continue;
+ }
+
+ cameraParams.set(CameraParameters::KEY_FOCUS_MODE, iter);
+ setParameters(device1, cameraParams);
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mNotifyMessage = NotifyCallbackMsg::ERROR;
+ }
+
+ Return<Status> returnStatus = device1->autoFocus();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ while (NotifyCallbackMsg::FOCUS != mNotifyMessage) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kAutoFocusTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mResultCondition.wait_until(l, timeout));
+ }
+ }
+ }
+
+ disableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1);
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// In case autofocus is supported verify that it can be cancelled.
+TEST_F(CameraHidlTest, cancelAutoFocus) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ ::android::CameraParameters cameraParams;
+ getParameters(device1, &cameraParams /*out*/);
+
+ if (Status::OK != isAutoFocusModeAvailable(cameraParams,
+ CameraParameters::FOCUS_MODE_AUTO)) {
+ Return<void> ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+
+ // It should be fine to call before preview starts.
+ ASSERT_EQ(Status::OK, device1->cancelAutoFocus());
+
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+ startPreview(device1);
+
+ // It should be fine to call after preview starts too.
+ Return<Status> returnStatus = device1->cancelAutoFocus();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ returnStatus = device1->autoFocus();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ returnStatus = device1->cancelAutoFocus();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Check whether face detection is available and try to enable&disable.
+TEST_F(CameraHidlTest, sendCommandFaceDetection) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ ::android::CameraParameters cameraParams;
+ getParameters(device1, &cameraParams /*out*/);
+
+ int32_t hwFaces = cameraParams.getInt(
+ CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW);
+ int32_t swFaces = cameraParams.getInt(
+ CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW);
+ if ((0 >= hwFaces) && (0 >= swFaces)) {
+ Return<void> ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+ startPreview(device1);
+
+ if (0 < hwFaces) {
+ Return<Status> returnStatus = device1->sendCommand(
+ CommandType::START_FACE_DETECTION,
+ CAMERA_FACE_DETECTION_HW, 0);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+ // TODO(epeev) : Enable and check for face notifications
+ returnStatus = device1->sendCommand(
+ CommandType::STOP_FACE_DETECTION,
+ CAMERA_FACE_DETECTION_HW, 0);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+ }
+
+ if (0 < swFaces) {
+ Return<Status> returnStatus = device1->sendCommand(
+ CommandType::START_FACE_DETECTION,
+ CAMERA_FACE_DETECTION_SW, 0);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+ // TODO(epeev) : Enable and check for face notifications
+ returnStatus = device1->sendCommand(
+ CommandType::STOP_FACE_DETECTION,
+ CAMERA_FACE_DETECTION_SW, 0);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+ }
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Check whether smooth zoom is available and try to enable&disable.
+TEST_F(CameraHidlTest, sendCommandSmoothZoom) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ ::android::CameraParameters cameraParams;
+ getParameters(device1, &cameraParams /*out*/);
+
+ const char *smoothZoomStr = cameraParams.get(
+ CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED);
+ bool smoothZoomSupported = ((nullptr != smoothZoomStr) &&
+ (strcmp(smoothZoomStr, CameraParameters::TRUE) == 0)) ?
+ true : false;
+ if (!smoothZoomSupported) {
+ Return<void> ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+
+ int32_t maxZoom = cameraParams.getInt(
+ CameraParameters::KEY_MAX_ZOOM);
+ ASSERT_TRUE(0 < maxZoom);
+
+ sp<BufferItemConsumer> bufferItemConsumer;
+ sp<BufferItemHander> bufferHandler;
+ setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+ &bufferHandler /*out*/);
+ startPreview(device1);
+ setParameters(device1, cameraParams);
+
+ Return<Status> returnStatus = device1->sendCommand(
+ CommandType::START_SMOOTH_ZOOM, maxZoom, 0);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+ // TODO(epeev) : Enable and check for face notifications
+ returnStatus = device1->sendCommand(CommandType::STOP_SMOOTH_ZOOM,
+ 0, 0);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ stopPreviewAndClose(device1);
+ }
+ }
+}
+
+// Basic sanity tests related to camera parameters.
+TEST_F(CameraHidlTest, getSetParameters) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ ::android::CameraParameters cameraParams;
+ getParameters(device1, &cameraParams /*out*/);
+
+ int32_t width, height;
+ cameraParams.getPictureSize(&width, &height);
+ ASSERT_TRUE((0 < width) && (0 < height));
+ cameraParams.getPreviewSize(&width, &height);
+ ASSERT_TRUE((0 < width) && (0 < height));
+ int32_t minFps, maxFps;
+ cameraParams.getPreviewFpsRange(&minFps, &maxFps);
+ ASSERT_TRUE((0 < minFps) && (0 < maxFps));
+ ASSERT_NE(nullptr, cameraParams.getPreviewFormat());
+ ASSERT_NE(nullptr, cameraParams.getPictureFormat());
+ ASSERT_TRUE(strcmp(CameraParameters::PIXEL_FORMAT_JPEG,
+ cameraParams.getPictureFormat()) == 0);
+
+ const char *flashMode = cameraParams.get(
+ CameraParameters::KEY_FLASH_MODE);
+ ASSERT_TRUE((nullptr == flashMode) || (strcmp(
+ CameraParameters::FLASH_MODE_OFF, flashMode) == 0));
+
+ const char *wbMode = cameraParams.get(
+ CameraParameters::KEY_WHITE_BALANCE);
+ ASSERT_TRUE((nullptr == wbMode) || (strcmp(
+ CameraParameters::WHITE_BALANCE_AUTO, wbMode) == 0));
+
+ const char *effect = cameraParams.get(CameraParameters::KEY_EFFECT);
+ ASSERT_TRUE((nullptr == effect) || (strcmp(
+ CameraParameters::EFFECT_NONE, effect) == 0));
+
+ ::android::Vector<::android::Size> previewSizes;
+ cameraParams.getSupportedPreviewSizes(previewSizes);
+ ASSERT_FALSE(previewSizes.empty());
+ ::android::Vector<::android::Size> pictureSizes;
+ cameraParams.getSupportedPictureSizes(pictureSizes);
+ ASSERT_FALSE(pictureSizes.empty());
+ const char *previewFormats = cameraParams.get(
+ CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS);
+ ASSERT_NE(nullptr, previewFormats);
+ ::android::String8 previewFormatsString(previewFormats);
+ ASSERT_TRUE(previewFormatsString.contains(
+ CameraParameters::PIXEL_FORMAT_YUV420SP));
+ ASSERT_NE(nullptr, cameraParams.get(
+ CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS));
+ ASSERT_NE(nullptr, cameraParams.get(
+ CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES));
+ const char *focusModes = cameraParams.get(
+ CameraParameters::KEY_SUPPORTED_FOCUS_MODES);
+ ASSERT_NE(nullptr, focusModes);
+ ::android::String8 focusModesString(focusModes);
+ const char *focusMode = cameraParams.get(
+ CameraParameters::KEY_FOCUS_MODE);
+ ASSERT_NE(nullptr, focusMode);
+ // Auto focus mode should be default
+ if (focusModesString.contains(CameraParameters::FOCUS_MODE_AUTO)) {
+ ASSERT_TRUE(strcmp(
+ CameraParameters::FOCUS_MODE_AUTO, focusMode) == 0);
+ }
+ ASSERT_TRUE(0 < cameraParams.getInt(
+ CameraParameters::KEY_FOCAL_LENGTH));
+ int32_t horizontalViewAngle = cameraParams.getInt(
+ CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE);
+ ASSERT_TRUE((0 < horizontalViewAngle) && (360 >= horizontalViewAngle));
+ int32_t verticalViewAngle = cameraParams.getInt(
+ CameraParameters::KEY_VERTICAL_VIEW_ANGLE);
+ ASSERT_TRUE((0 < verticalViewAngle) && (360 >= verticalViewAngle));
+ int32_t jpegQuality = cameraParams.getInt(
+ CameraParameters::KEY_JPEG_QUALITY);
+ ASSERT_TRUE((1 <= jpegQuality) && (100 >= jpegQuality));
+ int32_t jpegThumbQuality = cameraParams.getInt(
+ CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY);
+ ASSERT_TRUE((1 <= jpegThumbQuality) && (100 >= jpegThumbQuality));
+
+ cameraParams.setPictureSize(pictureSizes[0].width,
+ pictureSizes[0].height);
+ cameraParams.setPreviewSize(previewSizes[0].width,
+ previewSizes[0].height);
+
+ setParameters(device1, cameraParams);
+ getParameters(device1, &cameraParams /*out*/);
+
+ cameraParams.getPictureSize(&width, &height);
+ ASSERT_TRUE((pictureSizes[0].width == width) &&
+ (pictureSizes[0].height == height));
+ cameraParams.getPreviewSize(&width, &height);
+ ASSERT_TRUE((previewSizes[0].width == width) &&
+ (previewSizes[0].height == height));
+
+ Return<void> ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
}
}
}
@@ -376,7 +1637,8 @@
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
@@ -384,8 +1646,9 @@
ASSERT_NE(device, nullptr);
device3_2 = device;
});
+ ASSERT_TRUE(ret.isOk());
- device3_2->getCameraCharacteristics(
+ ret = device3_2->getCameraCharacteristics(
[&](auto status, const auto& chars) {
ALOGI("getCameraCharacteristics returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
@@ -398,17 +1661,20 @@
ASSERT_GT(entryCount, 0u);
ALOGI("getCameraCharacteristics metadata entry count is %zu", entryCount);
});
+ ASSERT_TRUE(ret.isOk());
}
}
}
//In case it is supported verify that torch can be enabled.
+//Check for corresponding toch callbacks as well.
TEST_F(CameraHidlTest, setTorchMode) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
bool torchControlSupported = false;
+ Return<void> ret;
- CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported(
+ ret = CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported(
[&](auto status, bool support) {
ALOGI("isSetTorchModeSupported returns status:%d supported:%d",
(int)status, support);
@@ -416,11 +1682,17 @@
torchControlSupported = support;
});
+
+ sp<TorchProviderCb> cb = new TorchProviderCb(this);
+ Return<Status> returnStatus = env->mProvider->setCallback(cb);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
ALOGI("setTorchMode: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
@@ -428,32 +1700,116 @@
ASSERT_NE(device, nullptr);
device3_2 = device;
});
+ ASSERT_TRUE(ret.isOk());
- Status status = device3_2->setTorchMode(TorchMode::ON);
- ALOGI("setTorchMode return status %d", (int)status);
+ mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+ returnStatus = device3_2->setTorchMode(TorchMode::ON);
+ ASSERT_TRUE(returnStatus.isOk());
if (!torchControlSupported) {
- ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, status);
+ ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus);
} else {
- ASSERT_TRUE(status == Status::OK || status == Status::OPERATION_NOT_SUPPORTED);
- if (status == Status::OK) {
- status = device3_2->setTorchMode(TorchMode::OFF);
- ASSERT_EQ(Status::OK, status);
+ ASSERT_TRUE(returnStatus == Status::OK ||
+ returnStatus == Status::OPERATION_NOT_SUPPORTED);
+ if (returnStatus == Status::OK) {
+ {
+ std::unique_lock<std::mutex> l(mTorchLock);
+ while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kTorchTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mTorchCond.wait_until(l, timeout));
+ }
+ ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus);
+ mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+ }
+
+ returnStatus = device3_2->setTorchMode(TorchMode::OFF);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mTorchLock);
+ while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kTorchTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mTorchCond.wait_until(l, timeout));
+ }
+ ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus);
+ }
}
}
+ } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ ALOGI("dumpState: Testing camera device %s", name.c_str());
+ ret = env->mProvider->getCameraDeviceInterface_V1_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device1 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+ returnStatus = device1->setTorchMode(TorchMode::ON);
+ ASSERT_TRUE(returnStatus.isOk());
+ if (!torchControlSupported) {
+ ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus);
+ } else {
+ ASSERT_TRUE(returnStatus == Status::OK ||
+ returnStatus == Status::OPERATION_NOT_SUPPORTED);
+ if (returnStatus == Status::OK) {
+ {
+ std::unique_lock<std::mutex> l(mTorchLock);
+ while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kTorchTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mTorchCond.wait_until(l, timeout));
+ }
+ ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus);
+ mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+ }
+
+ returnStatus = device1->setTorchMode(TorchMode::OFF);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mTorchLock);
+ while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kTorchTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mTorchCond.wait_until(l, timeout));
+ }
+ ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus);
+ }
+ }
+ }
+ ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
}
}
+
+ returnStatus = env->mProvider->setCallback(nullptr);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
}
// Check dump functionality.
TEST_F(CameraHidlTest, dumpState) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ Return<void> ret;
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
ALOGI("dumpState: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
@@ -461,12 +1817,36 @@
ASSERT_NE(device, nullptr);
device3_2 = device;
});
+ ASSERT_TRUE(ret.isOk());
native_handle_t* raw_handle = native_handle_create(1, 0);
- raw_handle->data[0] = open(DUMP_OUTPUT, O_RDWR);
+ raw_handle->data[0] = open(kDumpOutput, O_RDWR);
ASSERT_GE(raw_handle->data[0], 0);
hidl_handle handle = raw_handle;
- device3_2->dumpState(handle);
+ ret= device3_2->dumpState(handle);
+ ASSERT_TRUE(ret.isOk());
+ close(raw_handle->data[0]);
+ native_handle_delete(raw_handle);
+ } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ ALOGI("dumpState: Testing camera device %s", name.c_str());
+ ret = env->mProvider->getCameraDeviceInterface_V1_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device1 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ native_handle_t* raw_handle = native_handle_create(1, 0);
+ raw_handle->data[0] = open(kDumpOutput, O_RDWR);
+ ASSERT_GE(raw_handle->data[0], 0);
+ hidl_handle handle = raw_handle;
+ Return<Status> returnStatus = device1->dumpState(handle);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
close(raw_handle->data[0]);
native_handle_delete(raw_handle);
}
@@ -477,12 +1857,13 @@
TEST_F(CameraHidlTest, openClose) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ Return<void> ret;
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
ALOGI("openClose: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
@@ -490,10 +1871,11 @@
ASSERT_NE(device, nullptr);
device3_2 = device;
});
+ ASSERT_TRUE(ret.isOk());
sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
sp<ICameraDeviceSession> session;
- device3_2->open(
+ ret = device3_2->open(
cb,
[&](auto status, const auto& newSession) {
ALOGI("device::open returns status:%d", (int)status);
@@ -501,18 +1883,38 @@
ASSERT_NE(newSession, nullptr);
session = newSession;
});
+ ASSERT_TRUE(ret.isOk());
native_handle_t* raw_handle = native_handle_create(1, 0);
- raw_handle->data[0] = open(DUMP_OUTPUT, O_RDWR);
+ raw_handle->data[0] = open(kDumpOutput, O_RDWR);
ASSERT_GE(raw_handle->data[0], 0);
hidl_handle handle = raw_handle;
- device3_2->dumpState(handle);
+ ret = device3_2->dumpState(handle);
+ ASSERT_TRUE(ret.isOk());
close(raw_handle->data[0]);
native_handle_delete(raw_handle);
- session->close();
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
// TODO: test all session API calls return INTERNAL_ERROR after close
// TODO: keep a wp copy here and verify session cannot be promoted out of this scope
+ } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+ openCameraDevice(name, env, &device1 /*out*/);
+ ASSERT_NE(nullptr, device1.get());
+
+ native_handle_t* raw_handle = native_handle_create(1, 0);
+ raw_handle->data[0] = open(kDumpOutput, O_RDWR);
+ ASSERT_GE(raw_handle->data[0], 0);
+ hidl_handle handle = raw_handle;
+ Return<Status> returnStatus = device1->dumpState(handle);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+ close(raw_handle->data[0]);
+ native_handle_delete(raw_handle);
+
+ ret = device1->close();
+ ASSERT_TRUE(ret.isOk());
}
}
}
@@ -526,8 +1928,9 @@
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+ Return<void> ret;
ALOGI("constructDefaultRequestSettings: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
@@ -535,10 +1938,11 @@
ASSERT_NE(device, nullptr);
device3_2 = device;
});
+ ASSERT_TRUE(ret.isOk());
sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
sp<ICameraDeviceSession> session;
- device3_2->open(
+ ret = device3_2->open(
cb,
[&](auto status, const auto& newSession) {
ALOGI("device::open returns status:%d", (int)status);
@@ -546,11 +1950,12 @@
ASSERT_NE(newSession, nullptr);
session = newSession;
});
+ ASSERT_TRUE(ret.isOk());
for (uint32_t t = (uint32_t) RequestTemplate::PREVIEW;
t <= (uint32_t) RequestTemplate::MANUAL; t++) {
RequestTemplate reqTemplate = (RequestTemplate) t;
- session->constructDefaultRequestSettings(
+ ret = session->constructDefaultRequestSettings(
reqTemplate,
[&](auto status, const auto& req) {
ALOGI("constructDefaultRequestSettings returns status:%d", (int)status);
@@ -577,8 +1982,10 @@
ASSERT_EQ(0u, req.size());
}
});
+ ASSERT_TRUE(ret.isOk());
}
- session->close();
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
}
}
}
@@ -592,35 +1999,12 @@
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
- ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
- ALOGI("configureStreams: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
- name,
- [&](auto status, const auto& device) {
- ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(device, nullptr);
- device3_2 = device;
- });
-
- sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
- sp<ICameraDeviceSession> session;
- device3_2->open(
- cb,
- [&](auto status, const auto& newSession) {
- ALOGI("device::open returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(newSession, nullptr);
- session = newSession;
- });
-
camera_metadata_t *staticMeta;
- device3_2->getCameraCharacteristics([&] (Status s,
- CameraMetadata metadata) {
- ASSERT_EQ(Status::OK, s);
- staticMeta =
- reinterpret_cast<camera_metadata_t*>(metadata.data());
- });
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, env, &session /*out*/,
+ &staticMeta /*out*/);
+
outputStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
outputStreams));
@@ -636,16 +2020,19 @@
::android::hardware::hidl_vec<Stream> streams = {stream};
StreamConfiguration config = {streams,
StreamConfigurationMode::NORMAL_MODE};
- session->configureStreams(config, [streamId] (Status s,
+ ret = session->configureStreams(config, [streamId] (Status s,
HalStreamConfiguration halConfig) {
ASSERT_EQ(Status::OK, s);
ASSERT_EQ(1u, halConfig.streams.size());
ASSERT_EQ(halConfig.streams[0].id, streamId);
});
+ ASSERT_TRUE(ret.isOk());
streamId++;
}
- session->close();
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
}
}
}
@@ -658,35 +2045,12 @@
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
- ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
- ALOGI("configureStreams: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
- name,
- [&](auto status, const auto& device) {
- ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(device, nullptr);
- device3_2 = device;
- });
-
- sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
- sp<ICameraDeviceSession> session;
- device3_2->open(
- cb,
- [&](auto status, const auto& newSession) {
- ALOGI("device::open returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(newSession, nullptr);
- session = newSession;
- });
-
camera_metadata_t *staticMeta;
- device3_2->getCameraCharacteristics([&] (Status s,
- CameraMetadata metadata) {
- ASSERT_EQ(Status::OK, s);
- staticMeta =
- reinterpret_cast<camera_metadata_t*>(metadata.data());
- });
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, env, &session /*out*/,
+ &staticMeta /*out*/);
+
outputStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
outputStreams));
@@ -701,10 +2065,12 @@
::android::hardware::hidl_vec<Stream> streams = {stream};
StreamConfiguration config = {streams,
StreamConfigurationMode::NORMAL_MODE};
- session->configureStreams(config, [] (Status s,
+ ret = session->configureStreams(config, [] (Status s,
HalStreamConfiguration) {
- ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+ ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+ (Status::INTERNAL_ERROR == s));
});
+ ASSERT_TRUE(ret.isOk());
stream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (UINT32_MAX),
@@ -714,10 +2080,11 @@
streams[0] = stream;
config = {streams,
StreamConfigurationMode::NORMAL_MODE};
- session->configureStreams(config, [] (Status s,
+ ret = session->configureStreams(config, [] (Status s,
HalStreamConfiguration) {
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
});
+ ASSERT_TRUE(ret.isOk());
for (auto &it : outputStreams) {
stream = {streamId++, StreamType::OUTPUT,
@@ -728,10 +2095,11 @@
streams[0] = stream;
config = {streams,
StreamConfigurationMode::NORMAL_MODE};
- session->configureStreams(config, [] (Status s,
+ ret = session->configureStreams(config, [] (Status s,
HalStreamConfiguration) {
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
});
+ ASSERT_TRUE(ret.isOk());
stream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (it.width),
@@ -741,13 +2109,16 @@
streams[0] = stream;
config = {streams,
StreamConfigurationMode::NORMAL_MODE};
- session->configureStreams(config, [] (Status s,
+ ret = session->configureStreams(config, [] (Status s,
HalStreamConfiguration) {
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
});
+ ASSERT_TRUE(ret.isOk());
}
- session->close();
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
}
}
}
@@ -762,41 +2133,19 @@
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
- ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
- ALOGI("configureStreams: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
- name,
- [&](auto status, const auto& device) {
- ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(device, nullptr);
- device3_2 = device;
- });
-
- sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
- sp<ICameraDeviceSession> session;
- device3_2->open(
- cb,
- [&](auto status, const auto& newSession) {
- ALOGI("device::open returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(newSession, nullptr);
- session = newSession;
- });
-
camera_metadata_t *staticMeta;
- device3_2->getCameraCharacteristics([&] (Status s,
- CameraMetadata metadata) {
- ASSERT_EQ(Status::OK, s);
- staticMeta =
- reinterpret_cast<camera_metadata_t*>(metadata.data());
- });
- Status ret = isZSLModeAvailable(staticMeta);
- if (Status::METHOD_NOT_SUPPORTED == ret) {
- session->close();
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, env, &session /*out*/,
+ &staticMeta /*out*/);
+
+ Status rc = isZSLModeAvailable(staticMeta);
+ if (Status::METHOD_NOT_SUPPORTED == rc) {
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
continue;
}
- ASSERT_EQ(Status::OK, ret);
+ ASSERT_EQ(Status::OK, rc);
inputStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
@@ -842,15 +2191,18 @@
inputStream, zslStream, outputStream};
StreamConfiguration config = {streams,
StreamConfigurationMode::NORMAL_MODE};
- session->configureStreams(config, [streamId] (Status s,
+ ret = session->configureStreams(config, [streamId] (Status s,
HalStreamConfiguration halConfig) {
ASSERT_EQ(Status::OK, s);
ASSERT_EQ(3u, halConfig.streams.size());
});
+ ASSERT_TRUE(ret.isOk());
}
}
- session->close();
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
}
}
}
@@ -862,42 +2214,19 @@
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
std::vector<AvailableStream> outputBlobStreams;
std::vector<AvailableStream> outputPreviewStreams;
- AvailableStream previewThreshold = {MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT,
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
AvailableStream blobThreshold = {INT32_MAX, INT32_MAX,
static_cast<int32_t>(PixelFormat::BLOB)};
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
- ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
- ALOGI("configureStreams: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
- name,
- [&](auto status, const auto& device) {
- ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(device, nullptr);
- device3_2 = device;
- });
-
- sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
- sp<ICameraDeviceSession> session;
- device3_2->open(
- cb,
- [&](auto status, const auto& newSession) {
- ALOGI("device::open returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(newSession, nullptr);
- session = newSession;
- });
-
camera_metadata_t *staticMeta;
- device3_2->getCameraCharacteristics([&] (Status s,
- CameraMetadata metadata) {
- ASSERT_EQ(Status::OK, s);
- staticMeta =
- reinterpret_cast<camera_metadata_t*>(metadata.data());
- });
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, env, &session /*out*/,
+ &staticMeta /*out*/);
+
outputBlobStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
outputBlobStreams, &blobThreshold));
@@ -925,15 +2254,18 @@
previewStream, blobStream};
StreamConfiguration config = {streams,
StreamConfigurationMode::NORMAL_MODE};
- session->configureStreams(config, [streamId] (Status s,
+ ret = session->configureStreams(config, [streamId] (Status s,
HalStreamConfiguration halConfig) {
ASSERT_EQ(Status::OK, s);
ASSERT_EQ(2u, halConfig.streams.size());
});
+ ASSERT_TRUE(ret.isOk());
}
}
- session->close();
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
}
}
}
@@ -947,38 +2279,16 @@
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
- ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
- ALOGI("configureStreams: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
- name,
- [&](auto status, const auto& device) {
- ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(device, nullptr);
- device3_2 = device;
- });
-
- sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
- sp<ICameraDeviceSession> session;
- device3_2->open(
- cb,
- [&](auto status, const auto& newSession) {
- ALOGI("device::open returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(newSession, nullptr);
- session = newSession;
- });
-
camera_metadata_t *staticMeta;
- device3_2->getCameraCharacteristics([&] (Status s,
- CameraMetadata metadata) {
- ASSERT_EQ(Status::OK, s);
- staticMeta =
- reinterpret_cast<camera_metadata_t*>(metadata.data());
- });
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, env, &session /*out*/,
+ &staticMeta /*out*/);
+
Status rc = isConstrainedModeAvailable(staticMeta);
if (Status::METHOD_NOT_SUPPORTED == rc) {
- session->close();
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
continue;
}
ASSERT_EQ(Status::OK, rc);
@@ -996,12 +2306,13 @@
::android::hardware::hidl_vec<Stream> streams = {stream};
StreamConfiguration config = {streams,
StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
- session->configureStreams(config, [streamId] (Status s,
+ ret = session->configureStreams(config, [streamId] (Status s,
HalStreamConfiguration halConfig) {
ASSERT_EQ(Status::OK, s);
ASSERT_EQ(1u, halConfig.streams.size());
ASSERT_EQ(halConfig.streams[0].id, streamId);
});
+ ASSERT_TRUE(ret.isOk());
stream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (0),
@@ -1011,10 +2322,12 @@
streams[0] = stream;
config = {streams,
StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
- session->configureStreams(config, [streamId] (Status s,
+ ret = session->configureStreams(config, [streamId] (Status s,
HalStreamConfiguration) {
- ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+ ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+ (Status::INTERNAL_ERROR == s));
});
+ ASSERT_TRUE(ret.isOk());
stream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (UINT32_MAX),
@@ -1024,10 +2337,11 @@
streams[0] = stream;
config = {streams,
StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
- session->configureStreams(config, [streamId] (Status s,
+ ret = session->configureStreams(config, [streamId] (Status s,
HalStreamConfiguration) {
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
});
+ ASSERT_TRUE(ret.isOk());
stream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (hfrStream.width),
@@ -1037,12 +2351,15 @@
streams[0] = stream;
config = {streams,
StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
- session->configureStreams(config, [streamId] (Status s,
+ ret = session->configureStreams(config, [streamId] (Status s,
HalStreamConfiguration) {
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
});
+ ASSERT_TRUE(ret.isOk());
- session->close();
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
}
}
}
@@ -1054,42 +2371,19 @@
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
std::vector<AvailableStream> outputBlobStreams;
std::vector<AvailableStream> outputVideoStreams;
- AvailableStream videoThreshold = {MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT,
+ AvailableStream videoThreshold = {kMaxVideoWidth, kMaxVideoHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
- AvailableStream blobThreshold = {MAX_VIDEO_WIDTH, MAX_VIDEO_HEIGHT,
+ AvailableStream blobThreshold = {kMaxVideoWidth, kMaxVideoHeight,
static_cast<int32_t>(PixelFormat::BLOB)};
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
- ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
- ALOGI("configureStreams: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
- name,
- [&](auto status, const auto& device) {
- ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(device, nullptr);
- device3_2 = device;
- });
-
- sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
- sp<ICameraDeviceSession> session;
- device3_2->open(
- cb,
- [&](auto status, const auto& newSession) {
- ALOGI("device::open returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(newSession, nullptr);
- session = newSession;
- });
-
camera_metadata_t *staticMeta;
- device3_2->getCameraCharacteristics([&] (Status s,
- CameraMetadata metadata) {
- ASSERT_EQ(Status::OK, s);
- staticMeta =
- reinterpret_cast<camera_metadata_t*>(metadata.data());
- });
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, env, &session /*out*/,
+ &staticMeta /*out*/);
+
outputBlobStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
outputBlobStreams, &blobThreshold));
@@ -1118,15 +2412,18 @@
videoStream, blobStream};
StreamConfiguration config = {streams,
StreamConfigurationMode::NORMAL_MODE};
- session->configureStreams(config, [streamId] (Status s,
+ ret = session->configureStreams(config, [streamId] (Status s,
HalStreamConfiguration halConfig) {
ASSERT_EQ(Status::OK, s);
ASSERT_EQ(2u, halConfig.streams.size());
});
+ ASSERT_TRUE(ret.isOk());
}
}
- session->close();
+ free_camera_metadata(staticMeta);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
}
}
}
@@ -1135,72 +2432,28 @@
TEST_F(CameraHidlTest, processCaptureRequestPreview) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
- std::vector<AvailableStream> outputPreviewStreams;
- AvailableStream previewThreshold = {MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT,
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
- int32_t streamId = 0;
uint64_t bufferId = 1;
uint32_t frameNumber = 1;
::android::hardware::hidl_vec<uint8_t> settings;
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
- ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
- ALOGI("configureStreams: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
- name,
- [&](auto status, const auto& device) {
- ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(device, nullptr);
- device3_2 = device;
- });
-
- sp<DeviceCb> cb = new DeviceCb(this);
- sp<ICameraDeviceSession> session;
- device3_2->open(
- cb,
- [&](auto status, const auto& newSession) {
- ALOGI("device::open returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(newSession, nullptr);
- session = newSession;
- });
-
- camera_metadata_t *staticMeta;
- device3_2->getCameraCharacteristics([&] (Status s,
- CameraMetadata metadata) {
- ASSERT_EQ(Status::OK, s);
- staticMeta =
- reinterpret_cast<camera_metadata_t*>(metadata.data());
- });
-
- outputPreviewStreams.clear();
- ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
- outputPreviewStreams, &previewThreshold));
- ASSERT_NE(0u, outputPreviewStreams.size());
-
+ Stream previewStream;
HalStreamConfiguration halStreamConfig;
- Stream previewStream = {streamId, StreamType::OUTPUT,
- static_cast<uint32_t> (outputPreviewStreams[0].width),
- static_cast<uint32_t> (outputPreviewStreams[0].height),
- static_cast<PixelFormat> (outputPreviewStreams[0].format),
- 0, 0, StreamRotation::ROTATION_0};
- ::android::hardware::hidl_vec<Stream> streams = {previewStream};
- StreamConfiguration config = {streams,
- StreamConfigurationMode::NORMAL_MODE};
- session->configureStreams(config, [&] (Status s,
- HalStreamConfiguration halConfig) {
- ASSERT_EQ(Status::OK, s);
- ASSERT_EQ(1u, halConfig.streams.size());
- halStreamConfig = halConfig;
- });
+ sp<ICameraDeviceSession> session;
+ configurePreviewStream(name, env, &previewThreshold,
+ &session /*out*/, &previewStream /*out*/,
+ &halStreamConfig /*out*/);
RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
- session->constructDefaultRequestSettings(reqTemplate,
+ Return<void> ret;
+ ret = session->constructDefaultRequestSettings(reqTemplate,
[&](auto status, const auto& req) {
ASSERT_EQ(Status::OK, status);
settings = req; });
+ ASSERT_TRUE(ret.isOk());
sp<GraphicBuffer> gb = new GraphicBuffer(previewStream.width,
previewStream.height,
@@ -1213,49 +2466,61 @@
BufferStatus::OK, nullptr, nullptr};
::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
outputBuffer};
+ StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
+ BufferStatus::ERROR, nullptr, nullptr};
CaptureRequest request = {frameNumber, settings,
- {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr},
- outputBuffers};
+ emptyInputBuffer, outputBuffers};
- std::unique_lock<std::mutex> l(mLock);
- mResultBuffers.clear();
- mResultFrameNumber = frameNumber;
- l.unlock();
-
- ASSERT_EQ(Status::OK, session->processCaptureRequest(request));
-
- l.lock();
- while (0 == mResultBuffers.size()) {
- auto timeout = std::chrono::system_clock::now() +
- std::chrono::seconds(STREAM_BUFFER_TIMEOUT);
- ASSERT_NE(std::cv_status::timeout,
- mResultCondition.wait_until(l, timeout));
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mResultBuffers.clear();
+ mResultFrameNumber = frameNumber;
}
- ASSERT_EQ(BufferStatus::OK, mResultBuffers[0].status);
- ASSERT_EQ(previewStream.id, mResultBuffers[0].streamId);
+ Return<Status> returnStatus = session->processCaptureRequest(
+ request);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
- request.frameNumber++;
- //Empty settings should be supported after the first call
- //for repeating requests.
- request.settings.setToExternal(nullptr, 0, true);
- mResultBuffers.clear();
- mResultFrameNumber++;
- l.unlock();
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ while (0 == mResultBuffers.size()) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kStreamBufferTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mResultCondition.wait_until(l, timeout));
+ }
- ASSERT_EQ(Status::OK, session->processCaptureRequest(request));
+ ASSERT_EQ(BufferStatus::OK, mResultBuffers[0].status);
+ ASSERT_EQ(previewStream.id, mResultBuffers[0].streamId);
- l.lock();
- while (0 == mResultBuffers.size()) {
- auto timeout = std::chrono::system_clock::now() +
- std::chrono::seconds(STREAM_BUFFER_TIMEOUT);
- ASSERT_NE(std::cv_status::timeout,
- mResultCondition.wait_until(l, timeout));
+ request.frameNumber++;
+ //Empty settings should be supported after the first call
+ //for repeating requests.
+ request.settings.setToExternal(nullptr, 0, true);
+ mResultBuffers.clear();
+ mResultFrameNumber++;
}
- ASSERT_EQ(BufferStatus::OK, mResultBuffers[0].status);
- ASSERT_EQ(previewStream.id, mResultBuffers[0].streamId);
- session->close();
+ returnStatus = session->processCaptureRequest(
+ request);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ while (0 == mResultBuffers.size()) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kStreamBufferTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mResultCondition.wait_until(l, timeout));
+ }
+ ASSERT_EQ(BufferStatus::OK, mResultBuffers[0].status);
+ ASSERT_EQ(previewStream.id, mResultBuffers[0].streamId);
+ }
+
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
}
}
}
@@ -1266,65 +2531,20 @@
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
std::vector<AvailableStream> outputPreviewStreams;
- AvailableStream previewThreshold = {MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT,
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
- int32_t streamId = 0;
uint64_t bufferId = 1;
uint32_t frameNumber = 1;
::android::hardware::hidl_vec<uint8_t> settings;
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
- ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
- ALOGI("configureStreams: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
- name,
- [&](auto status, const auto& device) {
- ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(device, nullptr);
- device3_2 = device;
- });
-
- sp<DeviceCb> cb = new DeviceCb(this);
- sp<ICameraDeviceSession> session;
- device3_2->open(
- cb,
- [&](auto status, const auto& newSession) {
- ALOGI("device::open returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(newSession, nullptr);
- session = newSession;
- });
-
- camera_metadata_t *staticMeta;
- device3_2->getCameraCharacteristics([&] (Status s,
- CameraMetadata metadata) {
- ASSERT_EQ(Status::OK, s);
- staticMeta =
- reinterpret_cast<camera_metadata_t*>(metadata.data());
- });
-
- outputPreviewStreams.clear();
- ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
- outputPreviewStreams, &previewThreshold));
- ASSERT_NE(0u, outputPreviewStreams.size());
-
+ Stream previewStream;
HalStreamConfiguration halStreamConfig;
- Stream previewStream = {streamId, StreamType::OUTPUT,
- static_cast<uint32_t> (outputPreviewStreams[0].width),
- static_cast<uint32_t> (outputPreviewStreams[0].height),
- static_cast<PixelFormat> (outputPreviewStreams[0].format),
- 0, 0, StreamRotation::ROTATION_0};
- ::android::hardware::hidl_vec<Stream> streams = {previewStream};
- StreamConfiguration config = {streams,
- StreamConfigurationMode::NORMAL_MODE};
- session->configureStreams(config, [&] (Status s,
- HalStreamConfiguration halConfig) {
- ASSERT_EQ(Status::OK, s);
- ASSERT_EQ(1u, halConfig.streams.size());
- halStreamConfig = halConfig;
- });
+ sp<ICameraDeviceSession> session;
+ configurePreviewStream(name, env, &previewThreshold,
+ &session /*out*/, &previewStream /*out*/,
+ &halStreamConfig /*out*/);
sp<GraphicBuffer> gb = new GraphicBuffer(previewStream.width,
previewStream.height,
@@ -1337,104 +2557,208 @@
BufferStatus::OK, nullptr, nullptr};
::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
outputBuffer};
+ StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
+ BufferStatus::ERROR, nullptr, nullptr};
CaptureRequest request = {frameNumber, settings,
- {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr},
- outputBuffers};
+ emptyInputBuffer, outputBuffers};
//Settings were not correctly initialized, we should fail here
- ASSERT_EQ(Status::INTERNAL_ERROR,
- session->processCaptureRequest(request));
+ Return<Status> returnStatus = session->processCaptureRequest(
+ request);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::INTERNAL_ERROR, returnStatus);
- session->close();
+ Return<void> ret = session->close();
+ ASSERT_TRUE(ret.isOk());
}
}
}
// Check whether an invalid capture request with missing output buffers
// will be reported correctly.
-TEST_F(CameraHidlTest, processCaptureRequestInvalidSingleSnapshot) {
+TEST_F(CameraHidlTest, processCaptureRequestInvalidBuffer) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
std::vector<AvailableStream> outputBlobStreams;
- AvailableStream blobThreshold = {INT32_MAX, INT32_MAX,
- static_cast<int32_t>(PixelFormat::BLOB)};
- int32_t streamId = 0;
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+ uint32_t frameNumber = 1;
+ ::android::hardware::hidl_vec<uint8_t> settings;
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ Stream previewStream;
+ HalStreamConfiguration halStreamConfig;
+ sp<ICameraDeviceSession> session;
+ configurePreviewStream(name, env, &previewThreshold,
+ &session /*out*/, &previewStream /*out*/,
+ &halStreamConfig /*out*/);
+
+ RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+ Return<void> ret;
+ ret = session->constructDefaultRequestSettings(reqTemplate,
+ [&](auto status, const auto& req) {
+ ASSERT_EQ(Status::OK, status);
+ settings = req; });
+ ASSERT_TRUE(ret.isOk());
+
+ ::android::hardware::hidl_vec<StreamBuffer> emptyOutputBuffers;
+ StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
+ BufferStatus::ERROR, nullptr, nullptr};
+ CaptureRequest request = {frameNumber, settings,
+ emptyInputBuffer, emptyOutputBuffers};
+
+ //Output buffers are missing, we should fail here
+ Return<Status> returnStatus = session->processCaptureRequest(
+ request);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::INTERNAL_ERROR,
+ returnStatus);
+
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Generate, trigger and flush a preview request
+TEST_F(CameraHidlTest, flushPreviewRequest) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ std::vector<AvailableStream> outputPreviewStreams;
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
uint64_t bufferId = 1;
uint32_t frameNumber = 1;
::android::hardware::hidl_vec<uint8_t> settings;
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
- ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
- ALOGI("configureStreams: Testing camera device %s", name.c_str());
- env->mProvider->getCameraDeviceInterface_V3_x(
- name,
- [&](auto status, const auto& device) {
- ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(device, nullptr);
- device3_2 = device;
- });
-
- sp<DeviceCb> cb = new DeviceCb(this);
- sp<ICameraDeviceSession> session;
- device3_2->open(
- cb,
- [&](auto status, const auto& newSession) {
- ALOGI("device::open returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(newSession, nullptr);
- session = newSession;
- });
-
- camera_metadata_t *staticMeta;
- device3_2->getCameraCharacteristics([&] (Status s,
- CameraMetadata metadata) {
- ASSERT_EQ(Status::OK, s);
- staticMeta =
- reinterpret_cast<camera_metadata_t*>(metadata.data());
- });
-
- outputBlobStreams.clear();
- ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
- outputBlobStreams, &blobThreshold));
- ASSERT_NE(0u, outputBlobStreams.size());
-
+ Stream previewStream;
HalStreamConfiguration halStreamConfig;
- Stream previewStream = {streamId, StreamType::OUTPUT,
- static_cast<uint32_t> (outputBlobStreams[0].width),
- static_cast<uint32_t> (outputBlobStreams[0].height),
- static_cast<PixelFormat> (outputBlobStreams[0].format),
- 0, 0, StreamRotation::ROTATION_0};
- ::android::hardware::hidl_vec<Stream> streams = {previewStream};
- StreamConfiguration config = {streams,
- StreamConfigurationMode::NORMAL_MODE};
- session->configureStreams(config, [&] (Status s,
- HalStreamConfiguration halConfig) {
- ASSERT_EQ(Status::OK, s);
- ASSERT_EQ(1u, halConfig.streams.size());
- halStreamConfig = halConfig;
- });
+ sp<ICameraDeviceSession> session;
+ configurePreviewStream(name, env, &previewThreshold,
+ &session /*out*/, &previewStream /*out*/,
+ &halStreamConfig /*out*/);
- RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
- session->constructDefaultRequestSettings(reqTemplate,
+ RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+ Return<void> ret;
+ ret = session->constructDefaultRequestSettings(reqTemplate,
[&](auto status, const auto& req) {
ASSERT_EQ(Status::OK, status);
settings = req; });
+ ASSERT_TRUE(ret.isOk());
+ sp<GraphicBuffer> gb = new GraphicBuffer(previewStream.width,
+ previewStream.height,
+ static_cast<int32_t> (halStreamConfig.streams[0].overrideFormat),
+ 1, halStreamConfig.streams[0].producerUsage,
+ halStreamConfig.streams[0].consumerUsage);
+ ASSERT_NE(nullptr, gb.get());
StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
- bufferId, hidl_handle(nullptr), BufferStatus::OK,
- nullptr, nullptr};
- ::android::hardware::hidl_vec<StreamBuffer> outputBuffers;
+ bufferId, hidl_handle(gb->getNativeBuffer()->handle),
+ BufferStatus::OK, nullptr, nullptr};
+ ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
+ outputBuffer};
+ const StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
+ BufferStatus::ERROR, nullptr, nullptr};
CaptureRequest request = {frameNumber, settings,
- {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr},
- outputBuffers};
+ emptyInputBuffer, outputBuffers};
- //Output buffers are missing, we should fail here
- ASSERT_EQ(Status::INTERNAL_ERROR,
- session->processCaptureRequest(request));
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mResultBuffers.clear();
+ mErrors.clear();
+ mResultFrameNumber = frameNumber;
+ }
- session->close();
+ Return<Status> returnStatus = session->processCaptureRequest(
+ request);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+ //Flush before waiting for request to complete.
+ returnStatus = session->flush();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ while ((0 == mResultBuffers.size()) && (0 == mErrors.size())) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kStreamBufferTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mResultCondition.wait_until(l, timeout));
+ }
+
+ if (mErrors.empty()) {
+ ASSERT_EQ(BufferStatus::OK, mResultBuffers[0].status);
+ ASSERT_EQ(previewStream.id, mResultBuffers[0].streamId);
+ } else {
+ for (auto &error : mErrors) {
+ switch (error.errorCode) {
+ case ErrorCode::ERROR_REQUEST:
+ case ErrorCode::ERROR_RESULT:
+ //Expected
+ break;
+ case ErrorCode::ERROR_BUFFER:
+ //Expected as well
+ ASSERT_EQ(frameNumber, error.frameNumber);
+ ASSERT_EQ(previewStream.id, error.errorStreamId);
+ break;
+ case ErrorCode::ERROR_DEVICE:
+ default:
+ FAIL() <<"Unexpected error:" << static_cast<uint32_t> (error.errorCode);
+ }
+ }
+ }
+ }
+
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+ }
+}
+
+// Verify that camera flushes correctly without any pending requests.
+TEST_F(CameraHidlTest, flushEmpty) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ std::vector<AvailableStream> outputPreviewStreams;
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ Stream previewStream;
+ HalStreamConfiguration halStreamConfig;
+ sp<ICameraDeviceSession> session;
+ configurePreviewStream(name, env, &previewThreshold,
+ &session /*out*/, &previewStream /*out*/,
+ &halStreamConfig /*out*/);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ mResultBuffers.clear();
+ mErrors.clear();
+ mResultFrameNumber = 0;
+ }
+
+ Return<Status> returnStatus = session->flush();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::milliseconds(kEmptyFlushTimeoutMSec);
+ ASSERT_EQ(std::cv_status::timeout,
+ mResultCondition.wait_until(l, timeout));
+ ASSERT_TRUE(mErrors.empty());
+ ASSERT_TRUE(mResultBuffers.empty());
+ }
+
+ Return<void> ret = session->close();
+ ASSERT_TRUE(ret.isOk());
}
}
}
@@ -1443,7 +2767,7 @@
// static characteristics.
Status CameraHidlTest::getAvailableOutputStreams(camera_metadata_t *staticMeta,
std::vector<AvailableStream> &outputStreams,
- AvailableStream *threshold) {
+ const AvailableStream *threshold) {
if (nullptr == staticMeta) {
return Status::ILLEGAL_ARGUMENT;
}
@@ -1609,6 +2933,260 @@
return (result.format == format) ? Status::OK : Status::ILLEGAL_ARGUMENT;
}
+// Check whether the camera device supports specific focus mode.
+Status CameraHidlTest::isAutoFocusModeAvailable(
+ ::android::CameraParameters &cameraParams,
+ const char *mode) {
+ ::android::String8 focusModes(cameraParams.get(
+ CameraParameters::KEY_SUPPORTED_FOCUS_MODES));
+ if (focusModes.contains(mode)) {
+ return Status::OK;
+ }
+
+ return Status::METHOD_NOT_SUPPORTED;
+}
+
+// Open a device session and configure a preview stream.
+void CameraHidlTest::configurePreviewStream(const std::string &name,
+ const CameraHidlEnvironment* env,
+ const AvailableStream *previewThreshold,
+ sp<ICameraDeviceSession> *session /*out*/,
+ Stream *previewStream /*out*/,
+ HalStreamConfiguration *halStreamConfig /*out*/) {
+ ASSERT_NE(nullptr, env);
+ ASSERT_NE(nullptr, session);
+ ASSERT_NE(nullptr, previewStream);
+ ASSERT_NE(nullptr, halStreamConfig);
+
+ std::vector<AvailableStream> outputPreviewStreams;
+ ::android::sp<ICameraDevice> device3_2;
+ ALOGI("configureStreams: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+ (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ sp<DeviceCb> cb = new DeviceCb(this);
+ ret = device3_2->open(
+ cb,
+ [&](auto status, const auto& newSession) {
+ ALOGI("device::open returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(newSession, nullptr);
+ *session = newSession;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ camera_metadata_t *staticMeta;
+ ret = device3_2->getCameraCharacteristics([&] (Status s,
+ CameraMetadata metadata) {
+ ASSERT_EQ(Status::OK, s);
+ staticMeta = clone_camera_metadata(
+ reinterpret_cast<const camera_metadata_t*>(metadata.data()));
+ ASSERT_NE(nullptr, staticMeta);
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ outputPreviewStreams.clear();
+ auto rc = getAvailableOutputStreams(staticMeta,
+ outputPreviewStreams, previewThreshold);
+ free_camera_metadata(staticMeta);
+ ASSERT_EQ(Status::OK, rc);
+ ASSERT_FALSE(outputPreviewStreams.empty());
+
+ *previewStream = {0, StreamType::OUTPUT,
+ static_cast<uint32_t> (outputPreviewStreams[0].width),
+ static_cast<uint32_t> (outputPreviewStreams[0].height),
+ static_cast<PixelFormat> (outputPreviewStreams[0].format),
+ 0, 0, StreamRotation::ROTATION_0};
+ ::android::hardware::hidl_vec<Stream> streams = {*previewStream};
+ StreamConfiguration config = {streams,
+ StreamConfigurationMode::NORMAL_MODE};
+ ret = (*session)->configureStreams(config, [&] (Status s,
+ HalStreamConfiguration halConfig) {
+ ASSERT_EQ(Status::OK, s);
+ ASSERT_EQ(1u, halConfig.streams.size());
+ *halStreamConfig = halConfig;
+ });
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Open a device session with empty callbacks and return static metadata.
+void CameraHidlTest::openEmptyDeviceSession(const std::string &name,
+ const CameraHidlEnvironment* env,
+ sp<ICameraDeviceSession> *session /*out*/,
+ camera_metadata_t **staticMeta /*out*/) {
+ ASSERT_NE(nullptr, env);
+ ASSERT_NE(nullptr, session);
+ ASSERT_NE(nullptr, staticMeta);
+
+ ::android::sp<ICameraDevice> device3_2;
+ ALOGI("configureStreams: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+ (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ sp<EmptyDeviceCb> cb = new EmptyDeviceCb();
+ ret = device3_2->open(cb, [&](auto status, const auto& newSession) {
+ ALOGI("device::open returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(newSession, nullptr);
+ *session = newSession;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ ret = device3_2->getCameraCharacteristics([&] (Status s,
+ CameraMetadata metadata) {
+ ASSERT_EQ(Status::OK, s);
+ *staticMeta = clone_camera_metadata(
+ reinterpret_cast<const camera_metadata_t*>(metadata.data()));
+ ASSERT_NE(nullptr, *staticMeta);
+ });
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Open a particular camera device.
+void CameraHidlTest::openCameraDevice(const std::string &name,
+ const CameraHidlEnvironment* env,
+ sp<::android::hardware::camera::device::V1_0::ICameraDevice> *device1 /*out*/) {
+ ASSERT_TRUE(nullptr != env);
+ ASSERT_TRUE(nullptr != device1);
+
+ Return<void> ret;
+ ret = env->mProvider->getCameraDeviceInterface_V1_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V1_x returns status:%d",
+ (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ *device1 = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ sp<Camera1DeviceCb> deviceCb = new Camera1DeviceCb(this);
+ Return<Status> returnStatus = (*device1)->open(deviceCb);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+}
+
+// Initialize and configure a preview window.
+void CameraHidlTest::setupPreviewWindow(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
+ sp<BufferItemConsumer> *bufferItemConsumer /*out*/,
+ sp<BufferItemHander> *bufferHandler /*out*/) {
+ ASSERT_NE(nullptr, device.get());
+ ASSERT_NE(nullptr, bufferItemConsumer);
+ ASSERT_NE(nullptr, bufferHandler);
+
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ *bufferItemConsumer = new BufferItemConsumer(consumer,
+ GraphicBuffer::USAGE_HW_TEXTURE); //Use GLConsumer default usage flags
+ ASSERT_NE(nullptr, (*bufferItemConsumer).get());
+ *bufferHandler = new BufferItemHander(*bufferItemConsumer);
+ ASSERT_NE(nullptr, (*bufferHandler).get());
+ (*bufferItemConsumer)->setFrameAvailableListener(*bufferHandler);
+ sp<Surface> surface = new Surface(producer);
+ sp<PreviewWindowCb> previewCb = new PreviewWindowCb(surface);
+
+ auto rc = device->setPreviewWindow(previewCb);
+ ASSERT_TRUE(rc.isOk());
+ ASSERT_EQ(Status::OK, rc);
+}
+
+// Stop camera preview and close camera.
+void CameraHidlTest::stopPreviewAndClose(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) {
+ Return<void> ret = device->stopPreview();
+ ASSERT_TRUE(ret.isOk());
+
+ ret = device->close();
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Enable a specific camera message type.
+void CameraHidlTest::enableMsgType(unsigned int msgType,
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) {
+ Return<void> ret = device->enableMsgType(msgType);
+ ASSERT_TRUE(ret.isOk());
+
+ Return<bool> returnBoolStatus = device->msgTypeEnabled(msgType);
+ ASSERT_TRUE(returnBoolStatus.isOk());
+ ASSERT_TRUE(returnBoolStatus);
+}
+
+// Disable a specific camera message type.
+void CameraHidlTest::disableMsgType(unsigned int msgType,
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) {
+ Return<void> ret = device->disableMsgType(msgType);
+ ASSERT_TRUE(ret.isOk());
+
+ Return<bool> returnBoolStatus = device->msgTypeEnabled(msgType);
+ ASSERT_TRUE(returnBoolStatus.isOk());
+ ASSERT_FALSE(returnBoolStatus);
+}
+
+// Wait until a specific frame notification arrives.
+void CameraHidlTest::waitForFrameLocked(DataCallbackMsg msgFrame,
+ std::unique_lock<std::mutex> &l) {
+ while (msgFrame != mDataMessageTypeReceived) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kStreamBufferTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout,
+ mResultCondition.wait_until(l, timeout));
+ }
+}
+
+// Start preview on a particular camera device
+void CameraHidlTest::startPreview(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) {
+ Return<Status> returnStatus = device->startPreview();
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+}
+
+// Retrieve camera parameters.
+void CameraHidlTest::getParameters(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
+ CameraParameters *cameraParams /*out*/) {
+ ASSERT_NE(nullptr, cameraParams);
+
+ Return<void> ret;
+ ret = device->getParameters([&] (const ::android::hardware::hidl_string& params) {
+ ASSERT_FALSE(params.empty());
+ ::android::String8 paramString(params.c_str());
+ (*cameraParams).unflatten(paramString);
+ });
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Set camera parameters.
+void CameraHidlTest::setParameters(
+ const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
+ const CameraParameters &cameraParams) {
+ Return<Status> returnStatus = device->setParameters(
+ cameraParams.flatten().string());
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, returnStatus);
+}
+
int main(int argc, char **argv) {
::testing::AddGlobalTestEnvironment(CameraHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
diff --git a/configstore/1.0/ISurfaceFlingerConfigs.hal b/configstore/1.0/ISurfaceFlingerConfigs.hal
index 318590d..58cb9f1 100644
--- a/configstore/1.0/ISurfaceFlingerConfigs.hal
+++ b/configstore/1.0/ISurfaceFlingerConfigs.hal
@@ -41,4 +41,39 @@
vsyncSfEventPhaseOffsetNs() generates (OptionalInt64 value);
useTripleFramebuffer() generates (OptionalBool value);
+
+ /*
+ * Instruct the Render Engine to use EGL_IMG_context_priority hint if
+ * availabe.
+ */
+ useContextPriority() generates(OptionalBool value);
+
+ /*
+ * hasWideColorDisplay indicates that the device has
+ * or can support a wide-color display, e.g. color space
+ * greater than sRGB. Typical display may have same
+ * color primaries as DCI-P3.
+ * Indicate support for this feature by setting
+ * TARGET_HAS_WIDE_COLOR_DISPLAY to true in BoardConfig.mk
+ * This also means that the device is color managed.
+ * A color managed device will use the appropriate
+ * display mode depending on the content on the screen.
+ * Default is sRGB.
+ */
+ hasWideColorDisplay() generates (OptionalBool value);
+
+ /*
+ * hwHdrDisplay indicates that the device has
+ * or can support an HDR (High Dynamic Range) display.
+ * Typically an HDR display is also wide-color.
+ * Indicate support for this feature by setting
+ * TARGET_HAS_HDR_DISPLAY to true in BoardConfig.mk
+ */
+ hasHDRDisplay() generates (OptionalBool value);
+
+ /*
+ * Specify the offset in nanoseconds to add to vsync time when timestamping
+ * present fences.
+ */
+ presentTimeOffsetFromVSyncNs() generates(OptionalInt64 value);
};
diff --git a/configstore/1.0/default/SurfaceFlingerConfigs.cpp b/configstore/1.0/default/SurfaceFlingerConfigs.cpp
index f73ecb4..86e9b35 100644
--- a/configstore/1.0/default/SurfaceFlingerConfigs.cpp
+++ b/configstore/1.0/default/SurfaceFlingerConfigs.cpp
@@ -39,6 +39,46 @@
return Void();
}
+Return<void> SurfaceFlingerConfigs::useContextPriority(useContextPriority_cb _hidl_cb) {
+#ifdef USE_CONTEXT_PRIORITY
+ _hidl_cb({true, USE_CONTEXT_PRIORITY});
+ LOG(INFO) << "SurfaceFlinger useContextPriority=" << USE_CONTEXT_PRIORITY;
+#else
+ _hidl_cb({false, false});
+#endif
+ return Void();
+}
+
+Return<void> SurfaceFlingerConfigs::hasWideColorDisplay(hasWideColorDisplay_cb _hidl_cb) {
+ bool value = false;
+#ifdef HAS_WIDE_COLOR_DISPLAY
+ value = true;
+#endif
+ _hidl_cb({true, value});
+ LOG(INFO) << "SurfaceFlinger Display: " << (value ? "Wide Color" : "Standard Color");
+ return Void();
+}
+
+Return<void> SurfaceFlingerConfigs::hasHDRDisplay(hasHDRDisplay_cb _hidl_cb) {
+ bool value = false;
+#ifdef HAS_HDR_DISPLAY
+ value = true;
+#endif
+ _hidl_cb({true, value});
+ LOG(INFO) << "SurfaceFlinger Display: " << (value ? "HDR" : "SDR");
+ return Void();
+}
+
+Return<void> SurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs(presentTimeOffsetFromVSyncNs_cb _hidl_cb) {
+#ifdef PRESENT_TIME_OFFSET_FROM_VSYNC_NS
+ _hidl_cb({true, PRESENT_TIME_OFFSET_FROM_VSYNC_NS});
+ LOG(INFO) << "SurfaceFlinger presentTimeStampOffsetNs = " << PRESENT_TIME_OFFSET_FROM_VSYNC_NS;
+#else
+ _hidl_cb({false, 0});
+#endif
+ return Void();
+}
+
// Methods from ::android::hidl::base::V1_0::IBase follow.
ISurfaceFlingerConfigs* HIDL_FETCH_ISurfaceFlingerConfigs(const char* /* name */) {
diff --git a/configstore/1.0/default/SurfaceFlingerConfigs.h b/configstore/1.0/default/SurfaceFlingerConfigs.h
index bbb61d6..8378383 100644
--- a/configstore/1.0/default/SurfaceFlingerConfigs.h
+++ b/configstore/1.0/default/SurfaceFlingerConfigs.h
@@ -27,6 +27,10 @@
Return<void> vsyncEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) override;
Return<void> vsyncSfEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) override;
Return<void> useTripleFramebuffer(useTripleFramebuffer_cb _hidl_cb) override;
+ Return<void> useContextPriority(useContextPriority_cb _hidl_cb) override;
+ Return<void> hasWideColorDisplay(hasWideColorDisplay_cb _hidl_cb) override;
+ Return<void> hasHDRDisplay(hasHDRDisplay_cb _hidl_cb) override;
+ Return<void> presentTimeOffsetFromVSyncNs(presentTimeOffsetFromVSyncNs_cb _hidl_cb) override;
// Methods from ::android::hidl::base::V1_0::IBase follow.
diff --git a/configstore/1.0/default/surfaceflinger.mk b/configstore/1.0/default/surfaceflinger.mk
index 49314d7..d824072 100644
--- a/configstore/1.0/default/surfaceflinger.mk
+++ b/configstore/1.0/default/surfaceflinger.mk
@@ -12,3 +12,25 @@
ifeq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),3)
LOCAL_CFLAGS += -DUSE_TRIPLE_FRAMEBUFFER
endif
+
+ifeq ($(TARGET_BOARD_PLATFORM),omap4)
+ LOCAL_CFLAGS += -DUSE_CONTEXT_PRIORITY=1
+endif
+
+ifeq ($(TARGET_BOARD_PLATFORM),s5pc110)
+ LOCAL_CFLAGS += -DUSE_CONTEXT_PRIORITY=1
+endif
+
+ifeq ($(TARGET_HAS_WIDE_COLOR_DISPLAY),true)
+ LOCAL_CFLAGS += -DHAS_WIDE_COLOR_DISPLAY
+endif
+
+ifeq ($(TARGET_HAS_HDR_DISPLAY),true)
+ LOCAL_CFLAGS += -DHAS_HDR_DISPLAY
+endif
+
+ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),)
+ LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=$(PRESENT_TIME_OFFSET_FROM_VSYNC_NS)
+else
+ LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=0
+endif
diff --git a/drm/1.0/ICryptoPlugin.hal b/drm/1.0/ICryptoPlugin.hal
index ca8fa50..0a7fd26 100644
--- a/drm/1.0/ICryptoPlugin.hal
+++ b/drm/1.0/ICryptoPlugin.hal
@@ -99,7 +99,8 @@
* ERROR_DRM_RESOURCE_BUSY if the resources required to perform the
* decryption are not available, ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION
* if required output protections are not active,
- * ERROR_DRM_SESSION_NOT_OPENED if the decrypt session is not opened, or
+ * ERROR_DRM_SESSION_NOT_OPENED if the decrypt session is not opened,
+ * ERROR_DRM_DECRYPT if the decrypt operation fails, and
* ERROR_DRM_CANNOT_HANDLE in other failure cases.
* @return bytesWritten the number of bytes output from the decryption
* @return detailedError if the error is a vendor-specific error, the
diff --git a/drm/1.0/default/TypeConvert.cpp b/drm/1.0/default/TypeConvert.cpp
index ede2a38..3a262c3 100644
--- a/drm/1.0/default/TypeConvert.cpp
+++ b/drm/1.0/default/TypeConvert.cpp
@@ -59,6 +59,9 @@
case android::ERROR_DRM_DEVICE_REVOKED:
status = Status::ERROR_DRM_DEVICE_REVOKED;
break;
+ case android::ERROR_DRM_DECRYPT:
+ status = Status::ERROR_DRM_DECRYPT;
+ break;
default:
ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN",
legacyStatus);
diff --git a/drm/1.0/types.hal b/drm/1.0/types.hal
index 5273044..cea5b16 100644
--- a/drm/1.0/types.hal
+++ b/drm/1.0/types.hal
@@ -90,6 +90,12 @@
ERROR_DRM_DEVICE_REVOKED,
/**
+ * The DRM Plugin must return ERROR_DRM_DECRYPT if the CryptoPlugin
+ * decrypt operation fails.
+ */
+ ERROR_DRM_DECRYPT,
+
+ /**
* ERROR_DRM_UNKNOWN must be returned when a fatal failure occurs and no
* other defined error is appropriate.
*/
diff --git a/graphics/Android.bp b/graphics/Android.bp
index eaa47ae..f4f7db4 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -3,6 +3,7 @@
"allocator/2.0",
"allocator/2.0/default",
"allocator/2.0/vts/functional",
+ "bufferqueue/1.0",
"common/1.0",
"composer/2.1",
"composer/2.1/default",
diff --git a/graphics/bufferqueue/1.0/Android.bp b/graphics/bufferqueue/1.0/Android.bp
new file mode 100644
index 0000000..4ba764f
--- /dev/null
+++ b/graphics/bufferqueue/1.0/Android.bp
@@ -0,0 +1,70 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+ name: "android.hardware.graphics.bufferqueue@1.0_hal",
+ srcs: [
+ "IGraphicBufferProducer.hal",
+ "IProducerListener.hal",
+ ],
+}
+
+genrule {
+ name: "android.hardware.graphics.bufferqueue@1.0_genc++",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.bufferqueue@1.0",
+ srcs: [
+ ":android.hardware.graphics.bufferqueue@1.0_hal",
+ ],
+ out: [
+ "android/hardware/graphics/bufferqueue/1.0/GraphicBufferProducerAll.cpp",
+ "android/hardware/graphics/bufferqueue/1.0/ProducerListenerAll.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.graphics.bufferqueue@1.0_genc++_headers",
+ tools: ["hidl-gen"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.bufferqueue@1.0",
+ srcs: [
+ ":android.hardware.graphics.bufferqueue@1.0_hal",
+ ],
+ out: [
+ "android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h",
+ "android/hardware/graphics/bufferqueue/1.0/IHwGraphicBufferProducer.h",
+ "android/hardware/graphics/bufferqueue/1.0/BnHwGraphicBufferProducer.h",
+ "android/hardware/graphics/bufferqueue/1.0/BpHwGraphicBufferProducer.h",
+ "android/hardware/graphics/bufferqueue/1.0/BsGraphicBufferProducer.h",
+ "android/hardware/graphics/bufferqueue/1.0/IProducerListener.h",
+ "android/hardware/graphics/bufferqueue/1.0/IHwProducerListener.h",
+ "android/hardware/graphics/bufferqueue/1.0/BnHwProducerListener.h",
+ "android/hardware/graphics/bufferqueue/1.0/BpHwProducerListener.h",
+ "android/hardware/graphics/bufferqueue/1.0/BsProducerListener.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.graphics.bufferqueue@1.0",
+ generated_sources: ["android.hardware.graphics.bufferqueue@1.0_genc++"],
+ generated_headers: ["android.hardware.graphics.bufferqueue@1.0_genc++_headers"],
+ export_generated_headers: ["android.hardware.graphics.bufferqueue@1.0_genc++_headers"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.media@1.0",
+ "android.hidl.base@1.0",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.media@1.0",
+ "android.hidl.base@1.0",
+ ],
+}
diff --git a/media/omx/1.0/IOmxBufferProducer.hal b/graphics/bufferqueue/1.0/IGraphicBufferProducer.hal
similarity index 95%
rename from media/omx/1.0/IOmxBufferProducer.hal
rename to graphics/bufferqueue/1.0/IGraphicBufferProducer.hal
index 7e2172b..c59a16c 100644
--- a/media/omx/1.0/IOmxBufferProducer.hal
+++ b/graphics/bufferqueue/1.0/IGraphicBufferProducer.hal
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -14,20 +14,29 @@
* limitations under the License.
*/
-package android.hardware.media.omx@1.0;
+package android.hardware.graphics.bufferqueue@1.0;
+
+import android.hardware.media@1.0::Fence;
+import android.hardware.media@1.0::AnwBuffer;
+import android.hardware.media@1.0::Rect;
+import android.hardware.media@1.0::Region;
import android.hardware.graphics.common@1.0::Dataspace;
import android.hardware.graphics.common@1.0::PixelFormat;
-import android.hardware.media@1.0::types;
-import IOmxProducerListener;
+import IProducerListener;
/**
* Ref: frameworks/native/include/gui/IGraphicBufferProducer.h:
* IGraphicBufferProducer
* This is a wrapper/wrapped HAL interface for the actual binder interface.
*/
-interface IOmxBufferProducer {
+interface IGraphicBufferProducer {
+
+ /**
+ * Type for return values of functions in IGraphicBufferProducer.
+ */
+ typedef int32_t Status;
/**
* Ref: frameworks/native/include/ui/FenceTime.h: FenceTime::Snapshot
@@ -142,7 +151,7 @@
/**
* requestBuffer requests a new buffer for the given index. The server (i.e.
- * the IOmxBufferProducer implementation) assigns the newly created
+ * the IProducerListener implementation) assigns the newly created
* buffer to the given slot index, and the client is expected to mirror the
* slot->buffer mapping so that it's not necessary to transfer an
* AnwBuffer for every dequeue operation.
@@ -466,12 +475,12 @@
);
/**
- * connect attempts to connect a client API to the IOmxBufferProducer.
- * This must be called before any other IOmxBufferProducer methods are
+ * connect attempts to connect a client API to the IGraphicBufferProducer.
+ * This must be called before any other IGraphicBufferProducer methods are
* called except for getAllocator. A consumer must be already connected.
*
* This method will fail if the connect was previously called on the
- * IOmxBufferProducer and no corresponding disconnect call was made.
+ * IGraphicBufferProducer and no corresponding disconnect call was made.
*
* The listener is an optional binder callback object that can be used if
* the producer wants to be notified when the consumer releases a buffer
@@ -506,7 +515,7 @@
* should be treated as opaque fatal unrecoverable errors.
*/
connect(
- IOmxProducerListener listener,
+ IProducerListener listener,
int32_t api,
bool producerControlledByApp
) generates (
@@ -516,8 +525,8 @@
/**
* disconnect attempts to disconnect a client API from the
- * IOmxBufferProducer. Calling this method will cause any subsequent
- * calls to other IOmxBufferProducer methods to fail except for
+ * IGraphicBufferProducer. Calling this method will cause any subsequent
+ * calls to other IGraphicBufferProducer methods to fail except for
* getAllocator and connect. Successfully calling connect after this will
* allow the other methods to succeed again.
*
@@ -526,7 +535,7 @@
* Alternatively if mode is AllLocal, then the API value is ignored, and any API
* connected from the same PID calling disconnect will be disconnected.
*
- * Disconnecting from an abandoned IOmxBufferProducer is legal and
+ * Disconnecting from an abandoned IGraphicBufferProducer is legal and
* is considered a no-op.
*
* Return of a value other than NO_ERROR means an error has occurred:
@@ -543,7 +552,7 @@
);
/**
- * Attaches a sideband buffer stream to the IOmxBufferProducer.
+ * Attaches a sideband buffer stream to the IGraphicBufferProducer.
*
* A sideband stream is a device-specific mechanism for passing buffers
* from the producer to the consumer without using dequeueBuffer/
diff --git a/media/omx/1.0/IOmxProducerListener.hal b/graphics/bufferqueue/1.0/IProducerListener.hal
similarity index 91%
rename from media/omx/1.0/IOmxProducerListener.hal
rename to graphics/bufferqueue/1.0/IProducerListener.hal
index 7fde93b..206a500 100644
--- a/media/omx/1.0/IOmxProducerListener.hal
+++ b/graphics/bufferqueue/1.0/IProducerListener.hal
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-package android.hardware.media.omx@1.0;
+package android.hardware.graphics.bufferqueue@1.0;
/**
* Ref: frameworks/native/include/gui/IProducerListener.h: IProducerListener
* This is a wrapper/wrapped HAL interface for the actual binder interface.
*/
-interface IOmxProducerListener {
+interface IProducerListener {
oneway onBufferReleased();
needsReleaseNotify() generates (bool result);
};
diff --git a/graphics/common/1.0/types.hal b/graphics/common/1.0/types.hal
index 1ddd892..dfecec1 100644
--- a/graphics/common/1.0/types.hal
+++ b/graphics/common/1.0/types.hal
@@ -1354,10 +1354,12 @@
*
* PC/Internet (sRGB) Gamma Correction (GC):
*
- * if Vlinear ≤ 0.0031308
+ * if Vlinear ≤ 0.0030186
* Vnonlinear = 12.92 * Vlinear
* else
* Vnonlinear = 1.055 * (Vlinear)^(1/2.4) – 0.055
+ *
+ * Note: In most cases sRGB transfer function will be fine.
*/
DISPLAY_P3 = 9
};
diff --git a/media/omx/1.0/Android.bp b/media/omx/1.0/Android.bp
index 85d15ae..81dd617 100644
--- a/media/omx/1.0/Android.bp
+++ b/media/omx/1.0/Android.bp
@@ -6,11 +6,9 @@
"types.hal",
"IGraphicBufferSource.hal",
"IOmx.hal",
- "IOmxBufferProducer.hal",
"IOmxBufferSource.hal",
"IOmxNode.hal",
"IOmxObserver.hal",
- "IOmxProducerListener.hal",
],
}
@@ -25,11 +23,9 @@
"android/hardware/media/omx/1.0/types.cpp",
"android/hardware/media/omx/1.0/GraphicBufferSourceAll.cpp",
"android/hardware/media/omx/1.0/OmxAll.cpp",
- "android/hardware/media/omx/1.0/OmxBufferProducerAll.cpp",
"android/hardware/media/omx/1.0/OmxBufferSourceAll.cpp",
"android/hardware/media/omx/1.0/OmxNodeAll.cpp",
"android/hardware/media/omx/1.0/OmxObserverAll.cpp",
- "android/hardware/media/omx/1.0/OmxProducerListenerAll.cpp",
],
}
@@ -52,11 +48,6 @@
"android/hardware/media/omx/1.0/BnHwOmx.h",
"android/hardware/media/omx/1.0/BpHwOmx.h",
"android/hardware/media/omx/1.0/BsOmx.h",
- "android/hardware/media/omx/1.0/IOmxBufferProducer.h",
- "android/hardware/media/omx/1.0/IHwOmxBufferProducer.h",
- "android/hardware/media/omx/1.0/BnHwOmxBufferProducer.h",
- "android/hardware/media/omx/1.0/BpHwOmxBufferProducer.h",
- "android/hardware/media/omx/1.0/BsOmxBufferProducer.h",
"android/hardware/media/omx/1.0/IOmxBufferSource.h",
"android/hardware/media/omx/1.0/IHwOmxBufferSource.h",
"android/hardware/media/omx/1.0/BnHwOmxBufferSource.h",
@@ -72,11 +63,6 @@
"android/hardware/media/omx/1.0/BnHwOmxObserver.h",
"android/hardware/media/omx/1.0/BpHwOmxObserver.h",
"android/hardware/media/omx/1.0/BsOmxObserver.h",
- "android/hardware/media/omx/1.0/IOmxProducerListener.h",
- "android/hardware/media/omx/1.0/IHwOmxProducerListener.h",
- "android/hardware/media/omx/1.0/BnHwOmxProducerListener.h",
- "android/hardware/media/omx/1.0/BpHwOmxProducerListener.h",
- "android/hardware/media/omx/1.0/BsOmxProducerListener.h",
],
}
@@ -92,6 +78,7 @@
"liblog",
"libutils",
"libcutils",
+ "android.hardware.graphics.bufferqueue@1.0",
"android.hardware.graphics.common@1.0",
"android.hardware.media@1.0",
"android.hidl.base@1.0",
@@ -101,6 +88,7 @@
"libhidltransport",
"libhwbinder",
"libutils",
+ "android.hardware.graphics.bufferqueue@1.0",
"android.hardware.graphics.common@1.0",
"android.hardware.media@1.0",
"android.hidl.base@1.0",
diff --git a/media/omx/1.0/IOmx.hal b/media/omx/1.0/IOmx.hal
index acb1aae..78d4b32 100644
--- a/media/omx/1.0/IOmx.hal
+++ b/media/omx/1.0/IOmx.hal
@@ -16,11 +16,11 @@
package android.hardware.media.omx@1.0;
+import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer;
import android.hardware.media@1.0::types;
import IOmxNode;
import IOmxObserver;
-import IOmxBufferProducer;
import IGraphicBufferSource;
/**
@@ -76,7 +76,7 @@
createInputSurface(
) generates (
Status status,
- IOmxBufferProducer producer,
+ IGraphicBufferProducer producer,
IGraphicBufferSource source
);
};
diff --git a/radio/1.0/IRadio.hal b/radio/1.0/IRadio.hal
index b3e3e98..0b1bf40 100644
--- a/radio/1.0/IRadio.hal
+++ b/radio/1.0/IRadio.hal
@@ -630,7 +630,6 @@
/*
* Scans for available networks
- * This request must not respond until the new operator is selected and registered.
*
* @param serial Serial number of request.
*
diff --git a/radio/1.0/IRadioResponse.hal b/radio/1.0/IRadioResponse.hal
index cd0899a..bf50792 100644
--- a/radio/1.0/IRadioResponse.hal
+++ b/radio/1.0/IRadioResponse.hal
@@ -787,10 +787,13 @@
*
* Valid errors returned:
* RadioError:NONE
- * RadioError:INVALID_ARGUMENTS
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:OPERATION_NOT_ALLOWED
- * RadioError:GENERIC_FAILURE
+ * RadioError:ABORTED
+ * RadioError:DEVICE_IN_USE
+ * RadioError:INTERNAL_ERR
+ * RadioError:NO_MEMORY
+ * RadioError:MODEM_ERR
*/
oneway getAvailableNetworksResponse(RadioResponseInfo info,
vec<OperatorInfo> networkInfos);
diff --git a/radio/1.0/types.hal b/radio/1.0/types.hal
index 7c1d143..9b904a5 100644
--- a/radio/1.0/types.hal
+++ b/radio/1.0/types.hal
@@ -86,9 +86,11 @@
SS_MODIFIED_TO_SS = 27, // SS request modified to different SS request
LCE_NOT_SUPPORTED = 36, // LCE service not supported(36 in RILConstants.java)
NO_MEMORY = 37, // Not sufficient memory to process the request
- INTERNAL_ERR = 38, // Hit unexpected vendor internal error scenario
+ INTERNAL_ERR = 38, // Modem hit unexpected error scenario while handling
+ // this request
SYSTEM_ERR = 39, // Hit platform or system error
- MODEM_ERR = 40, // Hit unexpected modem error
+ MODEM_ERR = 40, // Vendor RIL got unexpected or incorrect response
+ // from modem for this request
INVALID_STATE = 41, // Unexpected request for the current state
NO_RESOURCES = 42, // Not sufficient resource to process the request
SIM_ERR = 43, // Received error from SIM card
diff --git a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
index 1298e16..d21b512 100644
--- a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
+++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
@@ -20,6 +20,7 @@
#include <android/hardware/sensors/1.0/types.h>
#include <android/log.h>
#include <cutils/ashmem.h>
+#include <utils/SystemClock.h>
#include <VtsHalHidlTargetTestBase.h>
#include <hardware/sensors.h> // for sensor type strings
@@ -42,6 +43,7 @@
using namespace ::android::hardware::sensors::V1_0;
// Test environment for sensors
+class SensorsHidlTest;
class SensorsHidlEnvironment : public ::testing::Environment {
public:
// get the test environment singleton
@@ -50,9 +52,6 @@
return instance;
}
- // sensors hidl service
- sp<ISensors> sensors;
-
virtual void SetUp();
virtual void TearDown();
@@ -64,10 +63,15 @@
void setCollection(bool enable);
private:
+ friend SensorsHidlTest;
+ // sensors hidl service
+ sp<ISensors> sensors;
+
SensorsHidlEnvironment() {}
void addEvent(const Event& ev);
void startPollingThread();
+ void resetHal();
static void pollingThread(SensorsHidlEnvironment* env, std::shared_ptr<bool> stop);
bool collectionEnabled;
@@ -80,9 +84,9 @@
};
void SensorsHidlEnvironment::SetUp() {
- sensors = ::testing::VtsHalHidlTargetTestBase::getService<ISensors>();
- ALOGI_IF(sensors, "sensors is not nullptr, %p", sensors.get());
- ASSERT_NE(sensors, nullptr);
+ resetHal();
+
+ ASSERT_NE(sensors, nullptr) << "sensors is nullptr, cannot get hidl service";
collectionEnabled = false;
startPollingThread();
@@ -93,14 +97,77 @@
}
void SensorsHidlEnvironment::TearDown() {
- ALOGI("TearDown SensorsHidlEnvironement");
-
if (stopThread) {
*stopThread = true;
}
pollThread.detach();
}
+void SensorsHidlEnvironment::resetHal() {
+ // wait upto 100ms * 10 = 1s for hidl service.
+ constexpr auto RETRY_DELAY = std::chrono::milliseconds(100);
+
+ std::string step;
+ bool succeed = false;
+ for (size_t retry = 10; retry > 0; --retry) {
+ // this do ... while is for easy error handling
+ do {
+ step = "getService()";
+ sensors = ISensors::getService();
+ if (sensors == nullptr) {
+ break;
+ }
+
+ step = "poll() check";
+ // Poke ISensor service. If it has lingering connection from previous generation of
+ // system server, it will kill itself. There is no intention to handle the poll result,
+ // which will be done since the size is 0.
+ if(!sensors->poll(0, [](auto, const auto &, const auto &) {}).isOk()) {
+ break;
+ }
+
+ step = "getSensorList";
+ std::vector<SensorInfo> sensorList;
+ if (!sensors->getSensorsList(
+ [&] (const ::android::hardware::hidl_vec<SensorInfo> &list) {
+ sensorList.reserve(list.size());
+ for (size_t i = 0; i < list.size(); ++i) {
+ sensorList.push_back(list[i]);
+ }
+ }).isOk()) {
+ break;
+ }
+
+ // stop each sensor individually
+ step = "stop each sensor";
+ bool ok = true;
+ for (const auto &i : sensorList) {
+ if (!sensors->activate(i.sensorHandle, false).isOk()) {
+ ok = false;
+ break;
+ }
+ }
+ if (!ok) {
+ break;
+ }
+
+ // mark it done
+ step = "done";
+ succeed = true;
+ } while(0);
+
+ if (succeed) {
+ return;
+ }
+
+ // Delay 100ms before retry, hidl service is expected to come up in short time after crash.
+ ALOGI("%s unsuccessful, try again soon (remaining retry %zu).", step.c_str(), retry - 1);
+ std::this_thread::sleep_for(RETRY_DELAY);
+ }
+
+ sensors = nullptr;
+}
+
void SensorsHidlEnvironment::catEvents(std::vector<Event>* output) {
std::lock_guard<std::mutex> lock(events_mutex);
if (output) {
@@ -257,6 +324,10 @@
}
break;
}
+ case SharedMemType::GRALLOC: {
+
+ break;
+ }
default:
break;
}
@@ -308,6 +379,58 @@
return m;
}
+class SensorEventsChecker {
+ public:
+ virtual bool check(const std::vector<Event> &events, std::string *out) const = 0;
+ virtual ~SensorEventsChecker() {}
+};
+
+class NullChecker : public SensorEventsChecker {
+ public:
+ virtual bool check(const std::vector<Event> &, std::string *) const {
+ return true;
+ }
+};
+
+class SensorEventPerEventChecker : public SensorEventsChecker {
+ public:
+ virtual bool checkEvent(const Event &event, std::string *out) const = 0;
+ virtual bool check(const std::vector<Event> &events, std::string *out) const {
+ for (const auto &e : events) {
+ if (!checkEvent(e, out)) {
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+class Vec3NormChecker : public SensorEventPerEventChecker {
+ public:
+ Vec3NormChecker(float min, float max) : mRange(min, max) {}
+ static Vec3NormChecker byNominal(float nominal, float allowedError) {
+ return Vec3NormChecker(nominal - allowedError, nominal + allowedError);
+ }
+
+ virtual bool checkEvent(const Event &event, std::string *out) const {
+ Vec3 v = event.u.vec3;
+ float norm = std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
+ if (norm < mRange.first || norm > mRange.second) {
+ if (out != nullptr) {
+ std::ostringstream ss;
+ ss << "Event @ " << event.timestamp << " (" << v.x << ", " << v.y << ", " << v.z << ")"
+ << " has norm " << norm << ", which is beyond range"
+ << " [" << mRange.first << ", " << mRange.second << "]";
+ *out = ss.str();
+ }
+ return false;
+ }
+ return true;
+ }
+ protected:
+ std::pair<float, float> mRange;
+};
+
// The main test class for SENSORS HIDL HAL.
class SensorsHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
@@ -332,6 +455,7 @@
protected:
SensorInfo defaultSensorByType(SensorType type);
+ std::vector<SensorInfo> getSensorsList();
std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
bool clearBeforeStart = true, bool changeCollection = true);
@@ -393,16 +517,36 @@
return (int32_t) type > 0;
}
- static bool typeMatchStringType(SensorType type, const hidl_string& stringType);
- static bool typeMatchReportMode(SensorType type, SensorFlagBits reportMode);
- static bool delayMatchReportMode(int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode);
+ void testStreamingOperation(SensorType type,
+ std::chrono::nanoseconds samplingPeriod,
+ std::chrono::seconds duration,
+ const SensorEventsChecker &checker);
+ void testSamplingRateHotSwitchOperation(SensorType type);
+ void testBatchingOperation(SensorType type);
+ void testDirectReportOperation(
+ SensorType type, SharedMemType memType, RateLevel rate, const SensorEventsChecker &checker);
+
+ static void assertTypeMatchStringType(SensorType type, const hidl_string& stringType);
+ static void assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode);
+ static void assertDelayMatchReportMode(
+ int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode);
static SensorFlagBits expectedReportModeForType(SensorType type);
+ static bool isDirectReportRateSupported(SensorInfo sensor, RateLevel rate);
+ static bool isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type);
+
+ // checkers
+ static const Vec3NormChecker sAccelNormChecker;
+ static const Vec3NormChecker sGyroNormChecker;
// all sensors and direct channnels used
std::unordered_set<int32_t> mSensorHandles;
std::unordered_set<int32_t> mDirectChannelHandles;
};
+const Vec3NormChecker SensorsHidlTest::sAccelNormChecker(
+ Vec3NormChecker::byNominal(GRAVITY_EARTH, 0.5f/*m/s^2*/));
+const Vec3NormChecker SensorsHidlTest::sGyroNormChecker(
+ Vec3NormChecker::byNominal(0.f, 0.1f/*rad/s*/));
Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
// If activating a sensor, add the handle in a set so that when test fails it can be turned off.
@@ -433,7 +577,7 @@
std::vector<Event> SensorsHidlTest::collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
bool clearBeforeStart, bool changeCollection) {
std::vector<Event> events;
- constexpr useconds_t SLEEP_GRANULARITY = 100*1000; //gradularity 100 ms
+ constexpr useconds_t SLEEP_GRANULARITY = 100*1000; //granularity 100 ms
ALOGI("collect max of %zu events for %d us, clearBeforeStart %d",
nEventLimit, timeLimitUs, clearBeforeStart);
@@ -464,94 +608,93 @@
return events;
}
-bool SensorsHidlTest::typeMatchStringType(SensorType type, const hidl_string& stringType) {
+void SensorsHidlTest::assertTypeMatchStringType(SensorType type, const hidl_string& stringType) {
if (type >= SensorType::DEVICE_PRIVATE_BASE) {
- return true;
+ return;
}
- bool res = true;
switch (type) {
#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type) \
- case SensorType::type: res = stringType == SENSOR_STRING_TYPE_ ## type;\
- break;\
-
+ case SensorType::type: ASSERT_STREQ(SENSOR_STRING_TYPE_ ## type, stringType); break;
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE);
CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO);
- CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT);
default:
- ALOGW("Type %d is not checked, stringType = %s", (int)type, stringType.c_str());
+ FAIL() << "Type " << static_cast<int>(type) << " in android defined range is not checked, "
+ << "stringType = " << stringType;
#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE
}
- return res;
}
-bool SensorsHidlTest::typeMatchReportMode(SensorType type, SensorFlagBits reportMode) {
+void SensorsHidlTest::assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode) {
if (type >= SensorType::DEVICE_PRIVATE_BASE) {
- return true;
+ return;
}
SensorFlagBits expected = expectedReportModeForType(type);
- return expected == (SensorFlagBits)-1 || expected == reportMode;
+ ASSERT_TRUE(expected == (SensorFlagBits) -1 || expected == reportMode)
+ << "reportMode=" << static_cast<int>(reportMode)
+ << "expected=" << static_cast<int>(expected);
}
-bool SensorsHidlTest::delayMatchReportMode(
+void SensorsHidlTest::assertDelayMatchReportMode(
int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode) {
- bool res = true;
switch(reportMode) {
case SensorFlagBits::CONTINUOUS_MODE:
- res = (minDelay > 0) && (maxDelay >= 0);
+ ASSERT_LT(0, minDelay);
+ ASSERT_LE(0, maxDelay);
break;
case SensorFlagBits::ON_CHANGE_MODE:
- //TODO: current implementation does not satisfy minDelay == 0 on Proximity
- res = (minDelay >= 0) && (maxDelay >= 0);
- //res = (minDelay == 0) && (maxDelay >= 0);
+ ASSERT_LE(0, minDelay);
+ ASSERT_LE(0, maxDelay);
break;
case SensorFlagBits::ONE_SHOT_MODE:
- res = (minDelay == -1) && (maxDelay == 0);
+ ASSERT_EQ(-1, minDelay);
+ ASSERT_EQ(0, maxDelay);
break;
case SensorFlagBits::SPECIAL_REPORTING_MODE:
- res = (minDelay == 0) && (maxDelay == 0);
+ // do not enforce anything for special reporting mode
break;
default:
- res = false;
+ FAIL() << "Report mode " << static_cast<int>(reportMode) << " not checked";
}
-
- return res;
}
+// return -1 means no expectation for this type
SensorFlagBits SensorsHidlTest::expectedReportModeForType(SensorType type) {
switch (type) {
case SensorType::ACCELEROMETER:
@@ -599,6 +742,24 @@
}
}
+bool SensorsHidlTest::isDirectReportRateSupported(SensorInfo sensor, RateLevel rate) {
+ unsigned int r =
+ static_cast<unsigned int>(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT)
+ >> static_cast<unsigned int>(SensorFlagShift::DIRECT_REPORT);
+ return r >= static_cast<unsigned int>(rate);
+}
+
+bool SensorsHidlTest::isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type) {
+ switch (type) {
+ case SharedMemType::ASHMEM:
+ return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM) != 0;
+ case SharedMemType::GRALLOC:
+ return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_GRALLOC) != 0;
+ default:
+ return false;
+ }
+}
+
SensorInfo SensorsHidlTest::defaultSensorByType(SensorType type) {
SensorInfo ret;
@@ -617,60 +778,142 @@
return ret;
}
+std::vector<SensorInfo> SensorsHidlTest::getSensorsList() {
+ std::vector<SensorInfo> ret;
+
+ S()->getSensorsList(
+ [&] (const auto &list) {
+ const size_t count = list.size();
+ ret.reserve(list.size());
+ for (size_t i = 0; i < count; ++i) {
+ ret.push_back(list[i]);
+ }
+ });
+
+ return ret;
+}
+
// Test if sensor list returned is valid
TEST_F(SensorsHidlTest, SensorListValid) {
S()->getSensorsList(
[&] (const auto &list) {
const size_t count = list.size();
for (size_t i = 0; i < count; ++i) {
- auto &s = list[i];
- ALOGV("\t%zu: handle=%#08x type=%d name=%s",
- i, s.sensorHandle, (int)s.type, s.name.c_str());
+ const auto &s = list[i];
+ SCOPED_TRACE(::testing::Message() << i << "/" << count << ": "
+ << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+ << s.sensorHandle << std::dec
+ << " type=" << static_cast<int>(s.type)
+ << " name=" << s.name);
// Test non-empty type string
- ASSERT_FALSE(s.typeAsString.empty());
+ EXPECT_FALSE(s.typeAsString.empty());
// Test defined type matches defined string type
- ASSERT_TRUE(typeMatchStringType(s.type, s.typeAsString));
+ EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString));
// Test if all sensor has name and vendor
- ASSERT_FALSE(s.name.empty());
- ASSERT_FALSE(s.vendor.empty());
+ EXPECT_FALSE(s.name.empty());
+ EXPECT_FALSE(s.vendor.empty());
// Test power > 0, maxRange > 0
- ASSERT_GE(s.power, 0);
- ASSERT_GT(s.maxRange, 0);
+ EXPECT_LE(0, s.power);
+ EXPECT_LT(0, s.maxRange);
// Info type, should have no sensor
- ASSERT_FALSE(
+ EXPECT_FALSE(
s.type == SensorType::ADDITIONAL_INFO
|| s.type == SensorType::META_DATA);
// Test fifoMax >= fifoReserved
- ALOGV("max reserve = %d, %d", s.fifoMaxEventCount, s.fifoReservedEventCount);
- ASSERT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount);
+ EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount)
+ << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount;
// Test Reporting mode valid
- ASSERT_TRUE(typeMatchReportMode(s.type, extractReportMode(s.flags)));
+ EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags)));
// Test min max are in the right order
- ASSERT_LE(s.minDelay, s.maxDelay);
+ EXPECT_LE(s.minDelay, s.maxDelay);
// Test min/max delay matches reporting mode
- ASSERT_TRUE(delayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
+ EXPECT_NO_FATAL_FAILURE(
+ assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
}
});
}
-// Test if sensor hal can do normal accelerometer streaming properly
-TEST_F(SensorsHidlTest, NormalAccelerometerStreamingOperation) {
+// Test if sensor list returned is valid
+TEST_F(SensorsHidlTest, SetOperationMode) {
+ std::vector<SensorInfo> sensorList = getSensorsList();
+ bool needOperationModeSupport =
+ std::any_of(sensorList.begin(), sensorList.end(),
+ [] (const auto& s) {
+ return (s.flags & SensorFlagBits::DATA_INJECTION) != 0;
+ });
+ if (!needOperationModeSupport) {
+ return;
+ }
+
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL));
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::DATA_INJECTION));
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL));
+}
+
+// Test if sensor list returned is valid
+TEST_F(SensorsHidlTest, InjectSensorEventData) {
+ std::vector<SensorInfo> sensorList = getSensorsList();
+ std::vector<SensorInfo> sensorSupportInjection;
+
+ bool needOperationModeSupport =
+ std::any_of(sensorList.begin(), sensorList.end(),
+ [&sensorSupportInjection] (const auto& s) {
+ bool ret = (s.flags & SensorFlagBits::DATA_INJECTION) != 0;
+ if (ret) {
+ sensorSupportInjection.push_back(s);
+ }
+ return ret;
+ });
+ if (!needOperationModeSupport) {
+ return;
+ }
+
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL));
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::DATA_INJECTION));
+
+ for (const auto &s : sensorSupportInjection) {
+ switch (s.type) {
+ case SensorType::ACCELEROMETER:
+ case SensorType::GYROSCOPE:
+ case SensorType::MAGNETIC_FIELD: {
+ usleep(100000); // sleep 100ms
+
+ Event dummy;
+ dummy.timestamp = android::elapsedRealtimeNano();
+ dummy.sensorType = s.type;
+ dummy.sensorHandle = s.sensorHandle;
+ Vec3 v = {1, 2, 3, SensorStatus::ACCURACY_HIGH};
+ dummy.u.vec3 = v;
+
+ EXPECT_EQ(Result::OK, S()->injectSensorData(dummy));
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL));
+}
+
+void SensorsHidlTest::testStreamingOperation(SensorType type,
+ std::chrono::nanoseconds samplingPeriod,
+ std::chrono::seconds duration,
+ const SensorEventsChecker &checker) {
std::vector<Event> events;
- constexpr int64_t samplingPeriodInNs = 20ull*1000*1000; // 20ms
- constexpr int64_t batchingPeriodInNs = 0; // no batching
- constexpr useconds_t minTimeUs = 5*1000*1000; // 5 s
- constexpr size_t minNEvent = 100; // at lease 100 events
- constexpr SensorType type = SensorType::ACCELEROMETER;
+ const int64_t samplingPeriodInNs = samplingPeriod.count();
+ const int64_t batchingPeriodInNs = 0; // no batching
+ const useconds_t minTimeUs = std::chrono::microseconds(duration).count();
+ const size_t minNEvent = duration / samplingPeriod;
SensorInfo sensor = defaultSensorByType(type);
@@ -679,6 +922,11 @@
return;
}
+ if (std::chrono::microseconds(sensor.minDelay) > samplingPeriod) {
+ // rate not supported
+ return;
+ }
+
int32_t handle = sensor.sensorHandle;
ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
@@ -691,90 +939,110 @@
ASSERT_GT(events.size(), 0u);
size_t nRealEvent = 0;
+ bool handleMismatchReported = false;
+ bool metaSensorTypeErrorReported = false;
for (auto & e : events) {
if (e.sensorType == type) {
-
- ASSERT_EQ(e.sensorHandle, handle);
-
- Vec3 acc = e.u.vec3;
-
- double gravityNorm = std::sqrt(acc.x * acc.x + acc.y * acc.y + acc.z * acc.z);
- ALOGV("Norm = %f", gravityNorm);
-
- // assert this is earth gravity
- ASSERT_TRUE(std::fabs(gravityNorm - GRAVITY_EARTH) < 1);
-
+ // avoid generating hundreds of error
+ if (!handleMismatchReported) {
+ EXPECT_EQ(e.sensorHandle, handle)
+ << (handleMismatchReported = true,
+ "Event of the same type must come from the sensor registered");
+ }
++ nRealEvent;
} else {
- ALOGI("Event type %d, handle %d", (int) e.sensorType, (int) e.sensorHandle);
- // Only meta types are allowed besides the subscribed sensor
- ASSERT_TRUE(isMetaSensorType(e.sensorType));
+ // avoid generating hundreds of error
+ if (!metaSensorTypeErrorReported) {
+ EXPECT_TRUE(isMetaSensorType(e.sensorType))
+ << (metaSensorTypeErrorReported = true,
+ "Only meta types are allowed besides the type registered");
+ }
}
}
- ASSERT_GE(nRealEvent, minNEvent / 2); // make sure returned events are not all meta
+ std::string s;
+ EXPECT_TRUE(checker.check(events, &s)) << s;
+
+ EXPECT_GE(nRealEvent, minNEvent / 2); // make sure returned events are not all meta
}
-// Test if sensor hal can do gyroscope streaming properly
-TEST_F(SensorsHidlTest, NormalGyroscopeStreamingOperation) {
- std::vector<Event> events;
-
- constexpr int64_t samplingPeriodInNs = 10ull*1000*1000; // 10ms
- constexpr int64_t batchingPeriodInNs = 0; // no batching
- constexpr useconds_t minTimeUs = 5*1000*1000; // 5 s
- constexpr size_t minNEvent = 200;
- constexpr SensorType type = SensorType::GYROSCOPE;
-
- SensorInfo sensor = defaultSensorByType(type);
-
- if (!isValidType(sensor.type)) {
- // no default sensor of this type
- return;
- }
-
- int32_t handle = sensor.sensorHandle;
-
- ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
- ASSERT_EQ(activate(handle, 1), Result::OK);
- events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/);
- ASSERT_EQ(activate(handle, 0), Result::OK);
-
- ALOGI("Collected %zu samples", events.size());
-
- ASSERT_GT(events.size(), 0u);
-
- size_t nRealEvent = 0;
- for (auto & e : events) {
- if (e.sensorType == type) {
-
- ASSERT_EQ(e.sensorHandle, handle);
-
- Vec3 gyro = e.u.vec3;
-
- double gyroNorm = std::sqrt(gyro.x * gyro.x + gyro.y * gyro.y + gyro.z * gyro.z);
- ALOGV("Gyro Norm = %f", gyroNorm);
-
- // assert not drifting
- ASSERT_TRUE(gyroNorm < 0.1); // < ~5 degree/s
-
- ++ nRealEvent;
- } else {
- ALOGI("Event type %d, handle %d", (int) e.sensorType, (int) e.sensorHandle);
- // Only meta types are allowed besides the subscribed sensor
- ASSERT_TRUE(isMetaSensorType(e.sensorType));
- }
- }
-
- ASSERT_GE(nRealEvent, minNEvent / 2); // make sure returned events are not all meta
+// Test if sensor hal can do UI speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
+ testStreamingOperation(SensorType::ACCELEROMETER,
+ std::chrono::milliseconds(200),
+ std::chrono::seconds(5),
+ sAccelNormChecker);
}
-// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
-TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
+// Test if sensor hal can do normal speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
+ testStreamingOperation(SensorType::ACCELEROMETER,
+ std::chrono::milliseconds(20),
+ std::chrono::seconds(5),
+ sAccelNormChecker);
+}
+
+// Test if sensor hal can do game speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationFast) {
+ testStreamingOperation(SensorType::ACCELEROMETER,
+ std::chrono::milliseconds(5),
+ std::chrono::seconds(5),
+ sAccelNormChecker);
+}
+
+// Test if sensor hal can do UI speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
+ testStreamingOperation(SensorType::GYROSCOPE,
+ std::chrono::milliseconds(200),
+ std::chrono::seconds(5),
+ sGyroNormChecker);
+}
+
+// Test if sensor hal can do normal speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
+ testStreamingOperation(SensorType::GYROSCOPE,
+ std::chrono::milliseconds(20),
+ std::chrono::seconds(5),
+ sGyroNormChecker);
+}
+
+// Test if sensor hal can do game speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationFast) {
+ testStreamingOperation(SensorType::GYROSCOPE,
+ std::chrono::milliseconds(5),
+ std::chrono::seconds(5),
+ sGyroNormChecker);
+}
+
+// Test if sensor hal can do UI speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD,
+ std::chrono::milliseconds(200),
+ std::chrono::seconds(5),
+ NullChecker());
+}
+
+// Test if sensor hal can do normal speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD,
+ std::chrono::milliseconds(20),
+ std::chrono::seconds(5),
+ NullChecker());
+}
+
+// Test if sensor hal can do game speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationFast) {
+ testStreamingOperation(SensorType::MAGNETIC_FIELD,
+ std::chrono::milliseconds(5),
+ std::chrono::seconds(5),
+ NullChecker());
+}
+
+void SensorsHidlTest::testSamplingRateHotSwitchOperation(SensorType type) {
std::vector<Event> events1, events2;
constexpr int64_t batchingPeriodInNs = 0; // no batching
constexpr size_t minNEvent = 50;
- constexpr SensorType type = SensorType::ACCELEROMETER;
SensorInfo sensor = defaultSensorByType(type);
@@ -845,21 +1113,34 @@
maxDelayAverageInterval = timestampInterval / (nEvent - 1);
// change of rate is significant.
- ASSERT_GT((maxDelayAverageInterval - minDelayAverageInterval), minDelayAverageInterval / 10);
+ EXPECT_GT((maxDelayAverageInterval - minDelayAverageInterval), minDelayAverageInterval / 10);
// fastest rate sampling time is close to spec
ALOGI("minDelayAverageInterval = %" PRId64, minDelayAverageInterval);
- ASSERT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
+ EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
minSamplingPeriodInNs / 10);
}
-// Test if sensor hal can do normal accelerometer batching properly
-TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
+// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER);
+}
+
+// Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE);
+}
+
+// Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
+ testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD);
+}
+
+void SensorsHidlTest::testBatchingOperation(SensorType type) {
std::vector<Event> events;
- constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000;
- constexpr SensorType type = SensorType::ACCELEROMETER;
constexpr int64_t maxBatchingTestTimeNs = 30ull * 1000 * 1000 * 1000;
+ constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000;
SensorInfo sensor = defaultSensorByType(type);
@@ -922,24 +1203,46 @@
ASSERT_GT(nEvent, (size_t)(batchingPeriodInNs / minSamplingPeriodInNs * 9 / 10));
}
-// Test sensor event direct report with ashmem for gyro sensor
-TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReport) {
+// Test if sensor hal can do accelerometer batching properly
+TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
+ testBatchingOperation(SensorType::ACCELEROMETER);
+}
- constexpr SensorType type = SensorType::GYROSCOPE;
- constexpr size_t kEventSize = 104;
+// Test if sensor hal can do gyroscope batching properly
+TEST_F(SensorsHidlTest, GyroscopeBatchingOperation) {
+ testBatchingOperation(SensorType::GYROSCOPE);
+}
+
+// Test if sensor hal can do magnetometer batching properly
+TEST_F(SensorsHidlTest, MagnetometerBatchingOperation) {
+ testBatchingOperation(SensorType::MAGNETIC_FIELD);
+}
+
+void SensorsHidlTest::testDirectReportOperation(
+ SensorType type, SharedMemType memType, RateLevel rate, const SensorEventsChecker &checker) {
+ constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
constexpr size_t kNEvent = 500;
constexpr size_t kMemSize = kEventSize * kNEvent;
+ constexpr float kNormalNominal = 50;
+ constexpr float kFastNominal = 200;
+ constexpr float kVeryFastNominal = 800;
+
+ constexpr float kNominalTestTimeSec = 1.f;
+ constexpr float kMaxTestTimeSec = kNominalTestTimeSec + 0.5f; // 0.5 second for initialization
+
SensorInfo sensor = defaultSensorByType(type);
- if (!(sensor.flags | SensorFlagBits::MASK_DIRECT_REPORT)
- || !(sensor.flags | SensorFlagBits::DIRECT_CHANNEL_ASHMEM)) {
- // does not declare support
+ if (!isDirectReportRateSupported(sensor, rate)) {
+ return;
+ }
+
+ if (!isDirectChannelTypeSupported(sensor, memType)) {
return;
}
std::unique_ptr<SensorsTestSharedMemory>
- mem(SensorsTestSharedMemory::create(SharedMemType::ASHMEM, kMemSize));
+ mem(SensorsTestSharedMemory::create(memType, kMemSize));
ASSERT_NE(mem, nullptr);
char* buffer = mem->getBuffer();
@@ -961,39 +1264,119 @@
}
int32_t eventToken;
- configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::NORMAL,
+ configDirectReport(sensor.sensorHandle, channelHandle, rate,
[&eventToken] (auto result, auto token) {
ASSERT_EQ(result, Result::OK);
eventToken = token;
});
- usleep(1500000); // sleep 1 sec for data, plus 0.5 sec for initialization
+ usleep(static_cast<useconds_t>(kMaxTestTimeSec * 1e6f));
auto events = mem->parseEvents();
- // allowed to be 55% of nominal freq (50Hz)
- ASSERT_GT(events.size(), 50u / 2u);
- ASSERT_LT(events.size(), static_cast<size_t>(110*1.5));
+ // find norminal rate
+ float nominalFreq = 0.f;
+ switch (rate) {
+ case RateLevel::NORMAL:
+ nominalFreq = kNormalNominal;
+ break;
+ case RateLevel::FAST:
+ nominalFreq = kFastNominal;
+ break;
+ case RateLevel::VERY_FAST:
+ nominalFreq = kVeryFastNominal;
+ break;
+ case RateLevel::STOP:
+ FAIL();
+ }
+
+ // allowed to be between 55% and 220% of nominal freq
+ ASSERT_GT(events.size(), static_cast<size_t>(nominalFreq * 0.55f * kNominalTestTimeSec));
+ ASSERT_LT(events.size(), static_cast<size_t>(nominalFreq * 2.2f * kMaxTestTimeSec));
int64_t lastTimestamp = 0;
+ bool typeErrorReported = false;
+ bool tokenErrorReported = false;
+ bool timestampErrorReported = false;
for (auto &e : events) {
- ASSERT_EQ(e.sensorType, type);
- ASSERT_EQ(e.sensorHandle, eventToken);
- ASSERT_GT(e.timestamp, lastTimestamp);
-
- Vec3 gyro = e.u.vec3;
- double gyroNorm = std::sqrt(gyro.x * gyro.x + gyro.y * gyro.y + gyro.z * gyro.z);
- // assert not drifting
- ASSERT_TRUE(gyroNorm < 0.1); // < ~5 degree/sa
-
+ if (!typeErrorReported) {
+ EXPECT_EQ(type, e.sensorType)
+ << (typeErrorReported = true, "Type in event does not match type of sensor registered.");
+ }
+ if (!tokenErrorReported) {
+ EXPECT_EQ(eventToken, e.sensorHandle)
+ << (tokenErrorReported = true,
+ "Event token does not match that retured from configDirectReport");
+ }
+ if (!timestampErrorReported) {
+ EXPECT_GT(e.timestamp, lastTimestamp)
+ << (timestampErrorReported = true, "Timestamp not monotonically increasing");
+ }
lastTimestamp = e.timestamp;
}
+ std::string s;
+ EXPECT_TRUE(checker.check(events, &s)) << s;
+
// stop sensor and unregister channel
configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP,
[&eventToken] (auto result, auto) {
- ASSERT_EQ(result, Result::OK);
+ EXPECT_EQ(result, Result::OK);
});
- ASSERT_EQ(unregisterDirectChannel(channelHandle), Result::OK);
+ EXPECT_EQ(unregisterDirectChannel(channelHandle), Result::OK);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at normal rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at fast rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
+ sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at very fast rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
+ sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at normal rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at fast rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at very fast rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
+ sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for mag sensor at normal rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
+ NullChecker());
+}
+
+// Test sensor event direct report with ashmem for mag sensor at fast rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
+ testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
+ NullChecker());
+}
+
+// Test sensor event direct report with ashmem for mag sensor at very fast rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
+ testDirectReportOperation(
+ SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::VERY_FAST, NullChecker());
}
int main(int argc, char **argv) {
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp b/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
index afda739..b0aef4b 100644
--- a/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
+++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
@@ -138,7 +138,7 @@
} while (mClients.valueFor(*modelId) != 0 && *modelId != 0);
}
LOG_ALWAYS_FATAL_IF(*modelId == 0,
- "wrap around in sound model IDs, num loaded models %d", mClients.size());
+ "wrap around in sound model IDs, num loaded models %zu", mClients.size());
client = new SoundModelClient(*modelId, callback, cookie);
diff --git a/tests/msgq/1.0/default/Android.bp b/tests/msgq/1.0/default/Android.bp
index 692edda..16018ac 100644
--- a/tests/msgq/1.0/default/Android.bp
+++ b/tests/msgq/1.0/default/Android.bp
@@ -1,3 +1,18 @@
+//
+// Copyright (C) 2017 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.
+
cc_library_shared {
name: "android.hardware.tests.msgq@1.0-impl",
defaults: ["hidl_defaults"],
@@ -5,6 +20,7 @@
proprietary: true,
srcs: [
"TestMsgQ.cpp",
+ "BenchmarkMsgQ.cpp"
],
shared_libs: [
"libbase",
@@ -18,3 +34,35 @@
"android.hidl.base@1.0",
],
}
+
+cc_test {
+ name: "android.hardware.tests.msgq@1.0-service-benchmark",
+ srcs: ["mq_benchmark_service.cpp"],
+ gtest: false,
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "android.hardware.tests.msgq@1.0"
+ ],
+}
+
+cc_test {
+ name: "android.hardware.tests.msgq@1.0-service-test",
+ srcs: ["mq_test_service.cpp"],
+ gtest: false,
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "android.hardware.tests.msgq@1.0"
+ ],
+}
diff --git a/tests/msgq/1.0/default/BenchmarkMsgQ.cpp b/tests/msgq/1.0/default/BenchmarkMsgQ.cpp
new file mode 100644
index 0000000..43e6fcc
--- /dev/null
+++ b/tests/msgq/1.0/default/BenchmarkMsgQ.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2017 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 "BenchmarkMsgQ.h"
+#include <iostream>
+#include <thread>
+#include <fmq/MessageQueue.h>
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace msgq {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::tests::msgq::V1_0::IBenchmarkMsgQ follow.
+Return<void> BenchmarkMsgQ::configureClientInboxSyncReadWrite(
+ configureClientInboxSyncReadWrite_cb _hidl_cb) {
+ static constexpr size_t kNumElementsInQueue = 16 * 1024;
+ mFmqOutbox = new (std::nothrow) android::hardware::MessageQueue<uint8_t,
+ kSynchronizedReadWrite>(kNumElementsInQueue);
+ if (mFmqOutbox == nullptr) {
+ _hidl_cb(false /* ret */, android::hardware::MQDescriptorSync<uint8_t>(
+ std::vector<android::hardware::GrantorDescriptor>(),
+ nullptr /* nhandle */, 0 /* size */));
+ } else {
+ _hidl_cb(true /* ret */, *mFmqOutbox->getDesc());
+ }
+
+ return Void();
+}
+
+Return<void> BenchmarkMsgQ::configureClientOutboxSyncReadWrite(
+ configureClientOutboxSyncReadWrite_cb _hidl_cb) {
+ static constexpr size_t kNumElementsInQueue = 16 * 1024;
+ mFmqInbox = new (std::nothrow) android::hardware::MessageQueue<uint8_t,
+ kSynchronizedReadWrite>(kNumElementsInQueue);
+ if ((mFmqInbox == nullptr) || (mFmqInbox->isValid() == false)) {
+ _hidl_cb(false /* ret */, android::hardware::MQDescriptorSync<uint8_t>(
+ std::vector<android::hardware::GrantorDescriptor>(),
+ nullptr /* nhandle */, 0 /* size */));
+ } else {
+ _hidl_cb(true /* ret */, *mFmqInbox->getDesc());
+ }
+
+ return Void();
+}
+
+Return<bool> BenchmarkMsgQ::requestWrite(int32_t count) {
+ uint8_t* data = new (std::nothrow) uint8_t[count];
+ for (int i = 0; i < count; i++) {
+ data[i] = i;
+ }
+ bool result = mFmqOutbox->write(data, count);
+ delete[] data;
+ return result;
+}
+
+Return<bool> BenchmarkMsgQ::requestRead(int32_t count) {
+ uint8_t* data = new (std::nothrow) uint8_t[count];
+ bool result = mFmqInbox->read(data, count);
+ delete[] data;
+ return result;
+}
+
+Return<void> BenchmarkMsgQ::benchmarkPingPong(uint32_t numIter) {
+ std::thread(QueuePairReadWrite<kSynchronizedReadWrite>, mFmqInbox,
+ mFmqOutbox, numIter)
+ .detach();
+ return Void();
+}
+
+Return<void> BenchmarkMsgQ::benchmarkServiceWriteClientRead(uint32_t numIter) {
+ if (mTimeData) delete[] mTimeData;
+ mTimeData = new (std::nothrow) int64_t[numIter];
+ std::thread(QueueWriter<kSynchronizedReadWrite>, mFmqOutbox,
+ mTimeData, numIter).detach();
+ return Void();
+}
+
+Return<void> BenchmarkMsgQ::sendTimeData(const hidl_vec<int64_t>& clientRcvTimeArray) {
+ int64_t accumulatedTime = 0;
+
+ for (uint32_t i = 0; i < clientRcvTimeArray.size(); i++) {
+ std::chrono::time_point<std::chrono::high_resolution_clock>
+ clientRcvTime((std::chrono::high_resolution_clock::duration(
+ clientRcvTimeArray[i])));
+ std::chrono::time_point<std::chrono::high_resolution_clock>serverSendTime(
+ (std::chrono::high_resolution_clock::duration(mTimeData[i])));
+ accumulatedTime += static_cast<int64_t>(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(clientRcvTime -
+ serverSendTime).count());
+ }
+
+ accumulatedTime /= clientRcvTimeArray.size();
+ std::cout << "Average service to client write to read delay::"
+ << accumulatedTime << "ns" << std::endl;
+ return Void();
+}
+
+template <MQFlavor flavor>
+void BenchmarkMsgQ::QueueWriter(android::hardware::MessageQueue<uint8_t, flavor>* mFmqOutbox,
+ int64_t* mTimeData,
+ uint32_t numIter) {
+ uint8_t data[kPacketSize64];
+ uint32_t numWrites = 0;
+
+ while (numWrites < numIter) {
+ do {
+ mTimeData[numWrites] =
+ std::chrono::high_resolution_clock::now().time_since_epoch().count();
+ } while (mFmqOutbox->write(data, kPacketSize64) == false);
+ numWrites++;
+ }
+}
+
+template <MQFlavor flavor>
+void BenchmarkMsgQ::QueuePairReadWrite(
+ android::hardware::MessageQueue<uint8_t, flavor>* mFmqInbox,
+ android::hardware::MessageQueue<uint8_t, flavor>* mFmqOutbox,
+ uint32_t numIter) {
+ uint8_t data[kPacketSize64];
+ uint32_t numRoundTrips = 0;
+
+ while (numRoundTrips < numIter) {
+ while (mFmqInbox->read(data, kPacketSize64) == false)
+ ;
+ while (mFmqOutbox->write(data, kPacketSize64) == false)
+ ;
+ numRoundTrips++;
+ }
+}
+
+IBenchmarkMsgQ* HIDL_FETCH_IBenchmarkMsgQ(const char* /* name */) {
+ return new BenchmarkMsgQ();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace msgq
+} // namespace tests
+} // namespace hardware
+} // namespace android
diff --git a/tests/msgq/1.0/default/BenchmarkMsgQ.h b/tests/msgq/1.0/default/BenchmarkMsgQ.h
new file mode 100644
index 0000000..2cbe93c
--- /dev/null
+++ b/tests/msgq/1.0/default/BenchmarkMsgQ.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ANDROID_HARDWARE_TESTS_MSGQ_V1_0_BENCHMARKMSGQ_H
+#define ANDROID_HARDWARE_TESTS_MSGQ_V1_0_BENCHMARKMSGQ_H
+
+#include <android/hardware/tests/msgq/1.0/IBenchmarkMsgQ.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <fmq/MessageQueue.h>
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace msgq {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tests::msgq::V1_0::IBenchmarkMsgQ;
+using ::android::hidl::base::V1_0::DebugInfo;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::MQFlavor;
+
+struct BenchmarkMsgQ : public IBenchmarkMsgQ {
+ /*
+ * The various packet sizes used are as follows.
+ */
+ enum PacketSizes {
+ kPacketSize64 = 64,
+ kPacketSize128 = 128,
+ kPacketSize256 = 256,
+ kPacketSize512 = 512,
+ kPacketSize1024 = 1024
+ };
+ // Methods from ::android::hardware::tests::msgq::V1_0::IBenchmarkMsgQ follow.
+ Return<void> configureClientInboxSyncReadWrite(configureClientInboxSyncReadWrite_cb _hidl_cb) override;
+ Return<void> configureClientOutboxSyncReadWrite(configureClientOutboxSyncReadWrite_cb _hidl_cb) override;
+ Return<bool> requestWrite(int32_t count) override;
+ Return<bool> requestRead(int32_t count) override;
+ Return<void> benchmarkPingPong(uint32_t numIter) override;
+ Return<void> benchmarkServiceWriteClientRead(uint32_t numIter) override;
+ Return<void> sendTimeData(const hidl_vec<int64_t>& timeData) override;
+
+ /*
+ * This method writes numIter packets into the mFmqOutbox queue
+ * and notes the time before each write in the mTimeData array. It will
+ * be used to calculate the average server to client write to read delay.
+ */
+ template <MQFlavor flavor>
+ static void QueueWriter(android::hardware::MessageQueue<uint8_t, flavor>*
+ mFmqOutbox, int64_t* mTimeData, uint32_t numIter);
+ /*
+ * The method reads a packet from the inbox queue and writes the same
+ * into the outbox queue. The client will calculate the average time taken
+ * for each iteration which consists of two write and two read operations.
+ */
+ template <MQFlavor flavor>
+ static void QueuePairReadWrite(
+ android::hardware::MessageQueue<uint8_t, flavor>* mFmqInbox,
+ android::hardware::MessageQueue<uint8_t, flavor>* mFmqOutbox,
+ uint32_t numIter);
+
+private:
+ android::hardware::MessageQueue<uint8_t, kSynchronizedReadWrite>* mFmqInbox;
+ android::hardware::MessageQueue<uint8_t, kSynchronizedReadWrite>* mFmqOutbox;
+ int64_t* mTimeData;
+};
+
+extern "C" IBenchmarkMsgQ* HIDL_FETCH_IBenchmarkMsgQ(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace msgq
+} // namespace tests
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TESTS_MSGQ_V1_0_BENCHMARKMSGQ_H
diff --git a/tests/msgq/1.0/default/TestMsgQ.cpp b/tests/msgq/1.0/default/TestMsgQ.cpp
index 7cc4f5b..6fd4fc6 100644
--- a/tests/msgq/1.0/default/TestMsgQ.cpp
+++ b/tests/msgq/1.0/default/TestMsgQ.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2017 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 "TestMsgQ.h"
namespace android {
diff --git a/tests/msgq/1.0/default/TestMsgQ.h b/tests/msgq/1.0/default/TestMsgQ.h
index 760d931..86e4ac4 100644
--- a/tests/msgq/1.0/default/TestMsgQ.h
+++ b/tests/msgq/1.0/default/TestMsgQ.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
#ifndef ANDROID_HARDWARE_TESTS_MSGQ_V1_0_TESTMSGQ_H
#define ANDROID_HARDWARE_TESTS_MSGQ_V1_0_TESTMSGQ_H
diff --git a/tests/msgq/1.0/default/mq_benchmark_service.cpp b/tests/msgq/1.0/default/mq_benchmark_service.cpp
new file mode 100644
index 0000000..b9be81b
--- /dev/null
+++ b/tests/msgq/1.0/default/mq_benchmark_service.cpp
@@ -0,0 +1,28 @@
+/*
+* Copyright (C) 2017 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.
+*/
+
+#define LOG_TAG "FMQ_Benchmarks"
+
+#include <android/hardware/tests/msgq/1.0/IBenchmarkMsgQ.h>
+
+#include <hidl/LegacySupport.h>
+
+using android::hardware::tests::msgq::V1_0::IBenchmarkMsgQ;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<IBenchmarkMsgQ>();
+}
diff --git a/tests/msgq/1.0/default/mq_test_service.cpp b/tests/msgq/1.0/default/mq_test_service.cpp
new file mode 100644
index 0000000..b5cb662
--- /dev/null
+++ b/tests/msgq/1.0/default/mq_test_service.cpp
@@ -0,0 +1,28 @@
+/*
+* Copyright (C) 2017 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.
+*/
+
+#define LOG_TAG "FMQ_UnitTests"
+
+#include <android/hardware/tests/msgq/1.0/ITestMsgQ.h>
+
+#include <hidl/LegacySupport.h>
+
+using android::hardware::tests::msgq::V1_0::ITestMsgQ;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<ITestMsgQ>();
+}
diff --git a/tv/input/1.0/default/TvInput.cpp b/tv/input/1.0/default/TvInput.cpp
index 6fcb2e5..0bc6401 100644
--- a/tv/input/1.0/default/TvInput.cpp
+++ b/tv/input/1.0/default/TvInput.cpp
@@ -158,6 +158,7 @@
tvInputEvent.deviceInfo.type = static_cast<TvInputType>(
event->device_info.type);
tvInputEvent.deviceInfo.portId = event->device_info.hdmi.port_id;
+ tvInputEvent.deviceInfo.cableConnectionStatus = CableConnectionStatus::UNKNOWN;
// TODO: Ensure the legacy audio type code is the same once audio HAL default
// implementation is ready.
tvInputEvent.deviceInfo.audioType = static_cast<AudioDevice>(
diff --git a/tv/input/1.0/types.hal b/tv/input/1.0/types.hal
index 6852c70..55eb6ad 100644
--- a/tv/input/1.0/types.hal
+++ b/tv/input/1.0/types.hal
@@ -40,14 +40,27 @@
DISPLAY_PORT = 10,
};
+/*
+ * Status of cable connection.
+ * This status is for devices having availability to detect the cable in a mechanical way,
+ * regardless of whether the connected external device is electrically on or not.
+ * If the device does not have such capability, you must use UNKNOWN.
+ */
+enum CableConnectionStatus : int32_t {
+ UNKNOWN = 0,
+ CONNECTED = 1,
+ DISCONNECTED = 2,
+};
+
struct TvInputDeviceInfo {
int32_t deviceId;
TvInputType type;
- uint32_t portId; // HDMI port ID number. e.g. 2 for HDMI 2
- AudioDevice audioType; // Audio device type. e.g AudioDevice::IN_HDMI
- uint8_t[32] audioAddress; // Audio device address. "" if N/A. If the text
- // length is less than 32, the remaining part
- // must be filled with 0s.
+ uint32_t portId; // HDMI port ID number. e.g. 2 for HDMI 2
+ CableConnectionStatus cableConnectionStatus; // Cable connection status.
+ AudioDevice audioType; // Audio device type. e.g AudioDevice::IN_HDMI
+ uint8_t[32] audioAddress; // Audio device address. "" if N/A. If the text
+ // length is less than 32, the remaining part
+ // must be filled with 0s.
};
enum TvInputEventType : int32_t {
diff --git a/wifi/1.0/default/Android.mk b/wifi/1.0/default/Android.mk
index e84c1c5..cc5e1c6 100644
--- a/wifi/1.0/default/Android.mk
+++ b/wifi/1.0/default/Android.mk
@@ -46,7 +46,8 @@
libnl \
libutils \
libwifi-hal \
- libwifi-system
+ libwifi-system \
+ libcld80211
LOCAL_WHOLE_STATIC_LIBRARIES := $(LIB_WIFI_HAL)
LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
include $(BUILD_EXECUTABLE)
diff --git a/wifi/1.0/default/hidl_struct_util.cpp b/wifi/1.0/default/hidl_struct_util.cpp
index a89f8c0..fb93c5a 100644
--- a/wifi/1.0/default/hidl_struct_util.cpp
+++ b/wifi/1.0/default/hidl_struct_util.cpp
@@ -706,11 +706,17 @@
hidl_stats->iface.wmeVoPktStats.retries =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
// radio legacy_stats conversion.
- hidl_stats->radio.onTimeInMs = legacy_stats.radio.on_time;
- hidl_stats->radio.txTimeInMs = legacy_stats.radio.tx_time;
- hidl_stats->radio.rxTimeInMs = legacy_stats.radio.rx_time;
- hidl_stats->radio.onTimeInMsForScan = legacy_stats.radio.on_time_scan;
- hidl_stats->radio.txTimeInMsPerLevel = legacy_stats.radio_tx_time_per_levels;
+ std::vector<StaLinkLayerRadioStats> hidl_radios_stats;
+ for (const auto& legacy_radio_stats : legacy_stats.radios) {
+ StaLinkLayerRadioStats hidl_radio_stats;
+ hidl_radio_stats.onTimeInMs = legacy_radio_stats.stats.on_time;
+ hidl_radio_stats.txTimeInMs = legacy_radio_stats.stats.tx_time;
+ hidl_radio_stats.rxTimeInMs = legacy_radio_stats.stats.rx_time;
+ hidl_radio_stats.onTimeInMsForScan = legacy_radio_stats.stats.on_time_scan;
+ hidl_radio_stats.txTimeInMsPerLevel = legacy_radio_stats.tx_time_per_levels;
+ hidl_radios_stats.push_back(hidl_radio_stats);
+ }
+ hidl_stats->radios = hidl_radios_stats;
// Timestamp in the HAL wrapper here since it's not provided in the legacy
// HAL API.
hidl_stats->timeStampInMs = uptimeMillis();
diff --git a/wifi/1.0/default/wifi_legacy_hal.cpp b/wifi/1.0/default/wifi_legacy_hal.cpp
index f902e64..5fc0228 100644
--- a/wifi/1.0/default/wifi_legacy_hal.cpp
+++ b/wifi/1.0/default/wifi_legacy_hal.cpp
@@ -601,33 +601,37 @@
LinkLayerStats link_stats{};
LinkLayerStats* link_stats_ptr = &link_stats;
- on_link_layer_stats_result_internal_callback = [&link_stats_ptr](
- wifi_request_id /* id */,
- wifi_iface_stat* iface_stats_ptr,
- int num_radios,
- wifi_radio_stat* radio_stats_ptr) {
- if (iface_stats_ptr != nullptr) {
- link_stats_ptr->iface = *iface_stats_ptr;
- link_stats_ptr->iface.num_peers = 0;
- } else {
- LOG(ERROR) << "Invalid iface stats in link layer stats";
- }
- if (num_radios == 1 && radio_stats_ptr != nullptr) {
- link_stats_ptr->radio = *radio_stats_ptr;
- // Copy over the tx level array to the separate vector.
- if (radio_stats_ptr->num_tx_levels > 0 &&
- radio_stats_ptr->tx_time_per_levels != nullptr) {
- link_stats_ptr->radio_tx_time_per_levels.assign(
- radio_stats_ptr->tx_time_per_levels,
- radio_stats_ptr->tx_time_per_levels +
- radio_stats_ptr->num_tx_levels);
- }
- link_stats_ptr->radio.num_tx_levels = 0;
- link_stats_ptr->radio.tx_time_per_levels = nullptr;
- } else {
- LOG(ERROR) << "Invalid radio stats in link layer stats";
- }
- };
+ on_link_layer_stats_result_internal_callback =
+ [&link_stats_ptr](wifi_request_id /* id */,
+ wifi_iface_stat* iface_stats_ptr,
+ int num_radios,
+ wifi_radio_stat* radio_stats_ptr) {
+ if (iface_stats_ptr != nullptr) {
+ link_stats_ptr->iface = *iface_stats_ptr;
+ link_stats_ptr->iface.num_peers = 0;
+ } else {
+ LOG(ERROR) << "Invalid iface stats in link layer stats";
+ }
+ if (num_radios <= 0 || radio_stats_ptr == nullptr) {
+ LOG(ERROR) << "Invalid radio stats in link layer stats";
+ return;
+ }
+ for (int i = 0; i < num_radios; i++) {
+ LinkLayerRadioStats radio;
+ radio.stats = radio_stats_ptr[i];
+ // Copy over the tx level array to the separate vector.
+ if (radio_stats_ptr[i].num_tx_levels > 0 &&
+ radio_stats_ptr[i].tx_time_per_levels != nullptr) {
+ radio.tx_time_per_levels.assign(
+ radio_stats_ptr[i].tx_time_per_levels,
+ radio_stats_ptr[i].tx_time_per_levels +
+ radio_stats_ptr[i].num_tx_levels);
+ }
+ radio.stats.num_tx_levels = 0;
+ radio.stats.tx_time_per_levels = nullptr;
+ link_stats_ptr->radios.push_back(radio);
+ }
+ };
wifi_error status = global_func_table_.wifi_get_link_stats(
0, wlan_interface_handle_, {onSyncLinkLayerStatsResult});
diff --git a/wifi/1.0/default/wifi_legacy_hal.h b/wifi/1.0/default/wifi_legacy_hal.h
index c8fd5bd..576dfe6 100644
--- a/wifi/1.0/default/wifi_legacy_hal.h
+++ b/wifi/1.0/default/wifi_legacy_hal.h
@@ -49,10 +49,14 @@
// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in
// |wifi_radio_stat| structure in the legacy HAL API. Separate that out
// into a separate return element to avoid passing pointers around.
+struct LinkLayerRadioStats {
+ wifi_radio_stat stats;
+ std::vector<uint32_t> tx_time_per_levels;
+};
+
struct LinkLayerStats {
wifi_iface_stat iface;
- wifi_radio_stat radio;
- std::vector<uint32_t> radio_tx_time_per_levels;
+ std::vector<LinkLayerRadioStats> radios;
};
#pragma GCC diagnostic pop
@@ -285,7 +289,7 @@
// Opaque handle to be used for all wlan0 interface specific operations.
wifi_interface_handle wlan_interface_handle_;
// Flag to indicate if we have initiated the cleanup of legacy HAL.
- bool awaiting_event_loop_termination_;
+ std::atomic<bool> awaiting_event_loop_termination_;
// Flag to indicate if the legacy HAL has been started.
bool is_started_;
wifi_system::InterfaceTool iface_tool_;
diff --git a/wifi/1.0/types.hal b/wifi/1.0/types.hal
index d90d5be..d3845c9 100644
--- a/wifi/1.0/types.hal
+++ b/wifi/1.0/types.hal
@@ -143,7 +143,7 @@
/**
* TimeStamp in milliseconds (ms).
*/
-typedef uint32_t TimeStampInMs;
+typedef uint64_t TimeStampInMs;
/**
* TimeStamp in microseconds (us).
@@ -478,7 +478,7 @@
*/
struct StaLinkLayerStats {
StaLinkLayerIfaceStats iface;
- StaLinkLayerRadioStats radio;
+ vec<StaLinkLayerRadioStats> radios;
/**
* TimeStamp for each stats sample.
* This is the absolute milliseconds from boot when these stats were
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index eab338b..9403e98 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -14,17 +14,32 @@
// limitations under the License.
//
+cc_library_static {
+ name: "VtsHalWifiV1_0TargetTestUtil",
+ srcs: [
+ "VtsHalWifiV1_0TargetTest.cpp",
+ "wifi_hidl_call_util_selftest.cpp",
+ "wifi_hidl_test.cpp",
+ "wifi_hidl_test_utils.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.wifi@1.0",
+ ],
+ static_libs: ["VtsHalHidlTargetTestBase"],
+}
+
cc_test {
name: "VtsHalWifiV1_0TargetTest",
defaults: ["hidl_defaults"],
srcs: [
- "VtsHalWifiV1_0TargetTest.cpp",
"wifi_ap_iface_hidl_test.cpp",
"wifi_chip_hidl_test.cpp",
- "wifi_hidl_call_util_selftest.cpp",
- "wifi_hidl_test.cpp",
- "wifi_hidl_test_utils.cpp",
- "wifi_nan_iface_hidl_test.cpp",
"wifi_p2p_iface_hidl_test.cpp",
"wifi_rtt_controller_hidl_test.cpp",
"wifi_sta_iface_hidl_test.cpp"],
@@ -38,7 +53,28 @@
"libutils",
"android.hardware.wifi@1.0",
],
- static_libs: ["VtsHalHidlTargetTestBase"],
+ static_libs: ["VtsHalWifiV1_0TargetTestUtil", "VtsHalHidlTargetTestBase"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
+
+cc_test {
+ name: "VtsHalWifiNanV1_0TargetTest",
+ defaults: ["hidl_defaults"],
+ srcs: ["wifi_nan_iface_hidl_test.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libnativehelper",
+ "libutils",
+ "android.hardware.wifi@1.0",
+ ],
+ static_libs: ["VtsHalWifiV1_0TargetTestUtil", "VtsHalHidlTargetTestBase"],
cflags: [
"-O0",
"-g",
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
index ab1b6a3..c6ac03c 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
@@ -18,8 +18,33 @@
#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicant.h>
+
#include "supplicant_hidl_test_utils.h"
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicant;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicantIface;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
+
+class SupplicantHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ startSupplicantAndWaitForHidlService();
+ supplicant_ = getSupplicant();
+ ASSERT_NE(supplicant_.get(), nullptr);
+ }
+
+ virtual void TearDown() override { stopSupplicant(); }
+
+ protected:
+ // ISupplicant object used for all tests in this fixture.
+ sp<ISupplicant> supplicant_;
+};
+
/*
* Create:
* Ensures that an instance of the ISupplicant proxy object is
@@ -30,3 +55,131 @@
EXPECT_NE(nullptr, getSupplicant().get());
stopSupplicant();
}
+
+/*
+ * ListInterfaces
+ */
+TEST_F(SupplicantHidlTest, ListInterfaces) {
+ std::vector<ISupplicant::IfaceInfo> ifaces;
+ supplicant_->listInterfaces(
+ [&](const SupplicantStatus& status,
+ const hidl_vec<ISupplicant::IfaceInfo>& hidl_ifaces) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ ifaces = hidl_ifaces;
+ });
+
+ EXPECT_NE(ifaces.end(),
+ std::find_if(ifaces.begin(), ifaces.end(), [](const auto& iface) {
+ return iface.type == IfaceType::STA;
+ }));
+ EXPECT_NE(ifaces.end(),
+ std::find_if(ifaces.begin(), ifaces.end(), [](const auto& iface) {
+ return iface.type == IfaceType::P2P;
+ }));
+}
+
+/*
+ * GetInterface
+ */
+TEST_F(SupplicantHidlTest, GetInterface) {
+ std::vector<ISupplicant::IfaceInfo> ifaces;
+ supplicant_->listInterfaces(
+ [&](const SupplicantStatus& status,
+ const hidl_vec<ISupplicant::IfaceInfo>& hidl_ifaces) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ ifaces = hidl_ifaces;
+ });
+
+ ASSERT_NE(0u, ifaces.size());
+ supplicant_->getInterface(
+ ifaces[0],
+ [&](const SupplicantStatus& status, const sp<ISupplicantIface>& iface) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_NE(nullptr, iface.get());
+ });
+}
+
+/*
+ * SetDebugParams
+ */
+TEST_F(SupplicantHidlTest, SetDebugParams) {
+ bool show_timestamp = true;
+ bool show_keys = true;
+ ISupplicant::DebugLevel level = ISupplicant::DebugLevel::EXCESSIVE;
+
+ supplicant_->setDebugParams(level,
+ show_timestamp, // show timestamps
+ show_keys, // show keys
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS,
+ status.code);
+ });
+}
+
+/*
+ * GetDebugLevel
+ */
+TEST_F(SupplicantHidlTest, GetDebugLevel) {
+ bool show_timestamp = true;
+ bool show_keys = true;
+ ISupplicant::DebugLevel level = ISupplicant::DebugLevel::EXCESSIVE;
+
+ supplicant_->setDebugParams(level,
+ show_timestamp, // show timestamps
+ show_keys, // show keys
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS,
+ status.code);
+ });
+ EXPECT_EQ(level, supplicant_->getDebugLevel());
+}
+
+/*
+ * IsDebugShowTimestampEnabled
+ */
+TEST_F(SupplicantHidlTest, IsDebugShowTimestampEnabled) {
+ bool show_timestamp = true;
+ bool show_keys = true;
+ ISupplicant::DebugLevel level = ISupplicant::DebugLevel::EXCESSIVE;
+
+ supplicant_->setDebugParams(level,
+ show_timestamp, // show timestamps
+ show_keys, // show keys
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS,
+ status.code);
+ });
+ EXPECT_EQ(show_timestamp, supplicant_->isDebugShowTimestampEnabled());
+}
+
+/*
+ * IsDebugShowKeysEnabled
+ */
+TEST_F(SupplicantHidlTest, IsDebugShowKeysEnabled) {
+ bool show_timestamp = true;
+ bool show_keys = true;
+ ISupplicant::DebugLevel level = ISupplicant::DebugLevel::EXCESSIVE;
+
+ supplicant_->setDebugParams(level,
+ show_timestamp, // show timestamps
+ show_keys, // show keys
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS,
+ status.code);
+ });
+ EXPECT_EQ(show_keys, supplicant_->isDebugShowKeysEnabled());
+}
+
+/*
+ * SetConcurrenyPriority
+ */
+TEST_F(SupplicantHidlTest, SetConcurrencyPriority) {
+ supplicant_->setConcurrencyPriority(
+ IfaceType::STA, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ supplicant_->setConcurrencyPriority(
+ IfaceType::P2P, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index fdee0c6..1fcfc8c 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -17,9 +17,9 @@
#include <android-base/logging.h>
#include <VtsHalHidlTargetTestBase.h>
-#include <hidl/HidlTransportSupport.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <android/hidl/manager/1.0/IServiceNotification.h>
+#include <hidl/HidlTransportSupport.h>
#include <wifi_hal/driver_tool.h>
#include <wifi_system/interface_tool.h>
@@ -174,7 +174,7 @@
}
sp<ISupplicant> getSupplicant() {
- return getService<ISupplicant>(kSupplicantServiceName);
+ return ::testing::VtsHalHidlTargetTestBase::getService<ISupplicant>();
}
sp<ISupplicantStaIface> getSupplicantStaIface() {
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp
index 332b57b..c6cf01f 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_p2p_iface_hidl_test.cpp
@@ -18,8 +18,144 @@
#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIface.h>
+
#include "supplicant_hidl_test_utils.h"
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIfaceCallback;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantNetworkId;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+
+namespace {
+constexpr uint8_t kTestSsidPostfix[] = {'t', 'e', 's', 't'};
+constexpr uint8_t kTestMacAddr[] = {0x56, 0x67, 0x67, 0xf4, 0x56, 0x92};
+constexpr uint8_t kTestPeerMacAddr[] = {0x56, 0x67, 0x55, 0xf4, 0x56, 0x92};
+constexpr char kTestConnectPin[] = "34556665";
+constexpr char kTestGroupIfName[] = "TestGroup";
+constexpr uint32_t kTestConnectGoIntent = 6;
+constexpr uint32_t kTestFindTimeout = 5;
+constexpr SupplicantNetworkId kTestNetworkId = 5;
+constexpr uint32_t kTestChannel = 1;
+constexpr uint32_t kTestOperatingClass = 81;
+constexpr uint32_t kTestFreqRange[] = {2412, 2432};
+constexpr uint32_t kTestExtListenPeriod = 400;
+constexpr uint32_t kTestExtListenInterval = 400;
+} // namespace
+
+class SupplicantP2pIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ startSupplicantAndWaitForHidlService();
+ EXPECT_TRUE(turnOnExcessiveLogging());
+ p2p_iface_ = getSupplicantP2pIface();
+ ASSERT_NE(p2p_iface_.get(), nullptr);
+
+ memcpy(mac_addr_.data(), kTestMacAddr, mac_addr_.size());
+ memcpy(peer_mac_addr_.data(), kTestPeerMacAddr, peer_mac_addr_.size());
+ }
+
+ virtual void TearDown() override { stopSupplicant(); }
+
+ protected:
+ // ISupplicantP2pIface object used for all tests in this fixture.
+ sp<ISupplicantP2pIface> p2p_iface_;
+ // MAC address to use for various tests.
+ std::array<uint8_t, 6> mac_addr_;
+ std::array<uint8_t, 6> peer_mac_addr_;
+};
+
+class IfaceCallback : public ISupplicantP2pIfaceCallback {
+ Return<void> onNetworkAdded(uint32_t /* id */) override { return Void(); }
+ Return<void> onNetworkRemoved(uint32_t /* id */) override { return Void(); }
+ Return<void> onDeviceFound(
+ const hidl_array<uint8_t, 6>& /* srcAddress */,
+ const hidl_array<uint8_t, 6>& /* p2pDeviceAddress */,
+ const hidl_array<uint8_t, 8>& /* primaryDeviceType */,
+ const hidl_string& /* deviceName */, uint16_t /* configMethods */,
+ uint8_t /* deviceCapabilities */, uint32_t /* groupCapabilities */,
+ const hidl_array<uint8_t, 8>& /* wfdDeviceInfo */) override {
+ return Void();
+ }
+ Return<void> onDeviceLost(
+ const hidl_array<uint8_t, 6>& /* p2pDeviceAddress */) override {
+ return Void();
+ }
+ Return<void> onFindStopped() override { return Void(); }
+ Return<void> onGoNegotiationRequest(
+ const hidl_array<uint8_t, 6>& /* srcAddress */,
+ ISupplicantP2pIfaceCallback::WpsDevPasswordId /* passwordId */)
+ override {
+ return Void();
+ }
+ Return<void> onGoNegotiationCompleted(
+ ISupplicantP2pIfaceCallback::P2pStatusCode /* status */) override {
+ return Void();
+ }
+ Return<void> onGroupFormationSuccess() override { return Void(); }
+ Return<void> onGroupFormationFailure(
+ const hidl_string& /* failureReason */) override {
+ return Void();
+ }
+ Return<void> onGroupStarted(
+ const hidl_string& /* groupIfname */, bool /* isGo */,
+ const hidl_vec<uint8_t>& /* ssid */, uint32_t /* frequency */,
+ const hidl_array<uint8_t, 32>& /* psk */,
+ const hidl_string& /* passphrase */,
+ const hidl_array<uint8_t, 6>& /* goDeviceAddress */,
+ bool /* isPersistent */) override {
+ return Void();
+ }
+ Return<void> onGroupRemoved(const hidl_string& /* groupIfname */,
+ bool /* isGo */) override {
+ return Void();
+ }
+ Return<void> onInvitationReceived(
+ const hidl_array<uint8_t, 6>& /* srcAddress */,
+ const hidl_array<uint8_t, 6>& /* goDeviceAddress */,
+ const hidl_array<uint8_t, 6>& /* bssid */,
+ uint32_t /* persistentNetworkId */,
+ uint32_t /* operatingFrequency */) override {
+ return Void();
+ }
+ Return<void> onInvitationResult(
+ const hidl_array<uint8_t, 6>& /* bssid */,
+ ISupplicantP2pIfaceCallback::P2pStatusCode /* status */) override {
+ return Void();
+ }
+ Return<void> onProvisionDiscoveryCompleted(
+ const hidl_array<uint8_t, 6>& /* p2pDeviceAddress */,
+ bool /* isRequest */,
+ ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode /* status */,
+ uint16_t /* configMethods */,
+ const hidl_string& /* generatedPin */) override {
+ return Void();
+ }
+ Return<void> onServiceDiscoveryResponse(
+ const hidl_array<uint8_t, 6>& /* srcAddress */,
+ uint16_t /* updateIndicator */,
+ const hidl_vec<uint8_t>& /* tlvs */) override {
+ return Void();
+ }
+ Return<void> onStaAuthorized(
+ const hidl_array<uint8_t, 6>& /* srcAddress */,
+ const hidl_array<uint8_t, 6>& /* p2pDeviceAddress */) override {
+ return Void();
+ }
+ Return<void> onStaDeauthorized(
+ const hidl_array<uint8_t, 6>& /* srcAddress */,
+ const hidl_array<uint8_t, 6>& /* p2pDeviceAddress */) override {
+ return Void();
+ }
+};
+
/*
* Create:
* Ensures that an instance of the ISupplicantP2pIface proxy object is
@@ -30,3 +166,248 @@
EXPECT_NE(nullptr, getSupplicantP2pIface().get());
stopSupplicant();
}
+
+/*
+ * RegisterCallback
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, RegisterCallback) {
+ p2p_iface_->registerCallback(
+ new IfaceCallback(), [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * GetDeviceAddress
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, GetDeviceAddress) {
+ p2p_iface_->getDeviceAddress(
+ [](const SupplicantStatus& status,
+ const hidl_array<uint8_t, 6>& /* mac_addr */) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * SetSsidPostfix
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, SetSsidPostfix) {
+ std::vector<uint8_t> ssid(kTestSsidPostfix,
+ kTestSsidPostfix + sizeof(kTestSsidPostfix));
+ p2p_iface_->setSsidPostfix(ssid, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * Find
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, Find) {
+ p2p_iface_->find(kTestFindTimeout, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * StopFind
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, StopFind) {
+ p2p_iface_->find(kTestFindTimeout, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ p2p_iface_->stopFind([](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ p2p_iface_->stopFind([](const SupplicantStatus& status) {
+ EXPECT_NE(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * Flush
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, Flush) {
+ p2p_iface_->flush([](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * Connect
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, Connect) {
+ p2p_iface_->connect(
+ mac_addr_, ISupplicantP2pIface::WpsProvisionMethod::PBC,
+ kTestConnectPin, false, false, kTestConnectGoIntent,
+ [](const SupplicantStatus& status, const hidl_string& /* pin */) {
+ // This is not going to work with fake values.
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+}
+
+/*
+ * CancelConnect
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, CancelConnect) {
+ p2p_iface_->connect(
+ mac_addr_, ISupplicantP2pIface::WpsProvisionMethod::PBC,
+ kTestConnectPin, false, false, kTestConnectGoIntent,
+ [](const SupplicantStatus& status, const hidl_string& /* pin */) {
+ // This is not going to work with fake values.
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+
+ p2p_iface_->cancelConnect([](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+}
+
+/*
+ * ProvisionDiscovery
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, ProvisionDiscovery) {
+ p2p_iface_->provisionDiscovery(
+ mac_addr_, ISupplicantP2pIface::WpsProvisionMethod::PBC,
+ [](const SupplicantStatus& status) {
+ // This is not going to work with fake values.
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+}
+
+/*
+ * AddGroup
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, AddGroup) {
+ p2p_iface_->addGroup(false, kTestNetworkId,
+ [](const SupplicantStatus& /* status */) {
+ // TODO: Figure out the initialization sequence for
+ // this to work.
+ // EXPECT_EQ(SupplicantStatusCode::SUCCESS,
+ // status.code);
+ });
+}
+
+/*
+ * Reject
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, Reject) {
+ p2p_iface_->reject(mac_addr_, [](const SupplicantStatus& status) {
+ // This is not going to work with fake values.
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+}
+
+/*
+ * Invite
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, Invite) {
+ p2p_iface_->invite(kTestGroupIfName, mac_addr_, peer_mac_addr_,
+ [](const SupplicantStatus& status) {
+ // This is not going to work with fake values.
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN,
+ status.code);
+ });
+}
+
+/*
+ * Reinvoke
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, Reinvoke) {
+ p2p_iface_->reinvoke(
+ kTestNetworkId, mac_addr_, [](const SupplicantStatus& status) {
+ // This is not going to work with fake values.
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN,
+ status.code);
+ });
+}
+
+/*
+ * ConfigureExtListen
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, ConfigureExtListen) {
+ p2p_iface_->configureExtListen(kTestExtListenPeriod, kTestExtListenInterval,
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS,
+ status.code);
+ });
+}
+
+/*
+ * SetListenChannel
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, SetListenChannel) {
+ p2p_iface_->setListenChannel(
+ kTestChannel, kTestOperatingClass, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * SetDisallowedFrequencies
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, SetDisallowedFrequencies) {
+ std::vector<ISupplicantP2pIface::FreqRange> ranges = {
+ {kTestFreqRange[0], kTestFreqRange[1]}};
+ p2p_iface_->setDisallowedFrequencies(
+ ranges, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * GetSsid
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, GetSsid) {
+ std::array<uint8_t, 6> mac_addr;
+ memcpy(mac_addr.data(), kTestMacAddr, mac_addr.size());
+ p2p_iface_->getSsid(mac_addr, [](const SupplicantStatus& status,
+ const hidl_vec<uint8_t>& /* ssid */) {
+ // This is not going to work with fake values.
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+}
+
+/*
+ * GetGroupCapability
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, GetGroupCapability) {
+ std::array<uint8_t, 6> mac_addr;
+ memcpy(mac_addr.data(), kTestMacAddr, mac_addr.size());
+ p2p_iface_->getGroupCapability(
+ mac_addr, [](const SupplicantStatus& status, uint32_t /* caps */) {
+ // This is not going to work with fake values.
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+}
+
+/*
+ * FlushServices
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, FlushServices) {
+ p2p_iface_->flushServices([](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * SetMiracastMode
+ */
+TEST_F(SupplicantP2pIfaceHidlTest, SetMiracastMode) {
+ p2p_iface_->setMiracastMode(ISupplicantP2pIface::MiracastMode::DISABLED,
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS,
+ status.code);
+ });
+ p2p_iface_->setMiracastMode(ISupplicantP2pIface::MiracastMode::SOURCE,
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS,
+ status.code);
+ });
+ p2p_iface_->setMiracastMode(ISupplicantP2pIface::MiracastMode::SINK,
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS,
+ status.code);
+ });
+}
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
index c50539b..c2a58b6 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -18,8 +18,122 @@
#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIface.h>
+
#include "supplicant_hidl_test_utils.h"
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaIfaceCallback;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantNetworkId;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+
+namespace {
+constexpr uint8_t kTestMacAddr[] = {0x56, 0x67, 0x67, 0xf4, 0x56, 0x92};
+constexpr ISupplicantStaIface::AnqpInfoId kTestAnqpInfoIds[] = {
+ ISupplicantStaIface::AnqpInfoId::VENUE_NAME,
+ ISupplicantStaIface::AnqpInfoId::NAI_REALM,
+ ISupplicantStaIface::AnqpInfoId::DOMAIN_NAME};
+constexpr ISupplicantStaIface::Hs20AnqpSubtypes kTestHs20Types[] = {
+ ISupplicantStaIface::Hs20AnqpSubtypes::WAN_METRICS,
+ ISupplicantStaIface::Hs20AnqpSubtypes::OPERATOR_FRIENDLY_NAME};
+constexpr char kTestHs20IconFile[] = "TestFile";
+constexpr int8_t kTestCountryCode[] = {'U', 'S'};
+} // namespace
+
+class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ startSupplicantAndWaitForHidlService();
+ EXPECT_TRUE(turnOnExcessiveLogging());
+ sta_iface_ = getSupplicantStaIface();
+ ASSERT_NE(sta_iface_.get(), nullptr);
+
+ memcpy(mac_addr_.data(), kTestMacAddr, mac_addr_.size());
+ }
+
+ virtual void TearDown() override { stopSupplicant(); }
+
+ protected:
+ // ISupplicantStaIface object used for all tests in this fixture.
+ sp<ISupplicantStaIface> sta_iface_;
+ // MAC address to use for various tests.
+ std::array<uint8_t, 6> mac_addr_;
+};
+
+class IfaceCallback : public ISupplicantStaIfaceCallback {
+ Return<void> onNetworkAdded(uint32_t /* id */) override { return Void(); }
+ Return<void> onNetworkRemoved(uint32_t /* id */) override { return Void(); }
+ Return<void> onStateChanged(
+ ISupplicantStaIfaceCallback::State /* newState */,
+ const hidl_array<uint8_t, 6>& /*bssid */, uint32_t /* id */,
+ const hidl_vec<uint8_t>& /* ssid */) override {
+ return Void();
+ }
+ Return<void> onAnqpQueryDone(
+ const hidl_array<uint8_t, 6>& /* bssid */,
+ const ISupplicantStaIfaceCallback::AnqpData& /* data */,
+ const ISupplicantStaIfaceCallback::Hs20AnqpData& /* hs20Data */)
+ override {
+ return Void();
+ }
+ virtual Return<void> onHs20IconQueryDone(
+ const hidl_array<uint8_t, 6>& /* bssid */,
+ const hidl_string& /* fileName */,
+ const hidl_vec<uint8_t>& /* data */) override {
+ return Void();
+ }
+ virtual Return<void> onHs20SubscriptionRemediation(
+ const hidl_array<uint8_t, 6>& /* bssid */,
+ ISupplicantStaIfaceCallback::OsuMethod /* osuMethod */,
+ const hidl_string& /* url*/) override {
+ return Void();
+ }
+ Return<void> onHs20DeauthImminentNotice(
+ const hidl_array<uint8_t, 6>& /* bssid */, uint32_t /* reasonCode */,
+ uint32_t /* reAuthDelayInSec */,
+ const hidl_string& /* url */) override {
+ return Void();
+ }
+ Return<void> onDisconnected(const hidl_array<uint8_t, 6>& /* bssid */,
+ bool /* locallyGenerated */,
+ uint32_t /* reasonCode */) override {
+ return Void();
+ }
+ Return<void> onAssociationRejected(
+ const hidl_array<uint8_t, 6>& /* bssid */, uint32_t /* statusCode */,
+ bool /*timedOut */) override {
+ return Void();
+ }
+ Return<void> onAuthenticationTimeout(
+ const hidl_array<uint8_t, 6>& /* bssid */) override {
+ return Void();
+ }
+ Return<void> onEapFailure() override { return Void(); }
+ Return<void> onWpsEventSuccess() override { return Void(); }
+ Return<void> onWpsEventFail(
+ const hidl_array<uint8_t, 6>& /* bssid */,
+ ISupplicantStaIfaceCallback::WpsConfigError /* configError */,
+ ISupplicantStaIfaceCallback::WpsErrorIndication /* errorInd */)
+ override {
+ return Void();
+ }
+ Return<void> onWpsEventPbcOverlap() override { return Void(); }
+ Return<void> onExtRadioWorkStart(uint32_t /* id */) override {
+ return Void();
+ }
+ Return<void> onExtRadioWorkTimeout(uint32_t /* id*/) override {
+ return Void();
+ }
+};
+
/*
* Create:
* Ensures that an instance of the ISupplicantStaIface proxy object is
@@ -30,3 +144,257 @@
EXPECT_NE(nullptr, getSupplicantStaIface().get());
stopSupplicant();
}
+
+/*
+ * RegisterCallback
+ */
+TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback) {
+ sta_iface_->registerCallback(
+ new IfaceCallback(), [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * listNetworks.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, listNetworks) {
+ sta_iface_->listNetworks([](const SupplicantStatus& status,
+ const hidl_vec<SupplicantNetworkId>& ids) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(0u, ids.size());
+ });
+
+ sp<ISupplicantStaNetwork> sta_network = createSupplicantStaNetwork();
+ EXPECT_NE(nullptr, sta_network.get());
+
+ sta_iface_->listNetworks([](const SupplicantStatus& status,
+ const hidl_vec<SupplicantNetworkId>& ids) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_LT(0u, ids.size());
+ });
+}
+
+/*
+ * Reassociate.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, Reassociate) {
+ sta_iface_->reassociate([](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * Reconnect.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, Reconnect) {
+ sta_iface_->reconnect([](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_IFACE_NOT_DISCONNECTED,
+ status.code);
+ });
+}
+
+/*
+ * Disconnect.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, Disconnect) {
+ sta_iface_->disconnect([](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * SetPowerSave.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, SetPowerSave) {
+ sta_iface_->setPowerSave(true, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_iface_->setPowerSave(false, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * InitiateTdlsDiscover.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, InitiateTdlsDiscover) {
+ sta_iface_->initiateTdlsDiscover(
+ mac_addr_, [](const SupplicantStatus& status) {
+ // These requests will fail unless the MAC address mentioned is
+ // actually around.
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+}
+
+/*
+ * InitiateTdlsSetup.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, InitiateTdlsSetup) {
+ sta_iface_->initiateTdlsSetup(
+ mac_addr_, [](const SupplicantStatus& status) {
+ // These requests will fail unless the MAC address mentioned is
+ // actually around.
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+}
+
+/*
+ * InitiateTdlsTeardown.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, InitiateTdlsTeardown) {
+ sta_iface_->initiateTdlsTeardown(
+ mac_addr_, [](const SupplicantStatus& status) {
+ // These requests will fail unless the MAC address mentioned is
+ // actually around.
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+}
+
+/*
+ * InitiateAnqpQuery.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, InitiateAnqpQuery) {
+ std::vector<ISupplicantStaIface::AnqpInfoId> anqp_ids(
+ kTestAnqpInfoIds, kTestAnqpInfoIds + sizeof(kTestAnqpInfoIds));
+ std::vector<ISupplicantStaIface::Hs20AnqpSubtypes> hs_types(
+ kTestHs20Types, kTestHs20Types + sizeof(kTestHs20Types));
+ sta_iface_->initiateAnqpQuery(
+ mac_addr_, anqp_ids, hs_types, [](const SupplicantStatus& status) {
+ // These requests will fail unless the BSSID mentioned is actually
+ // present in scan results.
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+}
+
+/*
+ * InitiateHs20IconQuery.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, InitiateHs20IconQuery) {
+ sta_iface_->initiateHs20IconQuery(
+ mac_addr_, kTestHs20IconFile, [](const SupplicantStatus& status) {
+ // These requests will fail unless the BSSID mentioned is actually
+ // present in scan results.
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+ });
+}
+
+/*
+ * GetMacAddress.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, GetMacAddress) {
+ sta_iface_->getMacAddress([](const SupplicantStatus& status,
+ const hidl_array<uint8_t, 6>& mac_addr) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ std::array<uint8_t, 6> std_mac_addr(mac_addr);
+ EXPECT_GT(6, std::count(std_mac_addr.begin(), std_mac_addr.end(), 0));
+ });
+}
+
+/*
+ * StartRxFilter.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, StartRxFilter) {
+ sta_iface_->startRxFilter([](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * StopRxFilter.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, StopRxFilter) {
+ sta_iface_->stopRxFilter([](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * AddRxFilter.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, AddRxFilter) {
+ sta_iface_->addRxFilter(ISupplicantStaIface::RxFilterType::V4_MULTICAST,
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS,
+ status.code);
+ });
+ sta_iface_->addRxFilter(ISupplicantStaIface::RxFilterType::V6_MULTICAST,
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS,
+ status.code);
+ });
+}
+
+/*
+ * RemoveRxFilter.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, RemoveRxFilter) {
+ sta_iface_->removeRxFilter(ISupplicantStaIface::RxFilterType::V4_MULTICAST,
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS,
+ status.code);
+ });
+ sta_iface_->removeRxFilter(ISupplicantStaIface::RxFilterType::V6_MULTICAST,
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS,
+ status.code);
+ });
+}
+
+/*
+ * SetBtCoexistenceMode.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, SetBtCoexistenceMode) {
+ sta_iface_->setBtCoexistenceMode(
+ ISupplicantStaIface::BtCoexistenceMode::ENABLED,
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_iface_->setBtCoexistenceMode(
+ ISupplicantStaIface::BtCoexistenceMode::DISABLED,
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_iface_->setBtCoexistenceMode(
+ ISupplicantStaIface::BtCoexistenceMode::SENSE,
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * SetBtCoexistenceScanModeEnabled.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, SetBtCoexistenceScanModeEnabled) {
+ sta_iface_->setBtCoexistenceScanModeEnabled(
+ true, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_iface_->setBtCoexistenceScanModeEnabled(
+ false, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * SetSuspendModeEnabled.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, SetSuspendModeEnabled) {
+ sta_iface_->setSuspendModeEnabled(true, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_iface_->setSuspendModeEnabled(
+ false, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * SetCountryCode.
+ */
+TEST_F(SupplicantStaIfaceHidlTest, SetCountryCode) {
+ sta_iface_->setCountryCode(
+ kTestCountryCode, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
index cde75fa..aa84e9a 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -18,8 +18,104 @@
#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
+
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
+
#include "supplicant_hidl_test_utils.h"
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
+using ::android::hardware::wifi::supplicant::V1_0::
+ ISupplicantStaNetworkCallback;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+
+namespace {
+constexpr char kTestSsidStr[] = "TestSsid1234";
+constexpr char kTestPsk[] = "TestPsk123";
+constexpr char kTestIdStr[] = "TestIdstr";
+constexpr char kTestEapPasswdStr[] = "TestEapPasswd1234";
+constexpr char kTestEapCert[] = "keystore://CERT";
+constexpr char kTestEapPrivateKeyId[] = "key_id";
+constexpr char kTestEapMatch[] = "match";
+constexpr char kTestEapEngineID[] = "engine_id";
+constexpr uint8_t kTestBssid[] = {0x56, 0x67, 0x67, 0xf4, 0x56, 0x92};
+constexpr uint8_t kTestWepKey[] = {0x56, 0x67, 0x67, 0xf4, 0x56};
+constexpr uint8_t kTestKc[] = {0x56, 0x67, 0x67, 0xf4, 0x76, 0x87, 0x98, 0x12};
+constexpr uint8_t kTestSres[] = {0x56, 0x67, 0x67, 0xf4};
+constexpr uint8_t kTestRes[] = {0x56, 0x67, 0x67, 0xf4, 0x67};
+constexpr uint8_t kTestIk[] = {[0 ... 15] = 0x65};
+constexpr uint8_t kTestCk[] = {[0 ... 15] = 0x45};
+constexpr uint8_t kTestIdentity[] = {0x45, 0x67, 0x98, 0x67, 0x56};
+constexpr uint32_t kTestWepTxKeyIdx = 2;
+constexpr uint32_t kTestKeyMgmt = (ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK |
+ ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP);
+constexpr uint32_t kTestProto = (ISupplicantStaNetwork::ProtoMask::OSEN |
+ ISupplicantStaNetwork::ProtoMask::RSN);
+constexpr uint32_t kTestAuthAlg = (ISupplicantStaNetwork::AuthAlgMask::OPEN |
+ ISupplicantStaNetwork::AuthAlgMask::SHARED);
+constexpr uint32_t kTestGroupCipher =
+ (ISupplicantStaNetwork::GroupCipherMask::CCMP |
+ ISupplicantStaNetwork::GroupCipherMask::WEP104);
+constexpr uint32_t kTestPairwiseCipher =
+ (ISupplicantStaNetwork::PairwiseCipherMask::CCMP |
+ ISupplicantStaNetwork::PairwiseCipherMask::TKIP);
+} // namespace
+
+class SupplicantStaNetworkHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ startSupplicantAndWaitForHidlService();
+ EXPECT_TRUE(turnOnExcessiveLogging());
+ sta_network_ = createSupplicantStaNetwork();
+ ASSERT_NE(sta_network_.get(), nullptr);
+
+ ssid_.assign(kTestSsidStr, kTestSsidStr + strlen(kTestSsidStr));
+ }
+
+ virtual void TearDown() override { stopSupplicant(); }
+
+ protected:
+ void removeNetwork() {
+ sp<ISupplicantStaIface> sta_iface = getSupplicantStaIface();
+ ASSERT_NE(nullptr, sta_iface.get());
+ uint32_t net_id;
+ sta_network_->getId([&](const SupplicantStatus& status, int network_id) {
+ ASSERT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ net_id = network_id;
+ });
+ sta_iface->removeNetwork(net_id, [](const SupplicantStatus& status) {
+ ASSERT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ }
+
+ // ISupplicantStaNetwork object used for all tests in this fixture.
+ sp<ISupplicantStaNetwork> sta_network_;
+ // SSID to use for various tests.
+ std::vector<uint8_t> ssid_;
+};
+
+class NetworkCallback : public ISupplicantStaNetworkCallback {
+ Return<void> onNetworkEapSimGsmAuthRequest(
+ const ISupplicantStaNetworkCallback::NetworkRequestEapSimGsmAuthParams&
+ /* params */) override {
+ return Void();
+ }
+ Return<void> onNetworkEapSimUmtsAuthRequest(
+ const ISupplicantStaNetworkCallback::NetworkRequestEapSimUmtsAuthParams&
+ /* params */) override {
+ return Void();
+ }
+ Return<void> onNetworkEapIdentityRequest() override { return Void(); }
+};
+
/*
* Create:
* Ensures that an instance of the ISupplicantStaNetwork proxy object is
@@ -30,3 +126,535 @@
EXPECT_NE(nullptr, createSupplicantStaNetwork().get());
stopSupplicant();
}
+
+/*
+ * RegisterCallback
+ */
+TEST_F(SupplicantStaNetworkHidlTest, RegisterCallback) {
+ sta_network_->registerCallback(
+ new NetworkCallback(), [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/* Tests out the various setter/getter methods. */
+/*
+ * SetGetSsid
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetSsid) {
+ sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getSsid(
+ [&](const SupplicantStatus& status, const hidl_vec<uint8_t>& get_ssid) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(ssid_, std::vector<uint8_t>(get_ssid));
+ });
+}
+
+/*
+ * SetGetBssid
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetBssid) {
+ std::array<uint8_t, 6> set_bssid;
+ memcpy(set_bssid.data(), kTestBssid, set_bssid.size());
+ sta_network_->setBssid(set_bssid, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getBssid([&](const SupplicantStatus& status,
+ const hidl_array<uint8_t, 6>& get_bssid_hidl) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ std::array<uint8_t, 6> get_bssid;
+ memcpy(get_bssid.data(), get_bssid_hidl.data(), get_bssid.size());
+ EXPECT_EQ(set_bssid, get_bssid);
+ });
+}
+
+/*
+ * SetGetKeyMgmt
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetKeyMgmt) {
+ sta_network_->setKeyMgmt(kTestKeyMgmt, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getKeyMgmt(
+ [&](const SupplicantStatus& status, uint32_t key_mgmt) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(key_mgmt, kTestKeyMgmt);
+ });
+}
+
+/*
+ * SetGetProto
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetProto) {
+ sta_network_->setProto(kTestProto, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getProto([&](const SupplicantStatus& status, uint32_t proto) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(proto, kTestProto);
+ });
+}
+
+/*
+ * SetGetKeyAuthAlg
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetAuthAlg) {
+ sta_network_->setAuthAlg(kTestAuthAlg, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getAuthAlg(
+ [&](const SupplicantStatus& status, uint32_t auth_alg) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(auth_alg, kTestAuthAlg);
+ });
+}
+
+/*
+ * SetGetGroupCipher
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupCipher) {
+ sta_network_->setGroupCipher(
+ kTestGroupCipher, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getGroupCipher(
+ [&](const SupplicantStatus& status, uint32_t group_cipher) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(group_cipher, kTestGroupCipher);
+ });
+}
+
+/*
+ * SetGetPairwiseCipher
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher) {
+ sta_network_->setPairwiseCipher(
+ kTestPairwiseCipher, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getPairwiseCipher(
+ [&](const SupplicantStatus& status, uint32_t pairwise_cipher) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(pairwise_cipher, kTestPairwiseCipher);
+ });
+}
+
+/*
+ * SetGetPskPassphrase
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetPskPassphrase) {
+ sta_network_->setPskPassphrase(
+ kTestPsk, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getPskPassphrase(
+ [&](const SupplicantStatus& status, const hidl_string& psk) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(kTestPsk, std::string(psk.c_str()));
+ });
+}
+
+/*
+ * SetGetWepKeys
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetWepTxKeyIdx) {
+ sta_network_->setWepTxKeyIdx(
+ kTestWepTxKeyIdx, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getWepTxKeyIdx(
+ [&](const SupplicantStatus& status, uint32_t key_idx) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(kTestWepTxKeyIdx, key_idx);
+ });
+}
+
+/*
+ * SetGetWepKeys
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetWepKeys) {
+ for (uint32_t i = 0;
+ i < static_cast<uint32_t>(
+ ISupplicantStaNetwork::ParamSizeLimits::WEP_KEYS_MAX_NUM);
+ i++) {
+ std::vector<uint8_t> set_wep_key(std::begin(kTestWepKey),
+ std::end(kTestWepKey));
+ sta_network_->setWepKey(
+ i, set_wep_key, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getWepKey(i, [&](const SupplicantStatus& status,
+ const hidl_vec<uint8_t>& get_wep_key) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(set_wep_key, std::vector<uint8_t>(get_wep_key));
+ });
+ }
+}
+
+/*
+ * SetGetScanSsid
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetScanSsid) {
+ sta_network_->setScanSsid(
+ true, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getScanSsid(
+ [&](const SupplicantStatus& status, bool scan_ssid) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(true, scan_ssid);
+ });
+}
+
+/*
+ * SetGetRequirePmf
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetRequirePmf) {
+ sta_network_->setRequirePmf(
+ true, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getRequirePmf(
+ [&](const SupplicantStatus& status, bool require_pmf) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(true, require_pmf);
+ });
+}
+
+/*
+ * SetGetIdStr
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetIdStr) {
+ sta_network_->setIdStr(
+ kTestIdStr, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getIdStr(
+ [&](const SupplicantStatus& status, const hidl_string& id_str) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(kTestIdStr, std::string(id_str.c_str()));
+ });
+}
+
+
+/*
+ * SetGetEapMethod
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetEapMethod) {
+ ISupplicantStaNetwork::EapMethod set_eap_method =
+ ISupplicantStaNetwork::EapMethod::PEAP;
+ sta_network_->setEapMethod(
+ set_eap_method, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getEapMethod(
+ [&](const SupplicantStatus& status,
+ ISupplicantStaNetwork::EapMethod eap_method) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(set_eap_method, eap_method);
+ });
+}
+
+/*
+ * SetGetEapPhase2Method
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetEapPhase2Method) {
+ ISupplicantStaNetwork::EapPhase2Method set_eap_phase2_method =
+ ISupplicantStaNetwork::EapPhase2Method::NONE;
+ sta_network_->setEapPhase2Method(
+ set_eap_phase2_method, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getEapPhase2Method(
+ [&](const SupplicantStatus& status,
+ ISupplicantStaNetwork::EapPhase2Method eap_phase2_method) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(set_eap_phase2_method, eap_phase2_method);
+ });
+}
+
+/*
+ * SetGetEapIdentity
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetEapIdentity) {
+ std::vector<uint8_t> set_identity(kTestIdentity, kTestIdentity + sizeof(kTestIdentity));
+ sta_network_->setEapIdentity(
+ set_identity, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getEapIdentity(
+ [&](const SupplicantStatus& status, const std::vector<uint8_t>& identity) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(set_identity, identity);
+ });
+}
+
+/*
+ * SetGetEapAnonymousIdentity
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetEapAnonymousIdentity) {
+ std::vector<uint8_t> set_identity(kTestIdentity, kTestIdentity + sizeof(kTestIdentity));
+ sta_network_->setEapAnonymousIdentity(
+ set_identity, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getEapAnonymousIdentity(
+ [&](const SupplicantStatus& status, const std::vector<uint8_t>& identity) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(set_identity, identity);
+ });
+}
+
+/*
+ * SetGetEapPassword
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetEapPassword) {
+ std::vector<uint8_t> set_eap_passwd(
+ kTestEapPasswdStr, kTestEapPasswdStr + strlen(kTestEapPasswdStr));
+ sta_network_->setEapPassword(
+ set_eap_passwd, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getEapPassword([&](const SupplicantStatus& status,
+ const hidl_vec<uint8_t>& eap_passwd) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(set_eap_passwd, std::vector<uint8_t>(eap_passwd));
+ });
+}
+
+/*
+ * SetGetEapCACert
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetEapCACert) {
+ sta_network_->setEapCACert(
+ kTestEapCert, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getEapCACert([&](const SupplicantStatus& status,
+ const hidl_string& eap_cert) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(kTestEapCert, std::string(eap_cert.c_str()));
+ });
+}
+
+/*
+ * SetGetEapCAPath
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetEapCAPath) {
+ sta_network_->setEapCAPath(
+ kTestEapCert, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getEapCAPath([&](const SupplicantStatus& status,
+ const hidl_string& eap_cert) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(kTestEapCert, std::string(eap_cert.c_str()));
+ });
+}
+
+/*
+ * SetGetEapClientCert
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetEapClientCert) {
+ sta_network_->setEapClientCert(
+ kTestEapCert, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getEapClientCert([&](const SupplicantStatus& status,
+ const hidl_string& eap_cert) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(kTestEapCert, std::string(eap_cert.c_str()));
+ });
+}
+
+/*
+ * SetGetEapPrivateKeyId
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetEapPrivateKeyId) {
+ sta_network_->setEapPrivateKeyId(
+ kTestEapPrivateKeyId, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getEapPrivateKeyId([&](const SupplicantStatus& status,
+ const hidl_string& key_id) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(kTestEapPrivateKeyId, std::string(key_id.c_str()));
+ });
+}
+
+/*
+ * SetGetEapAltSubjectMatch
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetEapAltSubjectMatch) {
+ sta_network_->setEapAltSubjectMatch(
+ kTestEapMatch, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getEapAltSubjectMatch([&](const SupplicantStatus& status,
+ const hidl_string& match) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(kTestEapMatch, std::string(match.c_str()));
+ });
+}
+
+/*
+ * SetGetEapDomainSuffixMatch
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetEapDomainSuffixMatch) {
+ sta_network_->setEapDomainSuffixMatch(
+ kTestEapMatch, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getEapDomainSuffixMatch([&](const SupplicantStatus& status,
+ const hidl_string& match) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(kTestEapMatch, std::string(match.c_str()));
+ });
+}
+
+/*
+ * SetGetEapEngine
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetEapEngine) {
+ sta_network_->setEapEngine(
+ true, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getEapEngine([&](const SupplicantStatus& status,
+ bool enable) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(true, enable);
+ });
+}
+
+/*
+ * SetGetEapEngineID
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetEapEngineID) {
+ sta_network_->setEapEngineID(
+ kTestEapEngineID, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->getEapEngineID([&](const SupplicantStatus& status,
+ const hidl_string& id) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(kTestEapEngineID, std::string(id.c_str()));
+ });
+}
+
+/*
+ * Enable
+ */
+TEST_F(SupplicantStaNetworkHidlTest, Enable) {
+ // wpa_supplicant doesn't perform any connection initiation
+ // unless atleast the Ssid and Ket mgmt params are set.
+ sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->setKeyMgmt(kTestKeyMgmt, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ sta_network_->enable(false, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->enable(true, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ // Now remove the network and ensure that the calls fail.
+ removeNetwork();
+ sta_network_->enable(true, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_NETWORK_INVALID, status.code);
+ });
+}
+
+/*
+ * Disable
+ */
+TEST_F(SupplicantStaNetworkHidlTest, Disable) {
+ // wpa_supplicant doesn't perform any connection initiation
+ // unless atleast the Ssid and Ket mgmt params are set.
+ sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->setKeyMgmt(kTestKeyMgmt, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ sta_network_->disable([](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ // Now remove the network and ensure that the calls fail.
+ removeNetwork();
+ sta_network_->disable([](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_NETWORK_INVALID, status.code);
+ });
+}
+
+/*
+ * Select.
+ */
+TEST_F(SupplicantStaNetworkHidlTest, Select) {
+ // wpa_supplicant doesn't perform any connection initiation
+ // unless atleast the Ssid and Ket mgmt params are set.
+ sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ sta_network_->setKeyMgmt(kTestKeyMgmt, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ sta_network_->select([](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+ // Now remove the network and ensure that the calls fail.
+ removeNetwork();
+ sta_network_->select([](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_NETWORK_INVALID, status.code);
+ });
+}
+
+/*
+ * SendNetworkEapSimGsmAuthResponse
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapSimGsmAuthResponse) {
+ std::vector<ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>
+ params;
+ ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams param;
+ memcpy(param.kc.data(), kTestKc, param.kc.size());
+ memcpy(param.sres.data(), kTestSres, param.sres.size());
+ params.push_back(param);
+ sta_network_->sendNetworkEapSimGsmAuthResponse(
+ params, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * SendNetworkEapSimUmtsAuthResponse
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapSimUmtsAuthResponse) {
+ ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams params;
+ params.res = std::vector<uint8_t>(kTestRes, kTestRes + sizeof(kTestRes));
+ memcpy(params.ik.data(), kTestIk, params.ik.size());
+ memcpy(params.ck.data(), kTestCk, params.ck.size());
+ sta_network_->sendNetworkEapSimUmtsAuthResponse(
+ params, [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}
+
+/*
+ * SendNetworkEapIdentityResponse
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapIdentityResponse) {
+ sta_network_->sendNetworkEapIdentityResponse(
+ std::vector<uint8_t>(kTestIdentity,
+ kTestIdentity + sizeof(kTestIdentity)),
+ [](const SupplicantStatus& status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+}