Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8a1c2ede authored by Jeff Pu's avatar Jeff Pu Committed by Android (Google) Code Review
Browse files

Merge "Fingerprint virtual HAL checkin (part 2)"

parents 83530e56 343ca94b
Loading
Loading
Loading
Loading
+211 −42
Original line number Diff line number Diff line
@@ -56,43 +56,58 @@ void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb,
        return;
    }

    if (FingerprintHalProperties::operation_enroll_fails().value_or(false)) {
        LOG(ERROR) << "Fail: operation_enroll_fails";
        cb->onError(Error::VENDOR, 0 /* vendorError */);
    // Force error-out
    auto err = FingerprintHalProperties::operation_enroll_error().value_or(0);
    if (err != 0) {
        LOG(ERROR) << "Fail: operation_enroll_error";
        auto ec = convertError(err);
        cb->onError(ec.first, ec.second);
        return;
    }

    // format is "<id>:<progress_ms>,<progress_ms>,...:<result>
    // Format is "<id>:<progress_ms-[acquiredInfo..]>,...:<result>
    auto nextEnroll = FingerprintHalProperties::next_enrollment().value_or("");
    auto parts = Util::split(nextEnroll, ":");
    if (parts.size() != 3) {
        LOG(ERROR) << "Fail: invalid next_enrollment";
        LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll;
        cb->onError(Error::VENDOR, 0 /* vendorError */);
        return;
    }
    auto enrollmentId = std::stoi(parts[0]);
    auto progress = Util::split(parts[1], ",");
    for (size_t i = 0; i < progress.size(); i++) {
        auto left = progress.size() - i - 1;
        SLEEP_MS(std::stoi(progress[i]));
    auto progress = 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];
        auto acquired = progress[i + 1];
        auto N = acquired.size();

        for (int j = 0; j < N; j++) {
            SLEEP_MS(duration / N);

            if (shouldCancel(cancel)) {
                LOG(ERROR) << "Fail: cancel";
                cb->onError(Error::CANCELED, 0 /* vendorCode */);
                return;
            }
            auto ac = convertAcquiredInfo(acquired[j]);
            cb->onAcquired(ac.first, ac.second);
        }

        cb->onAcquired(AcquiredInfo::GOOD, 0 /* vendorCode */);
        if (left == 0 && !IS_TRUE(parts[2])) {  // end and failed
            LOG(ERROR) << "Fail: requested by caller: " << nextEnroll;
            FingerprintHalProperties::next_enrollment({});
            cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
        } else {  // progress and update props if last time
            LOG(INFO) << "onEnroll: " << enrollmentId << " left: " << left;
            if (left == 0) {
                auto enrollments = FingerprintHalProperties::enrollments();
                enrollments.emplace_back(enrollmentId);
                FingerprintHalProperties::enrollments(enrollments);
                FingerprintHalProperties::next_enrollment({});
                // change authenticatorId after new enrollment
                auto id = FingerprintHalProperties::authenticator_id().value_or(0);
                auto newId = id + 1;
                FingerprintHalProperties::authenticator_id(newId);
                LOG(INFO) << "Enrolled: " << enrollmentId;
            }
            cb->onEnrollmentProgress(enrollmentId, left);
@@ -104,12 +119,31 @@ void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* op
                                             const std::future<void>& cancel) {
    BEGIN_OP(FingerprintHalProperties::operation_authenticate_latency().value_or(DEFAULT_LATENCY));

    auto now = Util::getSystemNanoTime();
    int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(0);
    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);
    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;
    }

    int i = 0;
    do {
        if (FingerprintHalProperties::operation_authenticate_fails().value_or(false)) {
            LOG(ERROR) << "Fail: operation_authenticate_fails";
            cb->onError(Error::VENDOR, 0 /* vendorError */);
            cb->onAuthenticationFailed();
            return;
        }

        auto err = FingerprintHalProperties::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;
        }

