mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 05:49:27 +00:00
Face Biometric Virtual HAL Authentication Implementation
Bug: 294254230 Test: atest VtsHalBiometricsFaceTargetTest Test: atest VtsHalBiometricsFingerprintTargetTest Test: atest android.hardware.biometrics.face.FakeFaceEngineTest Test: atest android.hardware.biometrics.fingerprint.FakeFingerprintEngineTest Change-Id: Id7a4698730307235c5de94811f5e396ff4b9c5ae
This commit is contained in:
@@ -23,6 +23,9 @@
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/parseint.h>
|
||||
using ::android::base::ParseInt;
|
||||
|
||||
namespace aidl::android::hardware::biometrics {
|
||||
|
||||
#define SLEEP_MS(x) \
|
||||
@@ -64,6 +67,87 @@ class Util {
|
||||
std::sregex_token_iterator());
|
||||
return parts;
|
||||
}
|
||||
|
||||
// Returns a vector of integers for the string separated by comma,
|
||||
// Empty vector is returned if there is any parsing error
|
||||
static std::vector<int32_t> parseIntSequence(const std::string& str,
|
||||
const std::string& sep = ",") {
|
||||
std::vector<std::string> seqs = Util::split(str, sep);
|
||||
std::vector<int32_t> res;
|
||||
|
||||
for (const auto& seq : seqs) {
|
||||
int32_t val;
|
||||
if (ParseInt(seq, &val)) {
|
||||
res.push_back(val);
|
||||
} else {
|
||||
LOG(WARNING) << "Invalid int sequence:" + str + " seq:" + seq;
|
||||
res.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Parses a single enrollment stage string in the format of
|
||||
// enroll_stage_spec: <duration>[-acquiredInfos]
|
||||
// duration: integerInMs
|
||||
// acquiredInfos: [info1,info2,...]
|
||||
//
|
||||
// Returns false if there is parsing error
|
||||
//
|
||||
static bool parseEnrollmentCaptureSingle(const std::string& str,
|
||||
std::vector<std::vector<int32_t>>& res) {
|
||||
std::vector<int32_t> defaultAcquiredInfo = {1};
|
||||
bool aborted = true;
|
||||
|
||||
do {
|
||||
std::smatch sms;
|
||||
// Parses strings like "1000-[5,1]" or "500"
|
||||
std::regex ex("((\\d+)(-\\[([\\d|,]+)\\])?)");
|
||||
if (!regex_match(str.cbegin(), str.cend(), sms, ex)) break;
|
||||
int32_t duration;
|
||||
if (!ParseInt(sms.str(2), &duration)) break;
|
||||
res.push_back({duration});
|
||||
if (!sms.str(4).empty()) {
|
||||
auto acqv = parseIntSequence(sms.str(4));
|
||||
if (acqv.empty()) break;
|
||||
res.push_back(acqv);
|
||||
} else
|
||||
res.push_back(defaultAcquiredInfo);
|
||||
aborted = false;
|
||||
} while (0);
|
||||
|
||||
return !aborted;
|
||||
}
|
||||
|
||||
// Parses enrollment string consisting of one or more stages in the formst of
|
||||
// <enroll_stage_spec>[,enroll_stage_spec,...]
|
||||
// Empty vector is returned in case of parsing error
|
||||
static std::vector<std::vector<int32_t>> parseEnrollmentCapture(const std::string& str) {
|
||||
std::vector<std::vector<int32_t>> res;
|
||||
|
||||
std::string s(str);
|
||||
s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
|
||||
bool aborted = false;
|
||||
std::smatch sms;
|
||||
// Parses strings like "1000-[5,1],500,800-[6,5,1]"
|
||||
// -------------- ----- ---------------
|
||||
// into parts: A B C
|
||||
while (regex_search(s, sms, std::regex("^(,)?(\\d+(-\\[[\\d|,]+\\])?)"))) {
|
||||
if (!parseEnrollmentCaptureSingle(sms.str(2), res)) {
|
||||
aborted = true;
|
||||
break;
|
||||
}
|
||||
s = sms.suffix();
|
||||
}
|
||||
if (aborted || s.length() != 0) {
|
||||
res.clear();
|
||||
LOG(ERROR) << "Failed to parse enrollment captures:" + str;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::biometrics
|
||||
|
||||
@@ -136,56 +136,127 @@ void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationI
|
||||
const std::future<void>& cancel) {
|
||||
BEGIN_OP(FaceHalProperties::operation_authenticate_latency().value_or(0));
|
||||
|
||||
// Signal to the framework that we have begun authenticating.
|
||||
AuthenticationFrame frame;
|
||||
frame.data.acquiredInfo = AcquiredInfo::START;
|
||||
frame.data.vendorCode = 0;
|
||||
cb->onAuthenticationFrame(frame);
|
||||
|
||||
// Also signal that we have opened the camera.
|
||||
frame = {};
|
||||
frame.data.acquiredInfo = AcquiredInfo::FIRST_FRAME_RECEIVED;
|
||||
frame.data.vendorCode = 0;
|
||||
cb->onAuthenticationFrame(frame);
|
||||
|
||||
auto now = Util::getSystemNanoTime();
|
||||
int64_t duration = FaceHalProperties::operation_authenticate_duration().value_or(0);
|
||||
if (duration > 0) {
|
||||
do {
|
||||
SLEEP_MS(5);
|
||||
} while (!Util::hasElapsed(now, duration));
|
||||
}
|
||||
|
||||
if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
|
||||
LOG(ERROR) << "Fail: operation_authenticate_fails";
|
||||
cb->onError(Error::VENDOR, 0 /* vendorError */);
|
||||
return;
|
||||
}
|
||||
|
||||
if (FaceHalProperties::lockout().value_or(false)) {
|
||||
LOG(ERROR) << "Fail: lockout";
|
||||
cb->onLockoutPermanent();
|
||||
cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
|
||||
return;
|
||||
}
|
||||
|
||||
if (shouldCancel(cancel)) {
|
||||
LOG(ERROR) << "Fail: cancel";
|
||||
cb->onError(Error::CANCELED, 0 /* vendorCode */);
|
||||
return;
|
||||
}
|
||||
|
||||
auto id = FaceHalProperties::enrollment_hit().value_or(0);
|
||||
auto enrolls = FaceHalProperties::enrollments();
|
||||
auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
|
||||
if (id < 0 || !isEnrolled) {
|
||||
LOG(ERROR) << (isEnrolled ? "invalid enrollment hit" : "Fail: not enrolled");
|
||||
cb->onAuthenticationFailed();
|
||||
|
||||
auto vec2str = [](std::vector<AcquiredInfo> va) {
|
||||
std::stringstream ss;
|
||||
bool isFirst = true;
|
||||
for (auto ac : va) {
|
||||
if (!isFirst) ss << ",";
|
||||
ss << std::to_string((int8_t)ac);
|
||||
isFirst = false;
|
||||
}
|
||||
return ss.str();
|
||||
};
|
||||
|
||||
// default behavior mimic face sensor in U
|
||||
int64_t defaultAuthDuration = 500;
|
||||
std::string defaultAcquiredInfo =
|
||||
vec2str({AcquiredInfo::START, AcquiredInfo::FIRST_FRAME_RECEIVED});
|
||||
if (!isEnrolled) {
|
||||
std::vector<AcquiredInfo> v;
|
||||
for (int i = 0; i < 56; i++) v.push_back(AcquiredInfo::NOT_DETECTED);
|
||||
defaultAcquiredInfo += "," + vec2str(v);
|
||||
defaultAuthDuration = 2100;
|
||||
} else {
|
||||
defaultAcquiredInfo += "," + vec2str({AcquiredInfo::TOO_BRIGHT, AcquiredInfo::TOO_BRIGHT,
|
||||
AcquiredInfo::TOO_BRIGHT, AcquiredInfo::TOO_BRIGHT,
|
||||
AcquiredInfo::GOOD, AcquiredInfo::GOOD});
|
||||
}
|
||||
|
||||
int64_t now = Util::getSystemNanoTime();
|
||||
int64_t duration =
|
||||
FaceHalProperties::operation_authenticate_duration().value_or(defaultAuthDuration);
|
||||
auto acquired =
|
||||
FaceHalProperties::operation_authenticate_acquired().value_or(defaultAcquiredInfo);
|
||||
auto acquiredInfos = Util::parseIntSequence(acquired);
|
||||
int N = acquiredInfos.size();
|
||||
|
||||
if (N == 0) {
|
||||
LOG(ERROR) << "Fail to parse authentiate acquired info: " + acquired;
|
||||
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
|
||||
return;
|
||||
}
|
||||
|
||||
cb->onAuthenticationSucceeded(id, {} /* hat */);
|
||||
int i = 0;
|
||||
do {
|
||||
if (FaceHalProperties::lockout().value_or(false)) {
|
||||
LOG(ERROR) << "Fail: lockout";
|
||||
cb->onLockoutPermanent();
|
||||
cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
|
||||
return;
|
||||
}
|
||||
|
||||
if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
|
||||
LOG(ERROR) << "Fail: operation_authenticate_fails";
|
||||
cb->onAuthenticationFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
auto err = FaceHalProperties::operation_authenticate_error().value_or(0);
|
||||
if (err != 0) {
|
||||
LOG(ERROR) << "Fail: operation_authenticate_error";
|
||||
auto ec = convertError(err);
|
||||
cb->onError(ec.first, ec.second);
|
||||
return; /* simply terminating current operation for any user inserted error,
|
||||
revisit if tests need*/
|
||||
}
|
||||
|
||||
if (shouldCancel(cancel)) {
|
||||
LOG(ERROR) << "Fail: cancel";
|
||||
cb->onError(Error::CANCELED, 0 /* vendorCode */);
|
||||
return;
|
||||
}
|
||||
|
||||
if (i < N) {
|
||||
auto ac = convertAcquiredInfo(acquiredInfos[i]);
|
||||
AuthenticationFrame frame;
|
||||
frame.data.acquiredInfo = ac.first;
|
||||
frame.data.vendorCode = ac.second;
|
||||
cb->onAuthenticationFrame(frame);
|
||||
LOG(INFO) << "AcquiredInfo:" << i << ": (" << (int)ac.first << "," << (int)ac.second
|
||||
<< ")";
|
||||
i++;
|
||||
}
|
||||
|
||||
SLEEP_MS(duration / N);
|
||||
} while (!Util::hasElapsed(now, duration));
|
||||
|
||||
if (id > 0 && isEnrolled) {
|
||||
cb->onAuthenticationSucceeded(id, {} /* hat */);
|
||||
return;
|
||||
} else {
|
||||
LOG(ERROR) << "Fail: face not enrolled";
|
||||
cb->onAuthenticationFailed();
|
||||
cb->onError(Error::TIMEOUT, 0 /* vendorError*/);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<AcquiredInfo, int32_t> FakeFaceEngine::convertAcquiredInfo(int32_t code) {
|
||||
std::pair<AcquiredInfo, int32_t> res;
|
||||
if (code > FACE_ACQUIRED_VENDOR_BASE) {
|
||||
res.first = AcquiredInfo::VENDOR;
|
||||
res.second = code - FACE_ACQUIRED_VENDOR_BASE;
|
||||
} else {
|
||||
res.first = (AcquiredInfo)code;
|
||||
res.second = 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::pair<Error, int32_t> FakeFaceEngine::convertError(int32_t code) {
|
||||
std::pair<Error, int32_t> res;
|
||||
if (code > FACE_ERROR_VENDOR_BASE) {
|
||||
res.first = Error::VENDOR;
|
||||
res.second = code - FACE_ERROR_VENDOR_BASE;
|
||||
} else {
|
||||
res.first = (Error)code;
|
||||
res.second = 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel) {
|
||||
@@ -315,4 +386,4 @@ void FakeFaceEngine::resetLockoutImpl(ISessionCallback* cb,
|
||||
cb->onLockoutCleared();
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::biometrics::face
|
||||
} // namespace aidl::android::hardware::biometrics::face
|
||||
|
||||
@@ -62,6 +62,12 @@ class FakeFaceEngine {
|
||||
void resetLockoutImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& /*hat*/);
|
||||
|
||||
std::mt19937 mRandom;
|
||||
|
||||
private:
|
||||
static constexpr int32_t FACE_ACQUIRED_VENDOR_BASE = 1000;
|
||||
static constexpr int32_t FACE_ERROR_VENDOR_BASE = 1000;
|
||||
std::pair<AcquiredInfo, int32_t> convertAcquiredInfo(int32_t code);
|
||||
std::pair<Error, int32_t> convertError(int32_t code);
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::biometrics::face
|
||||
|
||||
@@ -18,6 +18,7 @@ On pixel devicse (non-CF), by default (after manufacture reset), Face VHAL is no
|
||||
Face VHAL enabling is gated by the following two AND conditions:
|
||||
1. The Face VHAL feature flag (as part of Trunk-development strategy) must be tured until the flags life-cycle ends.
|
||||
2. The Face VHAL must be enabled via sysprop
|
||||
See adb commands below
|
||||
|
||||
##Getting Stared
|
||||
|
||||
@@ -47,8 +48,7 @@ authentication failure, set the hit id to a different value.
|
||||
$ adb shell setprop vendor.face.virtual.operation_authenticate_duration 800
|
||||
$ adb shell setprop vendor.face.virtual.enrollment_hit 1
|
||||
```
|
||||
Note: At the initial phase of the Face VHAL development, Face-on-camera simulation is not supported, hence
|
||||
the authentication immediately occurrs as soon as the authentication request arriving at VHAL.
|
||||
Refer to face.sysprop for full supported features of authentication, such as error and acquiredInfo insertion
|
||||
|
||||
|
||||
## Enrollment via Setup
|
||||
|
||||
@@ -157,3 +157,22 @@ prop {
|
||||
access: ReadWrite
|
||||
api_name: "operation_authenticate_duration"
|
||||
}
|
||||
|
||||
# insert error for authenticate operations
|
||||
prop {
|
||||
prop_name: "vendor.face.virtual.operation_authenticate_error"
|
||||
type: Integer
|
||||
scope: Internal
|
||||
access: ReadWrite
|
||||
api_name: "operation_authenticate_error"
|
||||
}
|
||||
|
||||
# acquired info during authentication in format of sequence
|
||||
prop {
|
||||
prop_name: "vendor.face.virtual.operation_authenticate_acquired"
|
||||
type: String
|
||||
scope: Internal
|
||||
access: ReadWrite
|
||||
api_name: "operation_authenticate_acquired"
|
||||
}
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ TEST_F(FakeFaceEngineTest, AuthenticateFailedForUnEnrolled) {
|
||||
FaceHalProperties::enrollments({3});
|
||||
FaceHalProperties::enrollment_hit(100);
|
||||
mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
|
||||
ASSERT_EQ(Error::UNABLE_TO_PROCESS, mCallback->mError);
|
||||
ASSERT_EQ(Error::TIMEOUT, mCallback->mError);
|
||||
ASSERT_TRUE(mCallback->mAuthenticateFailed);
|
||||
}
|
||||
|
||||
@@ -380,4 +380,4 @@ TEST_F(FakeFaceEngineTest, ResetLockoutWithAuth) {
|
||||
ASSERT_FALSE(mCallback->mAuthenticateFailed);
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::biometrics::face
|
||||
} // namespace aidl::android::hardware::biometrics::face
|
||||
|
||||
@@ -142,7 +142,7 @@ bool FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb,
|
||||
return true;
|
||||
}
|
||||
auto enrollmentId = std::stoi(parts[0]);
|
||||
auto progress = parseEnrollmentCapture(parts[1]);
|
||||
auto progress = Util::parseEnrollmentCapture(parts[1]);
|
||||
for (size_t i = 0; i < progress.size(); i += 2) {
|
||||
auto left = (progress.size() - i) / 2 - 1;
|
||||
auto duration = progress[i][0];
|
||||
@@ -193,7 +193,7 @@ bool FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb,
|
||||
int64_t now = Util::getSystemNanoTime();
|
||||
int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(10);
|
||||
auto acquired = FingerprintHalProperties::operation_authenticate_acquired().value_or("1");
|
||||
auto acquiredInfos = parseIntSequence(acquired);
|
||||
auto acquiredInfos = Util::parseIntSequence(acquired);
|
||||
int N = acquiredInfos.size();
|
||||
|
||||
if (N == 0) {
|
||||
@@ -271,7 +271,7 @@ bool FakeFingerprintEngine::onDetectInteractFingerDown(ISessionCallback* cb,
|
||||
FingerprintHalProperties::operation_detect_interaction_duration().value_or(10);
|
||||
|
||||
auto acquired = FingerprintHalProperties::operation_detect_interaction_acquired().value_or("1");
|
||||
auto acquiredInfos = parseIntSequence(acquired);
|
||||
auto acquiredInfos = Util::parseIntSequence(acquired);
|
||||
int N = acquiredInfos.size();
|
||||
int64_t now = Util::getSystemNanoTime();
|
||||
|
||||
@@ -450,76 +450,6 @@ SensorLocation FakeFingerprintEngine::defaultSensorLocation() {
|
||||
return SensorLocation();
|
||||
}
|
||||
|
||||
std::vector<int32_t> FakeFingerprintEngine::parseIntSequence(const std::string& str,
|
||||
const std::string& sep) {
|
||||
std::vector<std::string> seqs = Util::split(str, sep);
|
||||
std::vector<int32_t> res;
|
||||
|
||||
for (const auto& seq : seqs) {
|
||||
int32_t val;
|
||||
if (ParseInt(seq, &val)) {
|
||||
res.push_back(val);
|
||||
} else {
|
||||
LOG(WARNING) << "Invalid int sequence:" + str;
|
||||
res.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FakeFingerprintEngine::parseEnrollmentCaptureSingle(const std::string& str,
|
||||
std::vector<std::vector<int32_t>>& res) {
|
||||
std::vector<int32_t> defaultAcquiredInfo = {(int32_t)AcquiredInfo::GOOD};
|
||||
bool aborted = true;
|
||||
|
||||
do {
|
||||
std::smatch sms;
|
||||
// Parses strings like "1000-[5,1]" or "500"
|
||||
std::regex ex("((\\d+)(-\\[([\\d|,]+)\\])?)");
|
||||
if (!regex_match(str.cbegin(), str.cend(), sms, ex)) break;
|
||||
int32_t duration;
|
||||
if (!ParseInt(sms.str(2), &duration)) break;
|
||||
res.push_back({duration});
|
||||
if (!sms.str(4).empty()) {
|
||||
auto acqv = parseIntSequence(sms.str(4));
|
||||
if (acqv.empty()) break;
|
||||
res.push_back(acqv);
|
||||
} else
|
||||
res.push_back(defaultAcquiredInfo);
|
||||
aborted = false;
|
||||
} while (0);
|
||||
|
||||
return !aborted;
|
||||
}
|
||||
|
||||
std::vector<std::vector<int32_t>> FakeFingerprintEngine::parseEnrollmentCapture(
|
||||
const std::string& str) {
|
||||
std::vector<std::vector<int32_t>> res;
|
||||
|
||||
std::string s(str);
|
||||
s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
|
||||
bool aborted = false;
|
||||
std::smatch sms;
|
||||
// Parses strings like "1000-[5,1],500,800-[6,5,1]"
|
||||
// ---------- --- -----------
|
||||
// into parts: A B C
|
||||
while (regex_search(s, sms, std::regex("^(,)?(\\d+(-\\[[\\d|,]+\\])?)"))) {
|
||||
if (!parseEnrollmentCaptureSingle(sms.str(2), res)) {
|
||||
aborted = true;
|
||||
break;
|
||||
}
|
||||
s = sms.suffix();
|
||||
}
|
||||
if (aborted || s.length() != 0) {
|
||||
res.clear();
|
||||
LOG(ERROR) << "Failed to parse enrollment captures:" + str;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::pair<AcquiredInfo, int32_t> FakeFingerprintEngine::convertAcquiredInfo(int32_t code) {
|
||||
std::pair<AcquiredInfo, int32_t> res;
|
||||
if (code > FINGERPRINT_ACQUIRED_VENDOR_BASE) {
|
||||
|
||||
@@ -68,10 +68,6 @@ class FakeFingerprintEngine {
|
||||
|
||||
virtual void fingerDownAction();
|
||||
|
||||
std::vector<int32_t> parseIntSequence(const std::string& str, const std::string& sep = ",");
|
||||
|
||||
std::vector<std::vector<int32_t>> parseEnrollmentCapture(const std::string& str);
|
||||
|
||||
int32_t getLatency(const std::vector<std::optional<std::int32_t>>& latencyVec);
|
||||
|
||||
std::mt19937 mRandom;
|
||||
@@ -110,8 +106,6 @@ class FakeFingerprintEngine {
|
||||
static constexpr int32_t FINGERPRINT_ERROR_VENDOR_BASE = 1000;
|
||||
std::pair<AcquiredInfo, int32_t> convertAcquiredInfo(int32_t code);
|
||||
std::pair<Error, int32_t> convertError(int32_t code);
|
||||
bool parseEnrollmentCaptureSingle(const std::string& str,
|
||||
std::vector<std::vector<int32_t>>& res);
|
||||
int32_t getRandomInRange(int32_t bound1, int32_t bound2);
|
||||
bool checkSensorLockout(ISessionCallback*);
|
||||
void clearLockout(ISessionCallback* cb);
|
||||
|
||||
@@ -421,29 +421,29 @@ TEST_F(FakeFingerprintEngineTest, RemoveEnrolled) {
|
||||
|
||||
TEST_F(FakeFingerprintEngineTest, parseIntSequence) {
|
||||
std::vector<int32_t> seqV;
|
||||
seqV = mEngine.parseIntSequence("");
|
||||
seqV = Util::parseIntSequence("");
|
||||
ASSERT_EQ(0, seqV.size());
|
||||
seqV = mEngine.parseIntSequence("2");
|
||||
seqV = Util::parseIntSequence("2");
|
||||
ASSERT_EQ(1, seqV.size());
|
||||
ASSERT_EQ(2, seqV[0]);
|
||||
seqV = mEngine.parseIntSequence("2,3,4");
|
||||
seqV = Util::parseIntSequence("2,3,4");
|
||||
std::vector<int32_t> expV{2, 3, 4};
|
||||
ASSERT_EQ(expV, seqV);
|
||||
seqV = mEngine.parseIntSequence("2,3,a");
|
||||
seqV = Util::parseIntSequence("2,3,a");
|
||||
ASSERT_EQ(0, seqV.size());
|
||||
seqV = mEngine.parseIntSequence("2, 3, 4");
|
||||
seqV = Util::parseIntSequence("2, 3, 4");
|
||||
ASSERT_EQ(expV, seqV);
|
||||
seqV = mEngine.parseIntSequence("123,456");
|
||||
seqV = Util::parseIntSequence("123,456");
|
||||
ASSERT_EQ(2, seqV.size());
|
||||
std::vector<int32_t> expV1{123, 456};
|
||||
ASSERT_EQ(expV1, seqV);
|
||||
seqV = mEngine.parseIntSequence("12f3,456");
|
||||
seqV = Util::parseIntSequence("12f3,456");
|
||||
ASSERT_EQ(0, seqV.size());
|
||||
}
|
||||
|
||||
TEST_F(FakeFingerprintEngineTest, parseEnrollmentCaptureOk) {
|
||||
std::vector<std::vector<int32_t>> ecV;
|
||||
ecV = mEngine.parseEnrollmentCapture("100,200,300");
|
||||
ecV = Util::parseEnrollmentCapture("100,200,300");
|
||||
ASSERT_EQ(6, ecV.size());
|
||||
std::vector<std::vector<int32_t>> expE{{100}, {200}, {300}};
|
||||
std::vector<int32_t> defC{1};
|
||||
@@ -451,26 +451,26 @@ TEST_F(FakeFingerprintEngineTest, parseEnrollmentCaptureOk) {
|
||||
ASSERT_EQ(expE[i / 2], ecV[i]);
|
||||
ASSERT_EQ(defC, ecV[i + 1]);
|
||||
}
|
||||
ecV = mEngine.parseEnrollmentCapture("100");
|
||||
ecV = Util::parseEnrollmentCapture("100");
|
||||
ASSERT_EQ(2, ecV.size());
|
||||
ASSERT_EQ(expE[0], ecV[0]);
|
||||
ASSERT_EQ(defC, ecV[1]);
|
||||
|
||||
ecV = mEngine.parseEnrollmentCapture("100-[5,6,7]");
|
||||
ecV = Util::parseEnrollmentCapture("100-[5,6,7]");
|
||||
std::vector<int32_t> expC{5, 6, 7};
|
||||
ASSERT_EQ(2, ecV.size());
|
||||
for (int i = 0; i < ecV.size(); i += 2) {
|
||||
ASSERT_EQ(expE[i / 2], ecV[i]);
|
||||
ASSERT_EQ(expC, ecV[i + 1]);
|
||||
}
|
||||
ecV = mEngine.parseEnrollmentCapture("100-[5,6,7], 200, 300-[9,10]");
|
||||
ecV = Util::parseEnrollmentCapture("100-[5,6,7], 200, 300-[9,10]");
|
||||
std::vector<std::vector<int32_t>> expC1{{5, 6, 7}, {1}, {9, 10}};
|
||||
ASSERT_EQ(6, ecV.size());
|
||||
for (int i = 0; i < ecV.size(); i += 2) {
|
||||
ASSERT_EQ(expE[i / 2], ecV[i]);
|
||||
ASSERT_EQ(expC1[i / 2], ecV[i + 1]);
|
||||
}
|
||||
ecV = mEngine.parseEnrollmentCapture("100-[5,6,7], 200-[2,1], 300-[9]");
|
||||
ecV = Util::parseEnrollmentCapture("100-[5,6,7], 200-[2,1], 300-[9]");
|
||||
std::vector<std::vector<int32_t>> expC2{{5, 6, 7}, {2, 1}, {9}};
|
||||
ASSERT_EQ(ecV.size(), 6);
|
||||
for (int i = 0; i < ecV.size(); i += 2) {
|
||||
@@ -484,7 +484,7 @@ TEST_F(FakeFingerprintEngineTest, parseEnrollmentCaptureFail) {
|
||||
"100,2x0,300", "200-[f]", "a,b"};
|
||||
std::vector<std::vector<int32_t>> ecV;
|
||||
for (const auto& s : badStr) {
|
||||
ecV = mEngine.parseEnrollmentCapture(s);
|
||||
ecV = Util::parseEnrollmentCapture(s);
|
||||
ASSERT_EQ(ecV.size(), 0);
|
||||
}
|
||||
}
|
||||
@@ -508,7 +508,7 @@ TEST_F(FakeFingerprintEngineTest, randomLatency) {
|
||||
TEST_F(FakeFingerprintEngineTest, lockoutTimer) {
|
||||
mEngine.startLockoutTimer(200, mCallback.get());
|
||||
ASSERT_TRUE(mEngine.getLockoutTimerStarted());
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(210));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(230));
|
||||
ASSERT_FALSE(mEngine.getLockoutTimerStarted());
|
||||
ASSERT_TRUE(mCallback->mLockoutCleared);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user