@@ -126,20 +160,25 @@ void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* op
            return;
        }

        if (i < N) {
            auto ac = convertAcquiredInfo(acquiredInfos[i]);
            cb->onAcquired(ac.first, ac.second);
            i++;
        }

        SLEEP_MS(duration / N);
    } while (!Util::hasElapsed(now, duration));

    auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
    auto enrolls = FingerprintHalProperties::enrollments();
    auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
    if (id > 0 && isEnrolled) {
        cb->onAuthenticationSucceeded(id, {} /* hat */);
        return;
        }

        SLEEP_MS(100);
    } while (!Util::hasElapsed(now, duration));

    LOG(ERROR) << "Fail: not enrolled";
    } else {
        LOG(ERROR) << "Fail: fingerprint not enrolled";
        cb->onAuthenticationFailed();
    cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
    }
}

void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
@@ -147,9 +186,26 @@ void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
    BEGIN_OP(FingerprintHalProperties::operation_detect_interaction_latency().value_or(
            DEFAULT_LATENCY));

    if (FingerprintHalProperties::operation_detect_interaction_fails().value_or(false)) {
        LOG(ERROR) << "Fail: operation_detect_interaction_fails";
        cb->onError(Error::VENDOR, 0 /* vendorError */);
    int64_t duration =
            FingerprintHalProperties::operation_detect_interaction_duration().value_or(10);
    auto acquired = FingerprintHalProperties::operation_detect_interaction_acquired().value_or("1");
    auto acquiredInfos = parseIntSequence(acquired);
    int N = acquiredInfos.size();
    int64_t now = Util::getSystemNanoTime();

    if (N == 0) {
        LOG(ERROR) << "Fail to parse detect interaction acquired info: " + acquired;
        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
        return;
    }

    int i = 0;
    do {
        auto err = FingerprintHalProperties::operation_detect_interaction_error().value_or(0);
        if (err != 0) {
            LOG(ERROR) << "Fail: operation_detect_interaction_error";
            auto ec = convertError(err);
            cb->onError(ec.first, ec.second);
            return;
        }

@@ -159,6 +215,14 @@ void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
            return;
        }

        if (i < N) {
            auto ac = convertAcquiredInfo(acquiredInfos[i]);
            cb->onAcquired(ac.first, ac.second);
            i++;
        }
        SLEEP_MS(duration / N);
    } while (!Util::hasElapsed(now, duration));

    auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
    auto enrolls = FingerprintHalProperties::enrollments();
    auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
@@ -211,24 +275,37 @@ void FakeFingerprintEngine::removeEnrollmentsImpl(ISessionCallback* cb,

void FakeFingerprintEngine::getAuthenticatorIdImpl(ISessionCallback* cb) {
    BEGIN_OP(0);
    int64_t authenticatorId = FingerprintHalProperties::authenticator_id().value_or(0);
    if (FingerprintHalProperties::enrollments().size() > 0 && authenticatorId == 0) {
        authenticatorId = 99999999;  // default authenticatorId, TODO(b/230515082)
    int64_t authenticatorId;
    if (FingerprintHalProperties::enrollments().size() == 0) {
        authenticatorId = 0;
    } else {
        authenticatorId = FingerprintHalProperties::authenticator_id().value_or(0);
        if (authenticatorId == 0) authenticatorId = 1;
    }
    cb->onAuthenticatorIdRetrieved(authenticatorId);
}

void FakeFingerprintEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
    BEGIN_OP(0);
    int64_t newId;
    if (FingerprintHalProperties::enrollments().size() == 0) {
        newId = 0;
    } else {
        auto id = FingerprintHalProperties::authenticator_id().value_or(0);
    auto newId = id + 1;
        newId = id + 1;
    }
    FingerprintHalProperties::authenticator_id(newId);
    cb->onAuthenticatorIdInvalidated(newId);
}

void FakeFingerprintEngine::resetLockoutImpl(ISessionCallback* cb,
                                             const keymaster::HardwareAuthToken& /*hat*/) {
                                             const keymaster::HardwareAuthToken& hat) {
    BEGIN_OP(0);
    if (hat.mac.empty()) {
        LOG(ERROR) << "Fail: hat in resetLockout()";
        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
        return;
    }
    FingerprintHalProperties::lockout(false);
    cb->onLockoutCleared();
}
@@ -286,4 +363,96 @@ SensorLocation FakeFingerprintEngine::defaultSensorLocation() {
    return {0 /* displayId (not used) */, 0 /* sensorLocationX */, 0 /* sensorLocationY */,
            0 /* sensorRadius */, "" /* display */};
}

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;
}

std::vector<std::vector<int32_t>> FakeFingerprintEngine::parseEnrollmentCapture(
        const std::string& str) {
    std::vector<int32_t> defaultAcquiredInfo = {(int32_t)AcquiredInfo::GOOD};
    std::vector<std::vector<int32_t>> res;
    int i = 0, N = str.length();
    std::size_t found = 0;
    bool aborted = true;

    while (found != std::string::npos) {
        std::string durationStr, acquiredStr;
        found = str.find_first_of("-,", i);
        if (found == std::string::npos) {
            if (N - i < 1) break;
            durationStr = str.substr(i, N - i);
        } else {
            durationStr = str.substr(i, found - i);
            if (str[found] == '-') {
                found = str.find_first_of('[', found + 1);
                if (found == std::string::npos) break;
                i = found + 1;
                found = str.find_first_of(']', found + 1);
                if (found == std::string::npos) break;
                acquiredStr = str.substr(i, found - i);
                found = str.find_first_of(',', found + 1);
            }
        }
        std::vector<int32_t> duration{0};
        if (!ParseInt(durationStr, &duration[0])) break;
        res.push_back(duration);
        if (!acquiredStr.empty()) {
            std::vector<int32_t> acquiredInfo = parseIntSequence(acquiredStr);
            if (acquiredInfo.empty()) break;
            res.push_back(acquiredInfo);
        } else
            res.push_back(defaultAcquiredInfo);

        i = found + 1;
        if (found == std::string::npos || found == N - 1) aborted = false;
    }

    if (aborted) {
        LOG(ERROR) << "Failed to parse enrollment captures:" + str;
        res.clear();
    }

    return res;
}

std::pair<AcquiredInfo, int32_t> FakeFingerprintEngine::convertAcquiredInfo(int32_t code) {
    std::pair<AcquiredInfo, int32_t> res;
    if (code > FINGERPRINT_ACQUIRED_VENDOR_BASE) {
        res.first = AcquiredInfo::VENDOR;
        res.second = code - FINGERPRINT_ACQUIRED_VENDOR_BASE;
    } else {
        res.first = (AcquiredInfo)code;
        res.second = 0;
    }
    return res;
}

std::pair<Error, int32_t> FakeFingerprintEngine::convertError(int32_t code) {
    std::pair<Error, int32_t> res;
    if (code > FINGERPRINT_ERROR_VENDOR_BASE) {
        res.first = Error::VENDOR;
        res.second = code - FINGERPRINT_ERROR_VENDOR_BASE;
    } else {
        res.first = (Error)code;
        res.second = 0;
    }
    return res;
}

}  // namespace aidl::android::hardware::biometrics::fingerprint
+16 −4
Original line number Diff line number Diff line
@@ -65,8 +65,18 @@ ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* out) {
            {SW_COMPONENT_ID, "" /* hardwareVersion */, "" /* firmwareVersion */,
             "" /* serialNumber */, SW_VERSION}};

    common::CommonProps commonProps = {SENSOR_ID, SENSOR_STRENGTH, MAX_ENROLLMENTS_PER_USER,
                                       componentInfo};
    auto sensorId = FingerprintHalProperties::sensor_id().value_or(SENSOR_ID);
    auto sensorStrength =
            FingerprintHalProperties::sensor_strength().value_or((int)SENSOR_STRENGTH);
    auto maxEnrollments =
            FingerprintHalProperties::max_enrollments().value_or(MAX_ENROLLMENTS_PER_USER);
    auto navigationGuesture = FingerprintHalProperties::navigation_guesture().value_or(false);
    auto detectInteraction = FingerprintHalProperties::detect_interaction().value_or(false);
    auto displayTouch = FingerprintHalProperties::display_touch().value_or(true);
    auto controlIllumination = FingerprintHalProperties::control_illumination().value_or(false);

    common::CommonProps commonProps = {sensorId, (common::SensorStrength)sensorStrength,
                                       maxEnrollments, componentInfo};

    SensorLocation sensorLocation = mEngine->getSensorLocation();

@@ -75,8 +85,10 @@ ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* out) {
    *out = {{commonProps,
             mSensorType,
             {sensorLocation},
             SUPPORTS_NAVIGATION_GESTURES,
             false /* supportsDetectInteraction */}};
             navigationGuesture,
             detectInteraction,
             displayTouch,
             controlIllumination}};
    return ndk::ScopedAStatus::ok();
}

+47 −2
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ $ adb shell cmd fingerprint sync
      $ adb shell getprop persist.vendor.fingerprint.virtual.enrollments
      ```

### Authenticate
## Authenticate

To authenticate successfully set the enrolled id that should succeed. Unset it
or change the value to make authenticate operations fail:
@@ -74,7 +74,52 @@ or change the value to make authenticate operations fail:
$ adb shell setprop vendor.fingerprint.virtual.enrollment_hit 1
````

### View HAL State
## Acquired Info Insertion

Fingerprint image acquisition states at HAL are reported to framework via onAcquired() callback. The valid acquired state info for AIDL HAL include

{UNKNOWN(0), GOOD(1), PARTIAL(2), INSUFFICIENT(3), SENSOR_DIRTY(4), TOO_SLOW(5), TOO_FAST(6), VENDOR(7), START(8), TOO_DARK(9), TOO_BRIGHT(10), IMMOBILE(11), RETRYING_CAPTURE(12)}

Refer to [AcquiredInfo.aidl](../android/hardware/biometrics/fingerprint/AcquiredInfo.aidl) for details


The states can be specified in sequence for the HAL operations involving fingerprint image captures, namely authenticate, enrollment and detectInteraction

```shell
$ adb shell setprop vendor.fingerprint.virtual.operation_authenticate_acquired 6,9,1
$ adb shell setprop vendor.fingerprint.virtual.operation_detect_interaction_acquired 6,1
$ adb shell setprop vendor.fingerprint.virtual.next_enrollment 2:1000-[5,1],500:true

#next_enrollment format example:
.---------------------- enrollment id (2)
|   .------------------ the image capture 1 duration (1000ms)
|   |   .--------------   acquired info first (TOO_SLOW)
|   |   | .------------   acquired info second (GOOD)
|   |   | |   .-------- the image capture 2 duration (500ms)
|   |   | |   |   .---- enrollment end status (success)
|   |   | |   |   |
|   |   | |   |   |
|   |   | |   |   |
2:1000-[5,1],500:true
```
For vendor specific acquired info, acquiredInfo = 1000 + vendorAcquiredInfo

## Error Insertion
The valid error codes for AIDL HAL include

{UNKNOWN(0), HW_UNAVAILABLE(1), UNABLE_TO_PROCESS(2), TIMEOUT(3), NO_SPACE(4), CANCELED(5), UNABLE_TO_REMOVE(6), VENDOR(7), BAD_CALIBRATION(8)}

Refer to [Error.aidl](../android/hardware/biometrics/fingerprint/Error.aidl) for details


There are many HAL operations which can result in errors, refer to [here](fingerprint.sysprop) file for details.

```shell
$ adb shell setprop vendor.fingerprint.virtual.operation_authenticate_error 8
```
For vendor specific error, errorCode = 1000 + vendorErrorCode

## View HAL State

To view all the properties of the HAL (see `fingerprint.sysprop` file for the API):

+70 −6
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ props {
    api_name: "authenticator_id"
    type: Long
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.authenticator_id"
    prop_name: "persist.vendor.fingerprint.virtual.authenticator_id"
  }
  prop {
    api_name: "challenge"
@@ -13,6 +13,21 @@ props {
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.challenge"
  }
  prop {
    api_name: "control_illumination"
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.udfps.control_illumination"
  }
  prop {
    api_name: "detect_interaction"
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.detect_interaction"
  }
  prop {
    api_name: "display_touch"
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.udfps.display_touch"
  }
  prop {
    api_name: "enrollment_hit"
    type: Integer
@@ -28,7 +43,18 @@ props {
  prop {
    api_name: "lockout"
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.lockout"
    prop_name: "persist.vendor.fingerprint.virtual.lockout"
  }
  prop {
    api_name: "max_enrollments"
    type: Integer
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.max_enrollments"
  }
  prop {
    api_name: "navigation_guesture"
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture"
  }
  prop {
    api_name: "next_enrollment"
@@ -36,12 +62,24 @@ props {
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.next_enrollment"
  }
  prop {
    api_name: "operation_authenticate_acquired"
    type: String
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_authenticate_acquired"
  }
  prop {
    api_name: "operation_authenticate_duration"
    type: Integer
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration"
  }
  prop {
    api_name: "operation_authenticate_error"
    type: Integer
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_authenticate_error"
  }
  prop {
    api_name: "operation_authenticate_fails"
    access: ReadWrite
@@ -54,9 +92,22 @@ props {
    prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency"
  }
  prop {
    api_name: "operation_detect_interaction_fails"
    api_name: "operation_detect_interaction_acquired"
    type: String
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_fails"
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_acquired"
  }
  prop {
    api_name: "operation_detect_interaction_duration"
    type: Integer
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_duration"
  }
  prop {
    api_name: "operation_detect_interaction_error"
    type: Integer
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error"
  }
  prop {
    api_name: "operation_detect_interaction_latency"
@@ -65,9 +116,10 @@ props {
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency"
  }
  prop {
    api_name: "operation_enroll_fails"
    api_name: "operation_enroll_error"
    type: Integer
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_enroll_fails"
    prop_name: "vendor.fingerprint.virtual.operation_enroll_error"
  }
  prop {
    api_name: "operation_enroll_latency"
@@ -75,12 +127,24 @@ props {
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_enroll_latency"
  }
  prop {
    api_name: "sensor_id"
    type: Integer
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.sensor_id"
  }
  prop {
    api_name: "sensor_location"
    type: String
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.sensor_location"
  }
  prop {
    api_name: "sensor_strength"
    type: Integer
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.sensor_strength"
  }
  prop {
    api_name: "type"
    type: String
+125 −12
Original line number Diff line number Diff line
@@ -32,8 +32,12 @@ prop {
    api_name: "enrollment_hit"
}

# the next enrollment in the format: "<id>:<delay>,<delay>,...:<result>"
# for example: "2:0:true"
# the next enrollment in the format of:
# "<id>:<delay>,<delay>,...:<result>"
# <delay> = <duration-[acquiredInfos]>
# [acquiredInfos] = [acquiredInfo1, acquiredInfo2, ...]
# (refer to README.md file for acquiredInfo values)
# e.g. "2:100,20:true", "2:100-[5,1],20:true"
# this property is reset after enroll completes
prop {
    prop_name: "vendor.fingerprint.virtual.next_enrollment"
@@ -45,7 +49,7 @@ prop {

# value for getAuthenticatorId or 0
prop {
    prop_name: "vendor.fingerprint.virtual.authenticator_id"
    prop_name: "persist.vendor.fingerprint.virtual.authenticator_id"
    type: Long
    scope: Public
    access: ReadWrite
@@ -63,7 +67,7 @@ prop {

# if locked out
prop {
    prop_name: "vendor.fingerprint.virtual.lockout"
    prop_name: "persist.vendor.fingerprint.virtual.lockout"
    type: Boolean
    scope: Public
    access: ReadWrite
@@ -79,22 +83,26 @@ prop {
    api_name: "operation_authenticate_fails"
}

# force all detectInteraction operations to fail
# force all detectInteraction operations to error out
# error consists of errorCode and vendorErrorCode
# valid errorCodes are listed in README.md file
# vendorErrorCode = (error>1000) ? error-1000 : 0
# e.g. error(1002) --> errorCode(7) and vendorErrorCode(2)
prop {
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_fails"
    type: Boolean
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "operation_detect_interaction_fails"
    api_name: "operation_detect_interaction_error"
}

# force all enroll operations to fail
# force all enroll operations to result in error
prop {
    prop_name: "vendor.fingerprint.virtual.operation_enroll_fails"
    type: Boolean
    prop_name: "vendor.fingerprint.virtual.operation_enroll_error"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "operation_enroll_fails"
    api_name: "operation_enroll_error"
}

# add a latency to authentication operations
@@ -134,6 +142,15 @@ prop {
    api_name: "operation_authenticate_duration"
}

# insert error for authenticate operations
prop {
    prop_name: "vendor.fingerprint.virtual.operation_authenticate_error"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "operation_authenticate_error"
}

# sensor location
#    <x>:<y>:<radius> in pixel
prop {
@@ -143,3 +160,99 @@ prop {
    access: ReadWrite
    api_name: "sensor_location"
}

# acquired info during authentication in format of sequence
prop {
    prop_name: "vendor.fingerprint.virtual.operation_authenticate_acquired"
    type: String
    scope: Public
    access: ReadWrite
    api_name: "operation_authenticate_acquired"
}

# millisecond duration for detect interaction operations
# (waits for changes to enrollment_hit)
prop {
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_duration"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "operation_detect_interaction_duration"
}

# acquired info during detect interaction operation in format of sequence
# e.g. 5,6,1  (TOO_SLOW, TOO_FAST, GOOD)
# onAcquired() callback will be invoked in sequence
# vendorAcquiredCode = (acquired>1000) ? acquired-1000 : 0
prop {
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_acquired"
    type: String
    scope: Public
    access: ReadWrite
    api_name: "operation_detect_interaction_acquired"
}

# sensor id (default: 5)
prop {
    prop_name: "persist.vendor.fingerprint.virtual.sensor_id"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "sensor_id"
}

# sensor strength (default: 2)
# [0=CONVENECE, 1=WEAK, 2=STRONG]
prop {
    prop_name: "persist.vendor.fingerprint.virtual.sensor_strength"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "sensor_strength"
}

# max enrollments per user (default: 5)
#
prop {
    prop_name: "persist.vendor.fingerprint.virtual.max_enrollments"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "max_enrollments"
}

# whether support navigation guestures (default: false)
prop {
    prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture"
    type: Boolean
    scope: Public
    access: ReadWrite
    api_name: "navigation_guesture"
}

# whether support detect interaction (default: false)
prop {
    prop_name: "persist.vendor.fingerprint.virtual.detect_interaction"
    type: Boolean
    scope: Public
    access: ReadWrite
    api_name: "detect_interaction"
}

# whether support display touch by hal (default: true)
prop {
    prop_name: "persist.vendor.fingerprint.virtual.udfps.display_touch"
    type: Boolean
    scope: Public
    access: ReadWrite
    api_name: "display_touch"
}

# whether support illumination control  by hal (default: false)
prop {
    prop_name: "persist.vendor.fingerprint.virtual.udfps.control_illumination"
    type: Boolean
    scope: Public
    access: ReadWrite
    api_name: "control_illumination"
}
Loading