├── src ├── assets │ ├── add.svg │ ├── menu.svg │ ├── back.svg │ ├── info.svg │ ├── edit.svg │ ├── delete.svg │ ├── assets.qrc │ ├── applogo.svg │ ├── sc-apps-fingerboard.svg │ └── fingerprint.svg ├── registertypes.h ├── qml │ ├── PointingHandOverlay.qml │ ├── qml.qrc │ ├── ErrorDialog.qml │ ├── FingerDelegate.qml │ ├── AboutDialog.qml │ ├── DeleteDialog.qml │ ├── LogPanel.qml │ ├── VerifyView.qml │ ├── EnrollView.qml │ ├── ListingView.qml │ ├── main.qml │ └── CircularProgressBar.qml ├── utils │ ├── deviceinfo.h │ ├── deviceinfo.cpp │ ├── logger.h │ ├── finger.h │ ├── logger.cpp │ ├── finger.cpp │ ├── appstate.cpp │ └── appstate.h ├── CMakeLists.txt ├── main.cpp ├── fprintd-dbus-interface-xml │ ├── fprintdmanager.xml │ └── fprintddevice.xml ├── interfaces │ ├── fingerboard_cpp_interface.h │ └── fingerboard_cpp_interface.cpp └── registertypes.cpp ├── fingerboard.desktop ├── logo.svg ├── .github └── FUNDING.yml ├── LICENSE ├── cmake └── cpack.cmake ├── CMakeLists.txt ├── .gitignore ├── README.rst └── .clang-format /src/assets/add.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/menu.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/back.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/info.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/registertypes.h: -------------------------------------------------------------------------------- 1 | #ifndef REGISTERTYPES_H 2 | #define REGISTERTYPES_H 3 | 4 | #include 5 | 6 | #include "interfaces/fingerboard_cpp_interface.h" 7 | #include "utils/appstate.h" 8 | #include "utils/finger.h" 9 | 10 | void registerQmlTypes(QObject* parent = nullptr); 11 | 12 | #endif // REGISTERTYPES_H 13 | -------------------------------------------------------------------------------- /fingerboard.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Fingerboard 3 | Comment=Fingerprint GUI 4 | TryExec=fingerboard 5 | Exec=fingerboard %U 6 | Terminal=false 7 | Type=Application 8 | Categories=Qt;System;Utility;Settings; 9 | StartupNotify=true 10 | Icon=fingerboard 11 | # Generic name with translations 12 | GenericName=Fingerprint GUI 13 | -------------------------------------------------------------------------------- /src/assets/delete.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/assets.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | applogo.svg 4 | fingerprint.svg 5 | add.svg 6 | edit.svg 7 | delete.svg 8 | back.svg 9 | info.svg 10 | menu.svg 11 | sc-apps-fingerboard.svg 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/qml/PointingHandOverlay.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | MouseArea { 4 | cursorShape: Qt.PointingHandCursor 5 | propagateComposedEvents: true 6 | 7 | onClicked: mouse.accepted = false; 8 | onPressed: mouse.accepted = false; 9 | onReleased: mouse.accepted = false; 10 | onDoubleClicked: mouse.accepted = false; 11 | onPositionChanged: mouse.accepted = false; 12 | onPressAndHold: mouse.accepted = false; 13 | } 14 | -------------------------------------------------------------------------------- /src/utils/deviceinfo.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_DEVICEINFO_H 2 | #define UTILS_DEVICEINFO_H 3 | 4 | #include 5 | 6 | class DeviceInfo : public QObject { 7 | Q_OBJECT 8 | 9 | public: 10 | DeviceInfo(QString name, QString scanType, int numEnrollStages, 11 | QObject *parent = nullptr); 12 | 13 | public slots: 14 | QString name(); 15 | QString scanType(); 16 | int numEnrollStages(); 17 | 18 | private: 19 | QString _name; 20 | }; 21 | 22 | #endif // UTILS_DEVICEINFO_H 23 | -------------------------------------------------------------------------------- /src/utils/deviceinfo.cpp: -------------------------------------------------------------------------------- 1 | #include "deviceinfo.h" 2 | 3 | DeviceInfo::DeviceInfo(QString name, QString scanType, int numEnrollStages, 4 | QObject *parent) 5 | : QObject(parent) { 6 | this->_name = name; 7 | this->_scanType = scanType; 8 | this->_numEnrollStages = numEnrollStages; 9 | } 10 | 11 | QString DeviceInfo::name() { return _name; } 12 | 13 | QString DeviceInfo::scanType() { return _scanType; } 14 | 15 | int DeviceInfo::numEnrollStages() { return _numEnrollStages; } 16 | -------------------------------------------------------------------------------- /src/qml/qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | LogPanel.qml 5 | ListingView.qml 6 | FingerDelegate.qml 7 | PointingHandOverlay.qml 8 | EnrollView.qml 9 | DeleteDialog.qml 10 | CircularProgressBar.qml 11 | VerifyView.qml 12 | ErrorDialog.qml 13 | AboutDialog.qml 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/utils/logger.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_LOGGER 2 | #define UTILS_LOGGER 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class Logger : public QObject { 10 | Q_OBJECT 11 | 12 | public: 13 | enum Level { ERROR = 0, WARNING, INFO, DEBUG, VERBOSE }; 14 | Q_ENUM(Level) 15 | 16 | Logger(QObject *parent = nullptr); 17 | ~Logger(); 18 | 19 | void log(Logger::Level level, QString msg); 20 | QString path(); 21 | 22 | signals: 23 | void writeLog(Logger::Level logLevel, QString msg); 24 | 25 | private: 26 | QFile *file; 27 | }; 28 | 29 | #endif // UTILS_LOGGER 30 | -------------------------------------------------------------------------------- /src/assets/applogo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/sc-apps-fingerboard.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [anupam-git]# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 2 | 3 | set( 4 | FINGERBOARD_SRCS 5 | 6 | main.cpp 7 | registertypes.cpp 8 | 9 | interfaces/fingerboard_cpp_interface.cpp 10 | 11 | utils/logger.cpp 12 | utils/appstate.cpp 13 | utils/finger.cpp 14 | ) 15 | 16 | set( 17 | FINGERBOARD_QML 18 | 19 | qml/qml.qrc 20 | assets/assets.qrc 21 | ) 22 | 23 | qt5_add_dbus_interfaces( 24 | FPRINTD_DBUS_INTERFACES 25 | 26 | fprintd-dbus-interface-xml/fprintddevice.xml 27 | fprintd-dbus-interface-xml/fprintdmanager.xml 28 | ) 29 | 30 | add_executable( 31 | ${PROJECT_NAME} 32 | 33 | ${FINGERBOARD_QML} 34 | ${FINGERBOARD_SRCS} 35 | 36 | ${FPRINTD_DBUS_INTERFACES} 37 | ) 38 | target_link_libraries( 39 | ${PROJECT_NAME} 40 | PRIVATE 41 | 42 | Qt5::Core 43 | Qt5::Qml 44 | Qt5::Quick 45 | Qt5::DBus 46 | Qt5::QuickControls2 47 | ) 48 | install(TARGETS ${PROJECT_NAME} DESTINATION bin) 49 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../fingerboard_version.h" 7 | #include "registertypes.h" 8 | 9 | int main(int argc, char *argv[]) { 10 | QQuickStyle::setStyle("Material"); 11 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 12 | 13 | QGuiApplication app(argc, argv); 14 | QQmlApplicationEngine engine; 15 | const QUrl url(QStringLiteral("qrc:/main.qml")); 16 | 17 | app.setApplicationName("fingerboard"); 18 | app.setApplicationDisplayName("Fingerboard"); 19 | app.setApplicationVersion(FINGERBOARD_VERSION_STRING); 20 | app.setWindowIcon(QIcon(":/sc-apps-fingerboard.svg")); 21 | 22 | registerQmlTypes(&app); 23 | 24 | QObject::connect( 25 | &engine, &QQmlApplicationEngine::objectCreated, &app, 26 | [url](QObject *obj, const QUrl &objUrl) { 27 | if (!obj && url == objUrl) QCoreApplication::exit(-1); 28 | }, 29 | Qt::QueuedConnection); 30 | engine.load(url); 31 | 32 | return app.exec(); 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Anupam Basak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /cmake/cpack.cmake: -------------------------------------------------------------------------------- 1 | set(CPACK_GENERATOR "DEB") 2 | 3 | set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) 4 | set(CPACK_DEBIAN_PACKAGE_DEPENDS 5 | "fprintd" 6 | "qml-module-qtquick-controls" 7 | "qml-module-qtquick-controls2" 8 | "qml-module-qtquick-layouts" 9 | "qml-module-qtgraphicaleffects" 10 | ) 11 | 12 | set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Anupam Basak") 13 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A fprintd based GUI for listing, enrolling, deleting and verifying fingerprints for Linux") 14 | set(CPACK_PACKAGE_VENDOR "Anupam Basak") 15 | set(CPACK_PACKAGE_CONTACT "Anupam Basak ") 16 | 17 | set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.rst") 18 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") 19 | 20 | set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) 21 | set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) 22 | set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) 23 | 24 | set(CPACK_PACKAGE_INSTALL_DIRECTORY "CMake ${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}") 25 | set(CPACK_SOURCE_STRIP_FILES "") 26 | 27 | include(CPack) 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/qml/ErrorDialog.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.12 5 | 6 | Dialog { 7 | property alias errorString: errorLabel.text 8 | 9 | visible: true 10 | modal: true 11 | implicitWidth: 400 12 | z: 10 13 | 14 | font.pixelSize: 10 15 | 16 | x: (parent.width - width) / 2 17 | y: (parent.height - height) / 2 18 | 19 | footer: DialogButtonBox { 20 | Button { 21 | flat: true 22 | text: "OK" 23 | DialogButtonBox.buttonRole: DialogButtonBox.RejectRole 24 | font.pixelSize: 10 25 | font.bold: true 26 | hoverEnabled: true 27 | 28 | PointingHandOverlay { 29 | anchors.fill: parent 30 | } 31 | } 32 | } 33 | 34 | ColumnLayout { 35 | Label { 36 | text: "ERROR" 37 | font.pixelSize: 15 38 | font.bold: true 39 | topPadding: 16 40 | bottomPadding: 16 41 | leftPadding: 12 42 | } 43 | 44 | Label { 45 | id: errorLabel 46 | 47 | font.pixelSize: 12 48 | leftPadding: 12 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | set(FINGERBOARD_VERSION 0.2.2) 4 | 5 | project(fingerboard VERSION ${FINGERBOARD_VERSION}) 6 | 7 | set(CMAKE_AUTOMOC ON) 8 | set(CMAKE_AUTORCC ON) 9 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 10 | 11 | find_package(ECM 1.7.0 REQUIRED NO_MODULE) 12 | set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${ECM_MODULE_PATH}) 13 | 14 | find_package( 15 | Qt5 16 | REQUIRED 17 | NO_MODULE 18 | 19 | COMPONENTS 20 | Core 21 | Qml 22 | Quick 23 | DBus 24 | QuickControls2 25 | ) 26 | 27 | include(ECMSetupVersion) 28 | include(ECMInstallIcons) 29 | include(ECMAddAppIcon) 30 | include(KDEInstallDirs) 31 | include(KDECMakeSettings) 32 | include(FeatureSummary) 33 | 34 | set(CMAKE_CXX_STANDARD 17) 35 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 36 | 37 | ecm_setup_version( 38 | ${FINGERBOARD_VERSION} 39 | 40 | VARIABLE_PREFIX FINGERBOARD 41 | VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/fingerboard_version.h" 42 | ) 43 | ecm_install_icons( 44 | ICONS src/assets/sc-apps-fingerboard.svg 45 | DESTINATION share/icons 46 | ) 47 | install(FILES fingerboard.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) 48 | 49 | 50 | add_subdirectory(src) 51 | 52 | feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) 53 | 54 | include(cmake/cpack.cmake) 55 | -------------------------------------------------------------------------------- /src/utils/finger.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_FINGER_H 2 | #define UTILS_FINGER_H 3 | 4 | #include 5 | #include 6 | 7 | class Finger : public QObject { 8 | Q_OBJECT 9 | 10 | public: 11 | enum Fingerprint { 12 | LEFT_THUMB, 13 | LEFT_INDEX, 14 | LEFT_MIDDLE, 15 | LEFT_RING, 16 | LEFT_LITTLE, 17 | RIGHT_THUMB, 18 | RIGHT_INDEX, 19 | RIGHT_MIDDLE, 20 | RIGHT_RING, 21 | RIGHT_LITTLE 22 | }; 23 | Q_ENUM(Fingerprint) 24 | 25 | Finger(QObject *parent = nullptr); 26 | 27 | public slots: 28 | QString name(Fingerprint finger); 29 | Fingerprint fromName(QString rawFingerName); 30 | QString rawFingerName(int fingerprint); 31 | 32 | private: 33 | QMap rawFingersMap = { 34 | {"left-thumb", Fingerprint::LEFT_THUMB}, 35 | {"left-index-finger", Fingerprint::LEFT_INDEX}, 36 | {"left-middle-finger", Fingerprint::LEFT_MIDDLE}, 37 | {"left-ring-finger", Fingerprint::LEFT_RING}, 38 | {"left-little-finger", Fingerprint::LEFT_LITTLE}, 39 | 40 | {"right-thumb", Fingerprint::RIGHT_THUMB}, 41 | {"right-index-finger", Fingerprint::RIGHT_INDEX}, 42 | {"right-middle-finger", Fingerprint::RIGHT_MIDDLE}, 43 | {"right-ring-finger", Fingerprint::RIGHT_RING}, 44 | {"right-little-finger", Fingerprint::RIGHT_LITTLE}, 45 | }; 46 | }; 47 | 48 | #endif // UTILS_FINGER_H 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Qt-es 35 | object_script.*.Release 36 | object_script.*.Debug 37 | *_plugin_import.cpp 38 | /.qmake.cache 39 | /.qmake.stash 40 | *.pro.user 41 | *.pro.user.* 42 | *.qbs.user 43 | *.qbs.user.* 44 | *.moc 45 | moc_*.cpp 46 | moc_*.h 47 | qrc_*.cpp 48 | ui_*.h 49 | *.qmlc 50 | *.jsc 51 | Makefile* 52 | *build-* 53 | 54 | # Qt unit tests 55 | target_wrapper.* 56 | 57 | # QtCreator 58 | *.autosave 59 | 60 | # QtCreator Qml 61 | *.qmlproject.user 62 | *.qmlproject.user.* 63 | 64 | # QtCreator CMake 65 | CMakeLists.txt.user* 66 | 67 | # Bazaar files 68 | .bzr 69 | 70 | # BUILD FILES 71 | pkg/ 72 | pkgbuild-fingerboard-*/ 73 | fingerboard-*.pkg.tar.xz 74 | fingerboard-*.deb 75 | appimage-builder-cache/ 76 | fingerboard*.AppImage 77 | 78 | # OTHERS 79 | build/ 80 | build-scripts/src 81 | *.kdev4 82 | *.directory 83 | *.*~ 84 | *.properties 85 | .*.kate-swp 86 | .swp.* 87 | *.DS_Store 88 | *.*~ 89 | ~*.* 90 | ~.* 91 | .vscode 92 | 93 | # Exceptions 94 | !build-scripts/ 95 | !build-scripts/build*.sh -------------------------------------------------------------------------------- /src/utils/logger.cpp: -------------------------------------------------------------------------------- 1 | #include "logger.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../fingerboard_version.h" 8 | 9 | Logger::Logger(QObject *parent) : QObject(parent) { 10 | file = new QFile( 11 | QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + 12 | "/fingerboard.log"); 13 | file->open(QIODevice::WriteOnly | QIODevice::Append); 14 | } 15 | 16 | void Logger::log(Logger::Level level, QString msg) { 17 | QString format = QString("%1 %2 : %3"); 18 | QString logLevel = ""; 19 | 20 | QString timestamp = 21 | QDateTime::currentDateTime().toString("dd/MMM/yyyy hh:mm:ss"); 22 | 23 | switch (level) { 24 | case Level::INFO: 25 | logLevel = "[INFO]"; 26 | break; 27 | 28 | case Level::DEBUG: 29 | logLevel = "[DEBUG]"; 30 | break; 31 | 32 | case Level::VERBOSE: 33 | logLevel = "[VERBOSE]"; 34 | break; 35 | 36 | case Level::WARNING: 37 | logLevel = "[WARNING]"; 38 | break; 39 | 40 | case Level::ERROR: 41 | logLevel = "[ERROR]"; 42 | break; 43 | } 44 | 45 | QString logMsg = format.arg(logLevel, 10).arg(timestamp, 22).arg(msg); 46 | QTextStream ts(file); 47 | 48 | ts << logMsg << '\n'; 49 | ts.flush(); 50 | 51 | emit writeLog(level, logMsg); 52 | } 53 | 54 | QString Logger::path() { return file->fileName(); } 55 | 56 | Logger::~Logger() { file->close(); } 57 | -------------------------------------------------------------------------------- /src/utils/finger.cpp: -------------------------------------------------------------------------------- 1 | #include "finger.h" 2 | 3 | Finger::Finger(QObject *parent) : QObject(parent) {} 4 | 5 | QString Finger::name(Finger::Fingerprint finger) { 6 | switch (finger) { 7 | case Finger::Fingerprint::LEFT_THUMB: 8 | return "Left Thumb"; 9 | case Finger::Fingerprint::LEFT_INDEX: 10 | return "Left Index Finger"; 11 | case Finger::Fingerprint::LEFT_MIDDLE: 12 | return "Left Middle Finger"; 13 | case Finger::Fingerprint::LEFT_RING: 14 | return "Left Ring Finger"; 15 | case Finger::Fingerprint::LEFT_LITTLE: 16 | return "Left Little Finger"; 17 | case Finger::Fingerprint::RIGHT_THUMB: 18 | return "Right Thumb"; 19 | case Finger::Fingerprint::RIGHT_INDEX: 20 | return "Right Index Finger"; 21 | case Finger::Fingerprint::RIGHT_MIDDLE: 22 | return "Right Middle Finger"; 23 | case Finger::Fingerprint::RIGHT_RING: 24 | return "Right Ring Finger"; 25 | case Finger::Fingerprint::RIGHT_LITTLE: 26 | return "Right Little Finger"; 27 | } 28 | 29 | return ""; 30 | } 31 | 32 | Finger::Fingerprint Finger::fromName(QString rawFingerName) { 33 | return rawFingersMap.value(rawFingerName); 34 | } 35 | 36 | QString Finger::rawFingerName(int fingerprint) { 37 | QMapIterator it(rawFingersMap); 38 | QString val = ""; 39 | 40 | while (it.hasNext()) { 41 | it.next(); 42 | 43 | if (fingerprint == it.value()) { 44 | val = it.key(); 45 | break; 46 | } 47 | } 48 | 49 | return val; 50 | } 51 | -------------------------------------------------------------------------------- /src/qml/FingerDelegate.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.12 5 | import QtGraphicalEffects 1.12 6 | 7 | Rectangle { 8 | RowLayout { 9 | anchors.verticalCenter: parent.verticalCenter 10 | width: parent.width 11 | 12 | Image { 13 | Layout.preferredWidth: 32 14 | Layout.preferredHeight: 32 15 | source: "qrc:/fingerprint.svg" 16 | Layout.margins: 10 17 | opacity: model.enrolled ? 1 : 0.5 18 | 19 | ColorOverlay { 20 | anchors.fill: parent 21 | source: parent 22 | color: model.enrolled ? "#7dc73f" : Material.color(Material.Grey) 23 | } 24 | } 25 | 26 | Label { 27 | Layout.fillWidth: true 28 | text: model.text 29 | font.pixelSize: 13 30 | color: Material.color(Material.Grey, Material.Shade600) 31 | opacity: model.enrolled ? 1 : 0.5 32 | } 33 | 34 | RoundButton { 35 | flat: true 36 | icon.source: model.enrolled ? "qrc:/edit.svg" : "qrc:/add.svg" 37 | icon.color: Material.color(Material.Grey) 38 | icon.width: 18 39 | icon.height: 18 40 | opacity: 0.5 41 | hoverEnabled: true 42 | 43 | onClicked: { 44 | selectedEnrollingFinger = model.finger; 45 | appstack.push(enrollView); 46 | } 47 | 48 | PointingHandOverlay { 49 | anchors.fill: parent 50 | } 51 | 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/fprintd-dbus-interface-xml/fprintdmanager.xml: -------------------------------------------------------------------------------- 1 | 5 | ]> 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | An array of object paths for devices. 16 | 17 | 18 | 19 | 20 | 21 | Enumerate all the fingerprint readers attached to the system. If there are 22 | no devices available, an empty array is returned. 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | The object path for the default device. 33 | 34 | 35 | 36 | 37 | 38 | Returns the default fingerprint reader device. 39 | 40 | 41 | 42 | 43 | if the device does not exist 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/assets/fingerprint.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/qml/AboutDialog.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.12 5 | 6 | Dialog { 7 | modal: true 8 | implicitWidth: 400 9 | font.pixelSize: 10 10 | z: 10 11 | 12 | 13 | x: (parent.width - width) / 2 14 | y: (parent.height - height) / 2 15 | 16 | footer: DialogButtonBox { 17 | Button { 18 | flat: true 19 | text: "OK" 20 | font.pixelSize: 10 21 | font.bold: true 22 | hoverEnabled: true 23 | DialogButtonBox.buttonRole: DialogButtonBox.RejectRole 24 | 25 | PointingHandOverlay { 26 | anchors.fill: parent 27 | } 28 | } 29 | } 30 | 31 | ColumnLayout { 32 | Label { 33 | text: "About" 34 | font.pixelSize: 24 35 | font.bold: true 36 | topPadding: 16 37 | bottomPadding: 16 38 | leftPadding: 12 39 | } 40 | 41 | Label { 42 | text: "A fprintd based fingerprint GUI for Linux" 43 | 44 | Layout.topMargin: 12 45 | font.pixelSize: 12 46 | leftPadding: 12 47 | } 48 | 49 | Label { 50 | text: "Author : Anupam Basak <GitHub>" 51 | onLinkActivated: Qt.openUrlExternally(link) 52 | 53 | Layout.topMargin: 32 54 | font.pixelSize: 12 55 | leftPadding: 12 56 | } 57 | Label { 58 | text: "Repository : https://github.com/anupam-git/fingerboard" 59 | onLinkActivated: Qt.openUrlExternally(link) 60 | 61 | enabled: true 62 | font.pixelSize: 12 63 | leftPadding: 12 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | Fingerboard 3 | =========== 4 | 5 | | A fprintd_ based fingerprint GUI for Linux 6 | 7 | Fingerboard is a fingerprint GUI to enroll, list, delete and verify fingerprints. 8 | Fingerboard is a GUI interface to fprint, and uses the D-Bus interfaces to communicate with fprint. 9 | 10 | Building 11 | -------- 12 | The project uses CMake build system. Follow the steps below to build, compile and install this project. 13 | 14 | Dependencies - Ubuntu 15 | ^^^^^^^^^^^^^^^^^^^^^ 16 | Note: Requires ``universe`` repository to be enabled for qt dependencies. 17 | 18 | .. code-block:: bash 19 | 20 | apt install \ 21 | gcc \ 22 | g++ \ 23 | make \ 24 | cmake \ 25 | extra-cmake-modules \ 26 | qtbase5-dev \ 27 | qtdeclarative5-dev \ 28 | qtquickcontrols2-5-dev \ 29 | libqt5svg5-dev \ 30 | qml-module-qtquick-controls \ 31 | qml-module-qtquick-controls2 \ 32 | qml-module-qtgraphicaleffects \ 33 | qml-module-qtquick-layouts 34 | 35 | Dependencies - Arch 36 | ^^^^^^^^^^^^^^^^^^^ 37 | 38 | .. code-block:: bash 39 | 40 | pacman -S \ 41 | gcc \ 42 | make \ 43 | cmake \ 44 | extra-cmake-modules \ 45 | qt5-base \ 46 | qt5-graphicaleffects \ 47 | qt5-svg \ 48 | qt5-quickcontrols \ 49 | qt5-quickcontrols2 50 | 51 | Build and compile 52 | ^^^^^^^^^^^^^^^^^ 53 | 54 | .. code-block:: bash 55 | 56 | # Make a build directory and cd into it 57 | mkdir build && cd build 58 | 59 | # Run cmake 60 | cmake .. -DCMAKE_INSTALL_PREFIX=/usr 61 | 62 | # Build the project 63 | make -j$(nproc) 64 | 65 | # [OPTIONAL] Install to system (requires root access) 66 | sudo make install 67 | 68 | Hacking 69 | ------- 70 | #. Any kind of contribution is appreciated 71 | #. Format the cpp sources and headers with ``clang-format -i -style=file `` 72 | #. Properly indent qml source 73 | 74 | .. References 75 | .. ---------- 76 | .. _fprintd: https://fprint.freedesktop.org/ 77 | .. _HACKING.rst: HACKING.rst 78 | -------------------------------------------------------------------------------- /src/qml/DeleteDialog.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.12 5 | 6 | import Fingerboard 1.0 7 | 8 | Dialog { 9 | modal: true 10 | implicitWidth: 400 11 | z: 10 12 | 13 | font.pixelSize: 10 14 | 15 | x: (parent.width - width) / 2 16 | y: (parent.height - height) / 2 17 | 18 | footer: DialogButtonBox { 19 | Button { 20 | flat: true 21 | text: "CANCEL" 22 | DialogButtonBox.buttonRole: DialogButtonBox.RejectRole 23 | font.pixelSize: 12 24 | font.bold: true 25 | hoverEnabled: true 26 | 27 | PointingHandOverlay { 28 | anchors.fill: parent 29 | } 30 | } 31 | Button { 32 | flat: true 33 | text: "DELETE" 34 | DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole 35 | font.pixelSize: 12 36 | font.bold: true 37 | hoverEnabled: true 38 | 39 | Material.accent: Material.Red 40 | 41 | PointingHandOverlay { 42 | anchors.fill: parent 43 | } 44 | } 45 | } 46 | 47 | onAccepted: { 48 | FingerboardCppInterface.deleteFp(); 49 | } 50 | 51 | Connections { 52 | target: AppState 53 | 54 | // function onDeleteCompleted() 55 | onDeleteCompleted: { 56 | FingerboardCppInterface.listFp(); 57 | } 58 | } 59 | 60 | ColumnLayout { 61 | Label { 62 | text: "Delete Fingerprints" 63 | font.pixelSize: 16 64 | font.bold: true 65 | topPadding: 16 66 | bottomPadding: 16 67 | leftPadding: 12 68 | } 69 | 70 | Label { 71 | text: "Are you sure you wish to delete ALL fingerprints ?" 72 | font.pixelSize: 14 73 | leftPadding: 12 74 | } 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/interfaces/fingerboard_cpp_interface.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERFACES_FINGERBOARD_CPP_INTERFACE_H 2 | #define INTERFACES_FINGERBOARD_CPP_INTERFACE_H 3 | 4 | #include 5 | #include 6 | 7 | #include "fprintddeviceinterface.h" 8 | #include "fprintdmanagerinterface.h" 9 | #include "utils/appstate.h" 10 | #include "utils/deviceinfo.h" 11 | #include "utils/finger.h" 12 | #include "utils/logger.h" 13 | 14 | #define FPRINTD_SERVICE "net.reactivated.Fprint" 15 | 16 | class FingerboardCppInterface : public QObject { 17 | Q_OBJECT 18 | 19 | Q_PROPERTY(QString deviceName READ getDeviceName NOTIFY deviceNameChanged) 20 | Q_PROPERTY(QString scanType READ getScanType NOTIFY scanTypeChanged) 21 | Q_PROPERTY( 22 | int numEnrollStages READ getNumEnrollStages NOTIFY numEnrollStagesChanged) 23 | 24 | public: 25 | FingerboardCppInterface(Finger *fingerObj, Logger *logger, AppState *appState, 26 | QObject *parent = nullptr); 27 | 28 | QString getDeviceName(); 29 | QString getScanType(); 30 | int getNumEnrollStages(); 31 | 32 | public slots: 33 | void init(); 34 | void deviceInfo(); 35 | void listFp(); 36 | void enrollFp(int finger); 37 | void verifyFp(QString finger = "any"); 38 | void deleteFp(); 39 | 40 | signals: 41 | void enrolledFingerprintsList(QList fingerprints); 42 | void log(int logLevel, QString msg); 43 | 44 | void deviceNameChanged(QString deviceName); 45 | void scanTypeChanged(QString scanType); 46 | void numEnrollStagesChanged(int numEnrollStages); 47 | 48 | private: 49 | net::reactivated::Fprint::Device *fprintdInterfaceDevice; 50 | net::reactivated::Fprint::Manager *fprintdInterfaceManager; 51 | QDBusInterface *fprintdDevicePropertiesInterface; 52 | QString username = qgetenv("USER"); 53 | QString defaultDevicePath; 54 | AppState *appState; 55 | Logger *logger; 56 | Finger *fingerObj; 57 | 58 | QString _deviceName; 59 | QString _scanType; 60 | int _numEnrollStages; 61 | 62 | bool claimFpDevice(); 63 | void releaseFpDevice(); 64 | 65 | private slots: 66 | void enrollStatusSlot(QString result, bool done); 67 | void verifyStatusSlot(QString result, bool done); 68 | }; 69 | 70 | #endif // INTERFACES_FINGERBOARD_CPP_INTERFACE_H 71 | -------------------------------------------------------------------------------- /src/registertypes.cpp: -------------------------------------------------------------------------------- 1 | #include "registertypes.h" 2 | 3 | #include 4 | 5 | #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 6 | 7 | Logger *logger = nullptr; 8 | Finger *fingerObj = nullptr; 9 | AppState *appState = nullptr; 10 | FingerboardCppInterface *fingerboardCppInterface = nullptr; 11 | 12 | static QObject *fingerObjSingletonProvider(QQmlEngine *e, QJSEngine *j) { 13 | Q_UNUSED(j) 14 | 15 | if (fingerObj == nullptr) { 16 | fingerObj = new Finger(e); 17 | } 18 | 19 | return fingerObj; 20 | } 21 | static QObject *appStateSingletonProvider(QQmlEngine *e, QJSEngine *j) { 22 | Q_UNUSED(j) 23 | 24 | if (appState == nullptr) { 25 | appState = new AppState(e); 26 | } 27 | 28 | return appState; 29 | } 30 | static QObject *fingerboardCppInterfaceSingletonProvider(QQmlEngine *e, 31 | QJSEngine *j) { 32 | Q_UNUSED(j) 33 | 34 | if (logger == nullptr) { 35 | logger = new Logger(e); 36 | } 37 | 38 | if (fingerObj == nullptr) { 39 | fingerObj = new Finger(e); 40 | } 41 | 42 | if (appState == nullptr) { 43 | appState = new AppState(e); 44 | } 45 | 46 | if (fingerboardCppInterface == nullptr) { 47 | fingerboardCppInterface = 48 | new FingerboardCppInterface(fingerObj, logger, appState, e); 49 | } 50 | 51 | return fingerboardCppInterface; 52 | } 53 | 54 | void registerQmlTypes(QObject *parent) { 55 | qmlRegisterSingletonType( 56 | "Fingerboard", 1, 0, "FingerboardCppInterface", 57 | fingerboardCppInterfaceSingletonProvider); 58 | 59 | qmlRegisterSingletonType("Fingerboard", 1, 0, "AppState", 60 | appStateSingletonProvider); 61 | 62 | qmlRegisterSingletonType("Fingerboard", 1, 0, "Finger", 63 | fingerObjSingletonProvider); 64 | qmlRegisterUncreatableType( 65 | "Fingerboard", 1, 0, "Logger", 66 | "Logger can be instantiated from c++ only"); 67 | } 68 | #else 69 | void registerQmlTypes(QObject *parent) { 70 | Finger *fingerObj = new Finger(parent); 71 | Logger *logger = new Logger(parent); 72 | AppState *appState = new AppState(parent); 73 | FingerboardCppInterface *fingerboardCppInterface = 74 | new FingerboardCppInterface(fingerObj, logger, appState, parent); 75 | 76 | qmlRegisterSingletonInstance( 77 | "Fingerboard", 1, 0, "FingerboardCppInterface", fingerboardCppInterface); 78 | qmlRegisterSingletonInstance("Fingerboard", 1, 0, "AppState", 79 | appState); 80 | qmlRegisterSingletonInstance("Fingerboard", 1, 0, "Finger", 81 | fingerObj); 82 | qmlRegisterUncreatableType( 83 | "Fingerboard", 1, 0, "Logger", 84 | "Logger can be instantiated from c++ only"); 85 | } 86 | #endif 87 | -------------------------------------------------------------------------------- /src/utils/appstate.cpp: -------------------------------------------------------------------------------- 1 | #include "appstate.h" 2 | 3 | AppState::AppState(QObject *parent) : QObject(parent) {} 4 | 5 | AppState::ErrorStatus AppState::errorStatusFromRawString( 6 | QString rawErrorString) { 7 | return rawErrorMap.value(rawErrorString); 8 | } 9 | 10 | void AppState::raiseError(QString rawError) { 11 | raiseError(rawErrorMap.value(rawError)); 12 | } 13 | 14 | void AppState::raiseError(AppState::ErrorStatus errorStatus) { 15 | emit error(errorStatus, errorStatusString(errorStatus)); 16 | } 17 | 18 | AppState::EnrollStatus AppState::getEnrollStatus() { return _enrollStatus; } 19 | 20 | AppState::EnrollStatus AppState::enrollStatusFromRawString(QString rawStatus) { 21 | return rawEnrollStatusMap.value(rawStatus); 22 | } 23 | 24 | void AppState::setEnrollStatus(AppState::EnrollStatus status) { 25 | _enrollStatus = status; 26 | emit enrollStatusChanged(status); 27 | } 28 | 29 | AppState::VerifyStatus AppState::getVerifyStatus() { return _verifyStatus; } 30 | 31 | AppState::VerifyStatus AppState::verifyStatusFromRawString(QString rawStatus) { 32 | return rawVerifyStatusMap.value(rawStatus); 33 | } 34 | 35 | void AppState::setVerifyStatus(AppState::VerifyStatus status) { 36 | _verifyStatus = status; 37 | emit verifyStatusChanged(status); 38 | } 39 | 40 | void AppState::resetApp() { 41 | _enrollStatus = EnrollStatus::ENROLL_EMPTY; 42 | _verifyStatus = VerifyStatus::VERIFY_EMPTY; 43 | 44 | emit enrollStatusChanged(_enrollStatus); 45 | emit verifyStatusChanged(_verifyStatus); 46 | } 47 | 48 | QString AppState::errorStatusString(AppState::ErrorStatus status) { 49 | switch (status) { 50 | case AppState::ErrorStatus::ERROR_NO_DEVICE: 51 | return "No Fingerprint Reader found"; 52 | case AppState::ErrorStatus::ERROR_PERMISSION_DENIED: 53 | return "User lacks the appropriate PolicyKit authorization"; 54 | case AppState::ErrorStatus::ERROR_NO_ENROLLED_PRINTS: 55 | return "User doesn't have any fingerprints enrolled"; 56 | case AppState::ErrorStatus::ERROR_ALREADY_IN_USE: 57 | return "Device is already claimed"; 58 | case AppState::ErrorStatus::ERROR_INTERNAL: 59 | return "Device couldn't be claimed"; 60 | case AppState::ErrorStatus::ERROR_CLAIM_DEVICE: 61 | return "Device was not claimed"; 62 | case AppState::ErrorStatus::ERROR_NO_ACTION_IN_PROGRESS: 63 | return "There are no ongoing verification"; 64 | case AppState::ErrorStatus::ERROR_INVALID_FINGERNAME: 65 | return "Finger name passed is invalid"; 66 | } 67 | 68 | return ""; 69 | } 70 | 71 | QString AppState::getEnrollStatusString() { 72 | switch (_enrollStatus) { 73 | case AppState::EnrollStatus::ENROLL_EMPTY: 74 | return ""; 75 | case AppState::EnrollStatus::ENROLL_START: 76 | return "Touch/Swipe to start Enrolling"; 77 | case AppState::EnrollStatus::ENROLL_FAILED: 78 | return "The enrollment failed"; 79 | case AppState::EnrollStatus::ENROLL_COMPLETED: 80 | return "The enrollment successfully completed"; 81 | case AppState::EnrollStatus::ENROLL_DATA_FULL: 82 | return "No further prints can be enrolled on this device"; 83 | case AppState::EnrollStatus::ENROLL_RETRY_SCAN: 84 | return "Retry scanning the finger"; 85 | case AppState::EnrollStatus::ENROLL_DISCONNECTED: 86 | return "The device was disconnected during the enrollment"; 87 | case AppState::EnrollStatus::ENROLL_STAGE_PASSED: 88 | return "Enrollment stage passed"; 89 | case AppState::EnrollStatus::ENROLL_UNKNOWN_ERROR: 90 | return "An unknown error occurred"; 91 | case AppState::EnrollStatus::ENROLL_SWIPE_TOO_SHORT: 92 | return "Swipe was too short"; 93 | case AppState::EnrollStatus::ENROLL_REMOVE_AND_RETRY: 94 | return "Remove the finger from the reader and retry scanning"; 95 | case AppState::EnrollStatus::ENROLL_FINGER_NOT_CENTERED: 96 | return "Finger was not centered on the reader"; 97 | } 98 | 99 | return ""; 100 | } 101 | 102 | QString AppState::getVerifyStatusString() { 103 | switch (_verifyStatus) { 104 | case AppState::VerifyStatus::VERIFY_EMPTY: 105 | return ""; 106 | case AppState::VerifyStatus::VERIFY_START: 107 | return "Touch/Swipe to start Verification"; 108 | case AppState::VerifyStatus::VERIFY_MATCH: 109 | return "The verification succeeded"; 110 | case AppState::VerifyStatus::VERIFY_NO_MATCH: 111 | return "The verification did not match"; 112 | case AppState::VerifyStatus::VERIFY_RETRY_SCAN: 113 | return "Retry scanning the finger"; 114 | case AppState::VerifyStatus::VERIFY_DISCONNECTED: 115 | return "The device was disconnected during the verification"; 116 | case AppState::VerifyStatus::VERIFY_UNKNOWN_ERROR: 117 | return "An unknown error occurred"; 118 | case AppState::VerifyStatus::VERIFY_SWIPE_TOO_SHORT: 119 | return "Swipe was too short"; 120 | case AppState::VerifyStatus::VERIFY_REMOVE_AND_RETRY: 121 | return "Remove the finger from the reader and retry scanning"; 122 | case AppState::VerifyStatus::VERIFY_FINGER_NOT_CENTERED: 123 | return "Finger was not centered on the reader"; 124 | } 125 | 126 | return ""; 127 | } 128 | -------------------------------------------------------------------------------- /src/qml/LogPanel.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Controls.Material 2.12 4 | import QtQuick.Layouts 1.12 5 | 6 | import Fingerboard 1.0 7 | 8 | Rectangle { 9 | Connections { 10 | target: FingerboardCppInterface 11 | 12 | // function onLog(logLevel, msg) 13 | onLog: { 14 | logsModel.append({ 15 | logLevel: logLevel, 16 | text: msg 17 | }); 18 | logPane.positionViewAtEnd(); 19 | } 20 | } 21 | 22 | ListModel { 23 | id: logsModel 24 | } 25 | 26 | ColumnLayout { 27 | anchors.fill: parent 28 | 29 | Rectangle { 30 | Layout.fillWidth: true 31 | height: 50 32 | color: "#f5f5f5" 33 | 34 | RowLayout { 35 | anchors { 36 | top: parent.top 37 | left: parent.left 38 | bottom: parent.bottom 39 | } 40 | 41 | Label { 42 | text: "Log Level" 43 | Layout.margins: 10 44 | font.pixelSize: 12 45 | } 46 | 47 | ComboBox { 48 | id: logLevelDropdown 49 | currentIndex: 2 50 | font.pixelSize: 12 51 | 52 | model: ListModel { 53 | id: logLevelModel 54 | 55 | ListElement { 56 | text: "ERROR" 57 | level: Logger.ERROR 58 | } 59 | ListElement { 60 | text: "WARNING" 61 | level: Logger.WARNING 62 | } 63 | ListElement { 64 | text: "INFO" 65 | level: Logger.INFO 66 | } 67 | ListElement { 68 | text: "DEBUG" 69 | level: Logger.DEBUG 70 | } 71 | ListElement { 72 | text: "VERBOSE" 73 | level: Logger.VERBOSE 74 | } 75 | } 76 | onCurrentIndexChanged: { 77 | logPane.forceLayout(); 78 | } 79 | textRole: "text" 80 | delegate: ItemDelegate { 81 | width: parent.width 82 | text: model.text 83 | font.pixelSize: 12 84 | } 85 | 86 | function selected() { 87 | return logLevelModel.get(currentIndex); 88 | } 89 | } 90 | 91 | CheckBox { 92 | id: colorize 93 | 94 | checked: true 95 | font.pixelSize: 12 96 | text: "Colorize" 97 | Material.primary: Material.Blue 98 | } 99 | } 100 | 101 | Button { 102 | width: 50 103 | height: 50 104 | icon.name: "window-close" 105 | flat: true 106 | 107 | anchors { 108 | right: parent.right 109 | verticalCenter: parent.verticalCenter 110 | } 111 | 112 | onClicked: { 113 | showLogs = false; 114 | } 115 | } 116 | } 117 | 118 | ListView { 119 | id: logPane 120 | Layout.fillWidth: true 121 | Layout.fillHeight: true 122 | 123 | clip: true 124 | interactive: true 125 | model: logsModel 126 | 127 | ScrollBar.vertical: ScrollBar { active: true; visible: true } 128 | 129 | delegate: Label { 130 | property bool shouldShow: model.logLevel <= logLevelDropdown.selected().level 131 | 132 | width: parent.width 133 | color: colorize.checked ? logPane.getColor(model.logLevel) : Material.color(Material.Grey, Material.Shade800); 134 | text: model.text 135 | font.family: 'monospace' 136 | height: shouldShow ? implicitHeight : 0 137 | visible: shouldShow 138 | } 139 | 140 | function getColor(logLevel) { 141 | switch (logLevel) { 142 | case Logger.ERROR: 143 | return Material.color(Material.Red); 144 | case Logger.WARNING: 145 | return Material.color(Material.Orange); 146 | case Logger.INFO: 147 | return Material.color(Material.Blue); 148 | case Logger.DEBUG: 149 | return Material.color(Material.Grey, Material.Shade800); 150 | case Logger.VERBOSE: 151 | return Material.color(Material.Grey); 152 | } 153 | } 154 | } 155 | } 156 | } 157 | 158 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Google 4 | AccessModifierOffset: -1 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveMacros: false 7 | AlignConsecutiveAssignments: false 8 | AlignConsecutiveDeclarations: false 9 | AlignEscapedNewlines: Left 10 | AlignOperands: true 11 | AlignTrailingComments: true 12 | AllowAllArgumentsOnNextLine: true 13 | AllowAllConstructorInitializersOnNextLine: true 14 | AllowAllParametersOfDeclarationOnNextLine: true 15 | AllowShortBlocksOnASingleLine: Never 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortFunctionsOnASingleLine: All 18 | AllowShortLambdasOnASingleLine: All 19 | AllowShortIfStatementsOnASingleLine: WithoutElse 20 | AllowShortLoopsOnASingleLine: true 21 | AlwaysBreakAfterDefinitionReturnType: None 22 | AlwaysBreakAfterReturnType: None 23 | AlwaysBreakBeforeMultilineStrings: true 24 | AlwaysBreakTemplateDeclarations: Yes 25 | BinPackArguments: true 26 | BinPackParameters: true 27 | BraceWrapping: 28 | AfterCaseLabel: false 29 | AfterClass: false 30 | AfterControlStatement: false 31 | AfterEnum: false 32 | AfterFunction: false 33 | AfterNamespace: false 34 | AfterObjCDeclaration: false 35 | AfterStruct: false 36 | AfterUnion: false 37 | AfterExternBlock: false 38 | BeforeCatch: false 39 | BeforeElse: false 40 | IndentBraces: false 41 | SplitEmptyFunction: true 42 | SplitEmptyRecord: true 43 | SplitEmptyNamespace: true 44 | BreakBeforeBinaryOperators: None 45 | BreakBeforeBraces: Attach 46 | BreakBeforeInheritanceComma: false 47 | BreakInheritanceList: BeforeColon 48 | BreakBeforeTernaryOperators: true 49 | BreakConstructorInitializersBeforeComma: false 50 | BreakConstructorInitializers: BeforeColon 51 | BreakAfterJavaFieldAnnotations: false 52 | BreakStringLiterals: true 53 | ColumnLimit: 80 54 | CommentPragmas: '^ IWYU pragma:' 55 | CompactNamespaces: false 56 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 57 | ConstructorInitializerIndentWidth: 4 58 | ContinuationIndentWidth: 4 59 | Cpp11BracedListStyle: true 60 | DeriveLineEnding: true 61 | DerivePointerAlignment: true 62 | DisableFormat: false 63 | ExperimentalAutoDetectBinPacking: false 64 | FixNamespaceComments: true 65 | ForEachMacros: 66 | - foreach 67 | - Q_FOREACH 68 | - BOOST_FOREACH 69 | IncludeBlocks: Regroup 70 | IncludeCategories: 71 | - Regex: '^' 72 | Priority: 2 73 | SortPriority: 0 74 | - Regex: '^<.*\.h>' 75 | Priority: 1 76 | SortPriority: 0 77 | - Regex: '^<.*' 78 | Priority: 2 79 | SortPriority: 0 80 | - Regex: '.*' 81 | Priority: 3 82 | SortPriority: 0 83 | IncludeIsMainRegex: '([-_](test|unittest))?$' 84 | IncludeIsMainSourceRegex: '' 85 | IndentCaseLabels: true 86 | IndentGotoLabels: true 87 | IndentPPDirectives: None 88 | IndentWidth: 2 89 | IndentWrappedFunctionNames: false 90 | JavaScriptQuotes: Leave 91 | JavaScriptWrapImports: true 92 | KeepEmptyLinesAtTheStartOfBlocks: false 93 | MacroBlockBegin: '' 94 | MacroBlockEnd: '' 95 | MaxEmptyLinesToKeep: 1 96 | NamespaceIndentation: None 97 | ObjCBinPackProtocolList: Never 98 | ObjCBlockIndentWidth: 2 99 | ObjCSpaceAfterProperty: false 100 | ObjCSpaceBeforeProtocolList: true 101 | PenaltyBreakAssignment: 2 102 | PenaltyBreakBeforeFirstCallParameter: 1 103 | PenaltyBreakComment: 300 104 | PenaltyBreakFirstLessLess: 120 105 | PenaltyBreakString: 1000 106 | PenaltyBreakTemplateDeclaration: 10 107 | PenaltyExcessCharacter: 1000000 108 | PenaltyReturnTypeOnItsOwnLine: 200 109 | PointerAlignment: Left 110 | RawStringFormats: 111 | - Language: Cpp 112 | Delimiters: 113 | - cc 114 | - CC 115 | - cpp 116 | - Cpp 117 | - CPP 118 | - 'c++' 119 | - 'C++' 120 | CanonicalDelimiter: '' 121 | BasedOnStyle: google 122 | - Language: TextProto 123 | Delimiters: 124 | - pb 125 | - PB 126 | - proto 127 | - PROTO 128 | EnclosingFunctions: 129 | - EqualsProto 130 | - EquivToProto 131 | - PARSE_PARTIAL_TEXT_PROTO 132 | - PARSE_TEST_PROTO 133 | - PARSE_TEXT_PROTO 134 | - ParseTextOrDie 135 | - ParseTextProtoOrDie 136 | CanonicalDelimiter: '' 137 | BasedOnStyle: google 138 | ReflowComments: true 139 | SortIncludes: true 140 | SortUsingDeclarations: true 141 | SpaceAfterCStyleCast: false 142 | SpaceAfterLogicalNot: false 143 | SpaceAfterTemplateKeyword: true 144 | SpaceBeforeAssignmentOperators: true 145 | SpaceBeforeCpp11BracedList: false 146 | SpaceBeforeCtorInitializerColon: true 147 | SpaceBeforeInheritanceColon: true 148 | SpaceBeforeParens: ControlStatements 149 | SpaceBeforeRangeBasedForLoopColon: true 150 | SpaceInEmptyBlock: false 151 | SpaceInEmptyParentheses: false 152 | SpacesBeforeTrailingComments: 2 153 | SpacesInAngles: false 154 | SpacesInConditionalStatement: false 155 | SpacesInContainerLiterals: true 156 | SpacesInCStyleCastParentheses: false 157 | SpacesInParentheses: false 158 | SpacesInSquareBrackets: false 159 | SpaceBeforeSquareBrackets: false 160 | Standard: Auto 161 | StatementMacros: 162 | - Q_UNUSED 163 | - QT_REQUIRE_VERSION 164 | TabWidth: 8 165 | UseCRLF: false 166 | UseTab: Never 167 | ... 168 | 169 | -------------------------------------------------------------------------------- /src/qml/VerifyView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.12 5 | import QtGraphicalEffects 1.0 6 | 7 | import Fingerboard 1.0 8 | 9 | Rectangle { 10 | property bool verifyStarted: false 11 | property bool verifyCompleted: false 12 | property bool verifyErrored: false 13 | 14 | width: 600 15 | height: 700 16 | 17 | Connections { 18 | target: AppState 19 | 20 | // function onVerifyStarted() 21 | onVerifyStarted: { 22 | verifyStarted= true; 23 | } 24 | 25 | // function onVerifyCompleted() 26 | onVerifyCompleted: { 27 | verifyCompleted = true; 28 | } 29 | 30 | // function onVerifyErrored() 31 | onVerifyErrored: { 32 | verifyErrored = true; 33 | } 34 | } 35 | 36 | ColumnLayout { 37 | width: parent.width 38 | 39 | Item { 40 | width: 200 41 | height: width 42 | Layout.alignment: Qt.AlignHCenter 43 | Layout.topMargin: 75 44 | 45 | CircularProgressBar { 46 | lineWidth: 6 47 | value: verifyCompleted || verifyErrored ? 1 : 0 48 | size: parent.width 49 | animationDuration: 200 50 | secondaryColor: Material.color(Material.Grey, Material.Shade300) 51 | primaryColor: getColor() 52 | 53 | function getColor() { 54 | if (verifyCompleted) { 55 | return Material.color(Material.Green) 56 | } else if (verifyErrored) { 57 | return Material.color(Material.Red, Material.Shade300) 58 | } else { 59 | return Material.color(Material.Blue) 60 | } 61 | } 62 | } 63 | 64 | Image { 65 | width: 100 66 | height: 100 67 | source: "qrc:/fingerprint.svg" 68 | smooth: true 69 | anchors.centerIn: parent 70 | 71 | ColorOverlay { 72 | anchors.fill: parent 73 | source: parent 74 | color: getColor() 75 | 76 | function getColor() { 77 | if (verifyCompleted) { 78 | return Material.color(Material.Green) 79 | } else if (verifyErrored) { 80 | return Material.color(Material.Red, Material.Shade300) 81 | } else { 82 | return Material.color(Material.Grey, Material.Shade600) 83 | } 84 | } 85 | } 86 | } 87 | } 88 | 89 | Label { 90 | text: getText() 91 | font.pixelSize: 30 92 | Layout.alignment: Qt.AlignHCenter 93 | Layout.topMargin: 32 94 | color: getColor() 95 | 96 | function getText() { 97 | if (verifyStarted && !verifyCompleted && !verifyErrored) { 98 | return "Verifying"; 99 | } else if (verifyStarted && verifyErrored) { 100 | return "No Match"; 101 | } else if (verifyStarted && verifyCompleted) { 102 | return "Matched"; 103 | } else { 104 | return ""; 105 | } 106 | } 107 | 108 | function getColor() { 109 | if (verifyCompleted) { 110 | return Material.color(Material.Green); 111 | } else if (verifyErrored) { 112 | return Material.color(Material.Red, Material.Shade300); 113 | } else { 114 | return Material.color(Material.Blue, Material.Shade600); 115 | } 116 | } 117 | } 118 | 119 | Label { 120 | visible: verifyStarted 121 | text: AppState.verifyStatusString 122 | Layout.alignment: Qt.AlignHCenter 123 | Layout.topMargin: 128 124 | font.pixelSize: 15 125 | color: Material.color(Material.Grey, Material.Shade500) 126 | } 127 | 128 | Button { 129 | visible: !verifyStarted 130 | Layout.preferredWidth: 128 131 | Layout.preferredHeight: 45 132 | text: "START" 133 | font.pixelSize: 12 134 | font.bold: true 135 | hoverEnabled: true 136 | Layout.alignment: Qt.AlignHCenter 137 | Layout.topMargin: 185 138 | 139 | Material.elevation: 0 140 | Material.background: Material.Blue 141 | 142 | onClicked: { 143 | FingerboardCppInterface.verifyFp(); 144 | } 145 | 146 | PointingHandOverlay { 147 | anchors.fill: parent 148 | } 149 | } 150 | } 151 | 152 | Button { 153 | flat: true 154 | icon.source: "qrc:/back.svg" 155 | icon.color: Material.color(Material.Grey, Material.Shade500) 156 | anchors { 157 | left: parent.left 158 | leftMargin: 16 159 | top: parent.top 160 | topMargin: 16 161 | } 162 | hoverEnabled: true 163 | 164 | onClicked: { 165 | appstack.pop(); 166 | } 167 | 168 | PointingHandOverlay { 169 | anchors.fill: parent 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/utils/appstate.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_APPSTATE_H 2 | #define UTILS_APPSTATE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class AppState : public QObject { 10 | Q_OBJECT 11 | 12 | Q_PROPERTY( 13 | EnrollStatus enrollStatus READ getEnrollStatus NOTIFY enrollStatusChanged) 14 | Q_PROPERTY(QString enrollStatusString READ getEnrollStatusString NOTIFY 15 | enrollStatusChanged) 16 | 17 | Q_PROPERTY( 18 | VerifyStatus verifyStatus READ getVerifyStatus NOTIFY verifyStatusChanged) 19 | Q_PROPERTY(QString verifyStatusString READ getVerifyStatusString NOTIFY 20 | verifyStatusChanged) 21 | 22 | public: 23 | enum ErrorStatus { 24 | ERROR_NO_DEVICE, 25 | 26 | ERROR_PERMISSION_DENIED, 27 | ERROR_NO_ENROLLED_PRINTS, 28 | ERROR_ALREADY_IN_USE, 29 | ERROR_INTERNAL, 30 | ERROR_CLAIM_DEVICE, 31 | ERROR_NO_ACTION_IN_PROGRESS, 32 | ERROR_INVALID_FINGERNAME, 33 | }; 34 | Q_ENUM(ErrorStatus); 35 | 36 | enum EnrollStatus { 37 | ENROLL_EMPTY, 38 | 39 | ENROLL_START, 40 | ENROLL_COMPLETED, 41 | ENROLL_FAILED, 42 | ENROLL_STAGE_PASSED, 43 | ENROLL_RETRY_SCAN, 44 | ENROLL_SWIPE_TOO_SHORT, 45 | ENROLL_FINGER_NOT_CENTERED, 46 | ENROLL_REMOVE_AND_RETRY, 47 | ENROLL_DATA_FULL, 48 | ENROLL_DISCONNECTED, 49 | ENROLL_UNKNOWN_ERROR 50 | }; 51 | Q_ENUM(EnrollStatus) 52 | 53 | enum VerifyStatus { 54 | VERIFY_EMPTY, 55 | 56 | VERIFY_START, 57 | VERIFY_NO_MATCH, 58 | VERIFY_MATCH, 59 | VERIFY_RETRY_SCAN, 60 | VERIFY_SWIPE_TOO_SHORT, 61 | VERIFY_FINGER_NOT_CENTERED, 62 | VERIFY_REMOVE_AND_RETRY, 63 | VERIFY_DISCONNECTED, 64 | VERIFY_UNKNOWN_ERROR 65 | }; 66 | Q_ENUM(VerifyStatus) 67 | 68 | AppState(QObject *parent = nullptr); 69 | 70 | ErrorStatus errorStatusFromRawString(QString rawErrorString); 71 | void raiseError(QString rawError); 72 | void raiseError(AppState::ErrorStatus errorStatus); 73 | 74 | EnrollStatus getEnrollStatus(); 75 | QString getEnrollStatusString(); 76 | EnrollStatus enrollStatusFromRawString(QString rawStatus); 77 | void setEnrollStatus(EnrollStatus status); 78 | 79 | VerifyStatus getVerifyStatus(); 80 | QString getVerifyStatusString(); 81 | VerifyStatus verifyStatusFromRawString(QString rawStatus); 82 | void setVerifyStatus(VerifyStatus status); 83 | 84 | void resetApp(); 85 | 86 | public slots: 87 | QString errorStatusString(AppState::ErrorStatus status); 88 | 89 | signals: 90 | void listingStarted(); 91 | void listingCompleted(); 92 | 93 | void enrollStarted(); 94 | void enrollStatusChanged(EnrollStatus status); 95 | void enrollCompleted(); 96 | void enrollErrored(); 97 | 98 | void verifyStarted(); 99 | void verifyStatusChanged(VerifyStatus status); 100 | void verifyCompleted(); 101 | void verifyErrored(); 102 | 103 | void deleteStarted(); 104 | void deleteCompleted(); 105 | 106 | void error(ErrorStatus errorStatus, QString errorString); 107 | 108 | void reset(); 109 | 110 | private: 111 | EnrollStatus _enrollStatus = EnrollStatus::ENROLL_EMPTY; 112 | VerifyStatus _verifyStatus = VerifyStatus::VERIFY_EMPTY; 113 | 114 | QMap rawErrorMap = { 115 | {"net.reactivated.Fprint.Error.PermissionDenied", 116 | ErrorStatus::ERROR_PERMISSION_DENIED}, 117 | {"net.reactivated.Fprint.Error.NoEnrolledPrints", 118 | ErrorStatus::ERROR_NO_ENROLLED_PRINTS}, 119 | {"net.reactivated.Fprint.Error.AlreadyInUse", 120 | ErrorStatus::ERROR_ALREADY_IN_USE}, 121 | {"net.reactivated.Fprint.Error.Internal", ErrorStatus::ERROR_INTERNAL}, 122 | {"net.reactivated.Fprint.Error.ClaimDevice", 123 | ErrorStatus::ERROR_CLAIM_DEVICE}, 124 | {"net.reactivated.Fprint.Error.NoActionInProgress", 125 | ErrorStatus::ERROR_NO_ACTION_IN_PROGRESS}, 126 | {"net.reactivated.Fprint.Error.InvalidFingername", 127 | ErrorStatus::ERROR_INVALID_FINGERNAME}}; 128 | 129 | QMap rawEnrollStatusMap = { 130 | {"enroll-completed", AppState::EnrollStatus::ENROLL_COMPLETED}, 131 | {"enroll-failed", AppState::EnrollStatus::ENROLL_FAILED}, 132 | {"enroll-stage-passed", AppState::EnrollStatus::ENROLL_STAGE_PASSED}, 133 | {"enroll-retry-scan", AppState::EnrollStatus::ENROLL_RETRY_SCAN}, 134 | {"enroll-swipe-too-short", 135 | AppState::EnrollStatus::ENROLL_SWIPE_TOO_SHORT}, 136 | {"enroll-finger-not-centered", 137 | AppState::EnrollStatus::ENROLL_FINGER_NOT_CENTERED}, 138 | {"enroll-remove-and-retry", 139 | AppState::EnrollStatus::ENROLL_REMOVE_AND_RETRY}, 140 | {"enroll-data-full", AppState::EnrollStatus::ENROLL_DATA_FULL}, 141 | {"enroll-disconnected", AppState::EnrollStatus::ENROLL_DISCONNECTED}, 142 | {"enroll-unknown-error", AppState::EnrollStatus::ENROLL_UNKNOWN_ERROR}}; 143 | 144 | QMap rawVerifyStatusMap = { 145 | {"verify-no-match", AppState::VerifyStatus::VERIFY_NO_MATCH}, 146 | {"verify-match", AppState::VerifyStatus::VERIFY_MATCH}, 147 | {"verify-retry-scan", AppState::VerifyStatus::VERIFY_RETRY_SCAN}, 148 | {"verify-swipe-too-short", 149 | AppState::VerifyStatus::VERIFY_SWIPE_TOO_SHORT}, 150 | {"verify-finger-not-centered", 151 | AppState::VerifyStatus::VERIFY_FINGER_NOT_CENTERED}, 152 | {"verify-remove-and-retry", 153 | AppState::VerifyStatus::VERIFY_REMOVE_AND_RETRY}, 154 | {"verify-disconnected", AppState::VerifyStatus::VERIFY_DISCONNECTED}, 155 | {"verify-unknown-error", AppState::VerifyStatus::VERIFY_UNKNOWN_ERROR}}; 156 | }; 157 | 158 | #endif // UTILS_APPSTATE_H 159 | -------------------------------------------------------------------------------- /src/qml/EnrollView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.12 5 | import QtGraphicalEffects 1.0 6 | 7 | import Fingerboard 1.0 8 | 9 | Rectangle { 10 | property int stageCounter: 0 11 | property bool enrollStarted: false 12 | property bool enrollCompleted: false 13 | property bool enrollErrored: false 14 | 15 | width: 600 16 | height: 700 17 | 18 | Connections { 19 | target: AppState 20 | 21 | // function onEnrollStarted() 22 | onEnrollStarted: { 23 | enrollStarted = true; 24 | } 25 | 26 | // function onEnrollStatusChanged(status) 27 | onEnrollStatusChanged: { 28 | switch (status) { 29 | case AppState.ENROLL_STAGE_PASSED: 30 | stageCounter++; 31 | break; 32 | } 33 | } 34 | 35 | // function onEnrollCompleted() 36 | onEnrollCompleted: { 37 | enrollCompleted = true; 38 | FingerboardCppInterface.listFp(); 39 | } 40 | } 41 | 42 | ColumnLayout { 43 | width: parent.width 44 | 45 | Item { 46 | width: 200 47 | height: width 48 | Layout.alignment: Qt.AlignHCenter 49 | Layout.topMargin: 75 50 | 51 | CircularProgressBar { 52 | lineWidth: 6 53 | value: enrollCompleted ? 1 : stageCounter/FingerboardCppInterface.numEnrollStages 54 | size: parent.width 55 | animationDuration: 200 56 | secondaryColor: Material.color(Material.Grey, Material.Shade300) 57 | primaryColor: getColor() 58 | 59 | function getColor() { 60 | if (enrollCompleted) { 61 | return Material.color(Material.Green) 62 | } else if (enrollErrored) { 63 | return Material.color(Material.Red, Material.Shade300) 64 | } else { 65 | return Material.color(Material.Blue) 66 | } 67 | } 68 | } 69 | 70 | Image { 71 | width: 128 72 | height: 128 73 | source: "qrc:/fingerprint.svg" 74 | smooth: true 75 | anchors.centerIn: parent 76 | 77 | ColorOverlay { 78 | anchors.fill: parent 79 | source: parent 80 | color: getColor() 81 | 82 | function getColor() { 83 | if (enrollCompleted) { 84 | return Material.color(Material.Green) 85 | } else if (enrollErrored) { 86 | return Material.color(Material.Red, Material.Shade300) 87 | } else { 88 | return Material.color(Material.Grey, Material.Shade600) 89 | } 90 | } 91 | } 92 | } 93 | } 94 | 95 | Label { 96 | text: Finger.name(selectedEnrollingFinger) 97 | font.pixelSize: 12 98 | font.bold: true 99 | Layout.alignment: Qt.AlignHCenter 100 | Layout.topMargin: 16 101 | color: Material.color(Material.Grey) 102 | } 103 | 104 | Label { 105 | visible: enrollStarted && !enrollCompleted 106 | text: `Stage ${stageCounter+1}\/${FingerboardCppInterface.numEnrollStages}` 107 | font.pixelSize: 30 108 | Layout.alignment: Qt.AlignHCenter 109 | Layout.topMargin: 32 110 | color: Material.color(Material.Blue, Material.Shade600) 111 | } 112 | 113 | Label { 114 | visible: enrollCompleted 115 | text: `Completed` 116 | font.pixelSize: 30 117 | Layout.alignment: Qt.AlignHCenter 118 | Layout.topMargin: 32 119 | color: Material.color(Material.Green) 120 | } 121 | 122 | Label { 123 | visible: enrollStarted 124 | text: AppState.enrollStatusString 125 | Layout.alignment: Qt.AlignHCenter 126 | Layout.topMargin: 128 127 | font.pixelSize: 15 128 | color: Material.color(Material.Grey, Material.Shade500) 129 | } 130 | 131 | Button { 132 | visible: !enrollStarted 133 | Layout.preferredWidth: 128 134 | Layout.preferredHeight: 45 135 | text: "START" 136 | font.pixelSize: 12 137 | font.bold: true 138 | hoverEnabled: true 139 | Layout.alignment: Qt.AlignHCenter 140 | Layout.topMargin: 185 141 | 142 | Material.elevation: 0 143 | Material.background: Material.Blue 144 | 145 | onClicked: { 146 | FingerboardCppInterface.enrollFp(selectedEnrollingFinger); 147 | } 148 | 149 | PointingHandOverlay { 150 | anchors.fill: parent 151 | } 152 | } 153 | } 154 | 155 | Button { 156 | flat: true 157 | icon.source: "qrc:/back.svg" 158 | icon.color: Material.color(Material.Grey, Material.Shade500) 159 | anchors { 160 | left: parent.left 161 | leftMargin: 16 162 | top: parent.top 163 | topMargin: 16 164 | } 165 | hoverEnabled: true 166 | 167 | onClicked: { 168 | appstack.pop(); 169 | } 170 | 171 | PointingHandOverlay { 172 | anchors.fill: parent 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/qml/ListingView.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Controls.Material 2.12 5 | import QtGraphicalEffects 1.12 6 | 7 | import Fingerboard 1.0 8 | 9 | Rectangle { 10 | property int ditchGap: 2 11 | 12 | width: 600 13 | 14 | Connections { 15 | target: FingerboardCppInterface 16 | 17 | // function onEnrolledFingerprintsList(fingerprints) 18 | onEnrolledFingerprintsList: { 19 | var enrolledFingersMap = {}; 20 | 21 | for (var enrolledFinger in fingerprints) { 22 | enrolledFingersMap[fingerprints[enrolledFinger]] = true; 23 | } 24 | 25 | for (var i=0; iVERIFY FINGERPRINT" 195 | font.pixelSize: 12 196 | font.bold: true 197 | bottomInset: 0 198 | topInset: 0 199 | hoverEnabled: true 200 | 201 | Material.elevation: 0 202 | Material.background: Material.Blue 203 | 204 | onClicked: { 205 | appstack.push(verifyView); 206 | } 207 | 208 | PointingHandOverlay { 209 | anchors.fill: parent 210 | } 211 | } 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /src/qml/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 1.4 as Controls1 3 | import QtQuick.Controls 2.12 4 | import QtQuick.Layouts 1.12 5 | import QtQuick.Controls.Material 2.12 6 | import QtGraphicalEffects 1.0 7 | 8 | import Fingerboard 1.0 9 | 10 | ApplicationWindow { 11 | property bool showLogs: false 12 | property bool noDevice: false 13 | property int selectedEnrollingFinger: -1 14 | 15 | id: appWindow 16 | minimumWidth: 1000 17 | minimumHeight: 800 18 | title: "Fingerboard" 19 | visible: true 20 | 21 | Material.theme: Material.Light 22 | Material.accent: Material.Blue 23 | 24 | Material.background: "#f5f5f5" 25 | 26 | Component.onCompleted: { 27 | FingerboardCppInterface.init(); 28 | } 29 | 30 | Connections { 31 | target: AppState 32 | 33 | // function onError(errorStatus, errorString) 34 | onError: { 35 | if (errorStatus === AppState.ERROR_NO_DEVICE) { 36 | noDevice = true; 37 | } 38 | 39 | var component = Qt.createComponent("ErrorDialog.qml"); 40 | component.createObject(appWindow, { errorString: errorString }); 41 | } 42 | } 43 | 44 | Menu { 45 | id: appMenu 46 | 47 | font.pixelSize: 12 48 | 49 | MenuItem { 50 | text: "Show Logs" 51 | checkable: true 52 | checked: showLogs 53 | 54 | Shortcut { 55 | sequence: "ctrl+l" 56 | onActivated: showLogs = !showLogs 57 | } 58 | 59 | onToggled: showLogs = !showLogs 60 | } 61 | 62 | MenuItem { 63 | text: "About" 64 | onTriggered: aboutDialog.open(); 65 | } 66 | 67 | MenuItem { 68 | text: "Exit" 69 | onTriggered: Qt.quit(); 70 | } 71 | } 72 | 73 | RoundButton { 74 | id: menuBtn 75 | 76 | width: 48 77 | height: 48 78 | flat: true 79 | icon.source: "qrc:/menu.svg" 80 | icon.color: Material.color(Material.Grey, Material.Shade700) 81 | icon.width: 18 82 | icon.height: 18 83 | hoverEnabled: true 84 | 85 | onClicked: { 86 | appMenu.popup(menuBtn.x + 5, menuBtn.y + menuBtn.height); 87 | } 88 | 89 | PointingHandOverlay { 90 | anchors.fill: parent 91 | } 92 | } 93 | 94 | Image { 95 | width: 24 96 | height: 24 97 | source: "qrc:/info.svg" 98 | anchors { 99 | right: parent.right 100 | top: menuBtn.top 101 | margins: 12 102 | } 103 | 104 | ColorOverlay { 105 | anchors.fill: parent 106 | source: parent 107 | color: Material.color(Material.Grey, Material.Shade700) 108 | } 109 | 110 | ToolTip.text: getDeviceInfoText() 111 | 112 | MouseArea { 113 | anchors.fill: parent 114 | hoverEnabled: true 115 | 116 | onContainsMouseChanged: { 117 | parent.ToolTip.visible = containsMouse; 118 | } 119 | } 120 | 121 | function getDeviceInfoText() { 122 | if (noDevice) { 123 | return "No fingerprint reader detected" 124 | } else { 125 | return `Device: ${FingerboardCppInterface.deviceName}
`+ 126 | `Scan Type: ${FingerboardCppInterface.scanType}
`+ 127 | `Enroll Stages: ${FingerboardCppInterface.numEnrollStages}` 128 | } 129 | } 130 | } 131 | 132 | Controls1.SplitView { 133 | anchors.fill: parent 134 | orientation: Qt.Vertical 135 | 136 | StackView { 137 | property int animationDuration: 300 138 | property int easingType: Easing.InOutExpo 139 | 140 | id: appstack 141 | Layout.fillHeight: true 142 | Layout.fillWidth: true 143 | Layout.topMargin: 32 144 | initialItem: initialView 145 | 146 | pushEnter: Transition { 147 | PropertyAnimation { 148 | property: "x" 149 | easing.type: appstack.easingType 150 | from: appstack.width 151 | to: 0 152 | duration: appstack.animationDuration 153 | } 154 | } 155 | pushExit: Transition { 156 | PropertyAnimation { 157 | property: "x" 158 | easing.type: appstack.easingType 159 | from: 0 160 | to: -appstack.width 161 | duration: appstack.animationDuration 162 | } 163 | } 164 | popEnter: Transition { 165 | PropertyAnimation { 166 | property: "x" 167 | easing.type: appstack.easingType 168 | from: -appstack.width 169 | to: 0 170 | duration: appstack.animationDuration 171 | } 172 | } 173 | popExit: Transition { 174 | PropertyAnimation { 175 | property: "x" 176 | easing.type: appstack.easingType 177 | from: 0 178 | to: appstack.width 179 | duration: appstack.animationDuration 180 | } 181 | } 182 | } 183 | 184 | LogPanel { 185 | visible: showLogs 186 | 187 | Layout.fillWidth: true 188 | height: 300 189 | } 190 | } 191 | 192 | Component { 193 | id: initialView 194 | 195 | Item { 196 | ListingView { 197 | anchors.horizontalCenter: parent.horizontalCenter 198 | } 199 | 200 | RoundButton { 201 | anchors { 202 | right: parent.right 203 | bottom: parent.bottom 204 | margins: 16 205 | } 206 | hoverEnabled: true 207 | padding: 18 208 | 209 | Material.background: Material.Red 210 | icon.source: "qrc:/delete.svg" 211 | icon.color: "white" 212 | 213 | z: 10 214 | 215 | onClicked: { 216 | deleteDialog.visible = true; 217 | } 218 | 219 | PointingHandOverlay { 220 | anchors.fill: parent 221 | } 222 | } 223 | } 224 | } 225 | 226 | Component { 227 | id: enrollView 228 | 229 | Item { 230 | EnrollView { 231 | anchors.horizontalCenter: parent.horizontalCenter 232 | } 233 | } 234 | } 235 | 236 | Component { 237 | id: verifyView 238 | 239 | Item { 240 | VerifyView { 241 | anchors.horizontalCenter: parent.horizontalCenter 242 | } 243 | } 244 | } 245 | 246 | DeleteDialog { 247 | id: deleteDialog 248 | } 249 | AboutDialog { 250 | id: aboutDialog 251 | } 252 | } 253 | 254 | -------------------------------------------------------------------------------- /src/qml/CircularProgressBar.qml: -------------------------------------------------------------------------------- 1 | // Based on : https://github.com/rafzby/circular-progressbar/blob/master/CircularProgressBar.qml 2 | 3 | /* 4 | 5 | GNU LESSER GENERAL PUBLIC LICENSE 6 | Version 3, 29 June 2007 7 | 8 | Copyright (C) 2007 Free Software Foundation, Inc. 9 | Everyone is permitted to copy and distribute verbatim copies 10 | of this license document, but changing it is not allowed. 11 | 12 | 13 | This version of the GNU Lesser General Public License incorporates 14 | the terms and conditions of version 3 of the GNU General Public 15 | License, supplemented by the additional permissions listed below. 16 | 17 | 0. Additional Definitions. 18 | 19 | As used herein, "this License" refers to version 3 of the GNU Lesser 20 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 21 | General Public License. 22 | 23 | "The Library" refers to a covered work governed by this License, 24 | other than an Application or a Combined Work as defined below. 25 | 26 | An "Application" is any work that makes use of an interface provided 27 | by the Library, but which is not otherwise based on the Library. 28 | Defining a subclass of a class defined by the Library is deemed a mode 29 | of using an interface provided by the Library. 30 | 31 | A "Combined Work" is a work produced by combining or linking an 32 | Application with the Library. The particular version of the Library 33 | with which the Combined Work was made is also called the "Linked 34 | Version". 35 | 36 | The "Minimal Corresponding Source" for a Combined Work means the 37 | Corresponding Source for the Combined Work, excluding any source code 38 | for portions of the Combined Work that, considered in isolation, are 39 | based on the Application, and not on the Linked Version. 40 | 41 | The "Corresponding Application Code" for a Combined Work means the 42 | object code and/or source code for the Application, including any data 43 | and utility programs needed for reproducing the Combined Work from the 44 | Application, but excluding the System Libraries of the Combined Work. 45 | 46 | 1. Exception to Section 3 of the GNU GPL. 47 | 48 | You may convey a covered work under sections 3 and 4 of this License 49 | without being bound by section 3 of the GNU GPL. 50 | 51 | 2. Conveying Modified Versions. 52 | 53 | If you modify a copy of the Library, and, in your modifications, a 54 | facility refers to a function or data to be supplied by an Application 55 | that uses the facility (other than as an argument passed when the 56 | facility is invoked), then you may convey a copy of the modified 57 | version: 58 | 59 | a) under this License, provided that you make a good faith effort to 60 | ensure that, in the event an Application does not supply the 61 | function or data, the facility still operates, and performs 62 | whatever part of its purpose remains meaningful, or 63 | 64 | b) under the GNU GPL, with none of the additional permissions of 65 | this License applicable to that copy. 66 | 67 | 3. Object Code Incorporating Material from Library Header Files. 68 | 69 | The object code form of an Application may incorporate material from 70 | a header file that is part of the Library. You may convey such object 71 | code under terms of your choice, provided that, if the incorporated 72 | material is not limited to numerical parameters, data structure 73 | layouts and accessors, or small macros, inline functions and templates 74 | (ten or fewer lines in length), you do both of the following: 75 | 76 | a) Give prominent notice with each copy of the object code that the 77 | Library is used in it and that the Library and its use are 78 | covered by this License. 79 | 80 | b) Accompany the object code with a copy of the GNU GPL and this license 81 | document. 82 | 83 | 4. Combined Works. 84 | 85 | You may convey a Combined Work under terms of your choice that, 86 | taken together, effectively do not restrict modification of the 87 | portions of the Library contained in the Combined Work and reverse 88 | engineering for debugging such modifications, if you also do each of 89 | the following: 90 | 91 | a) Give prominent notice with each copy of the Combined Work that 92 | the Library is used in it and that the Library and its use are 93 | covered by this License. 94 | 95 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 96 | document. 97 | 98 | c) For a Combined Work that displays copyright notices during 99 | execution, include the copyright notice for the Library among 100 | these notices, as well as a reference directing the user to the 101 | copies of the GNU GPL and this license document. 102 | 103 | d) Do one of the following: 104 | 105 | 0) Convey the Minimal Corresponding Source under the terms of this 106 | License, and the Corresponding Application Code in a form 107 | suitable for, and under terms that permit, the user to 108 | recombine or relink the Application with a modified version of 109 | the Linked Version to produce a modified Combined Work, in the 110 | manner specified by section 6 of the GNU GPL for conveying 111 | Corresponding Source. 112 | 113 | 1) Use a suitable shared library mechanism for linking with the 114 | Library. A suitable mechanism is one that (a) uses at run time 115 | a copy of the Library already present on the user's computer 116 | system, and (b) will operate properly with a modified version 117 | of the Library that is interface-compatible with the Linked 118 | Version. 119 | 120 | e) Provide Installation Information, but only if you would otherwise 121 | be required to provide such information under section 6 of the 122 | GNU GPL, and only to the extent that such information is 123 | necessary to install and execute a modified version of the 124 | Combined Work produced by recombining or relinking the 125 | Application with a modified version of the Linked Version. (If 126 | you use option 4d0, the Installation Information must accompany 127 | the Minimal Corresponding Source and Corresponding Application 128 | Code. If you use option 4d1, you must provide the Installation 129 | Information in the manner specified by section 6 of the GNU GPL 130 | for conveying Corresponding Source.) 131 | 132 | 5. Combined Libraries. 133 | 134 | You may place library facilities that are a work based on the 135 | Library side by side in a single library together with other library 136 | facilities that are not Applications and are not covered by this 137 | License, and convey such a combined library under terms of your 138 | choice, if you do both of the following: 139 | 140 | a) Accompany the combined library with a copy of the same work based 141 | on the Library, uncombined with any other library facilities, 142 | conveyed under the terms of this License. 143 | 144 | b) Give prominent notice with the combined library that part of it 145 | is a work based on the Library, and explaining where to find the 146 | accompanying uncombined form of the same work. 147 | 148 | 6. Revised Versions of the GNU Lesser General Public License. 149 | 150 | The Free Software Foundation may publish revised and/or new versions 151 | of the GNU Lesser General Public License from time to time. Such new 152 | versions will be similar in spirit to the present version, but may 153 | differ in detail to address new problems or concerns. 154 | 155 | Each version is given a distinguishing version number. If the 156 | Library as you received it specifies that a certain numbered version 157 | of the GNU Lesser General Public License "or any later version" 158 | applies to it, you have the option of following the terms and 159 | conditions either of that published version or of any later version 160 | published by the Free Software Foundation. If the Library as you 161 | received it does not specify a version number of the GNU Lesser 162 | General Public License, you may choose any version of the GNU Lesser 163 | General Public License ever published by the Free Software Foundation. 164 | 165 | If the Library as you received it specifies that a proxy can decide 166 | whether future versions of the GNU Lesser General Public License shall 167 | apply, that proxy's public statement of acceptance of any version is 168 | permanent authorization for you to choose that version for the 169 | Library. 170 | 171 | */ 172 | 173 | import QtQuick 2.9 174 | 175 | Item { 176 | id: root 177 | 178 | property int size: 150 179 | property int lineWidth: 5 180 | property real value: 0 181 | 182 | property color primaryColor: "#29b6f6" 183 | property color secondaryColor: "#e0e0e0" 184 | 185 | property int animationDuration: 1000 186 | 187 | width: size 188 | height: size 189 | 190 | onValueChanged: { 191 | canvas.degree = value * 360; 192 | } 193 | 194 | Canvas { 195 | id: canvas 196 | 197 | property real degree: 0 198 | 199 | anchors.fill: parent 200 | antialiasing: true 201 | 202 | onDegreeChanged: { 203 | requestPaint(); 204 | } 205 | 206 | onPaint: { 207 | var ctx = getContext("2d"); 208 | 209 | var x = root.width/2; 210 | var y = root.height/2; 211 | 212 | var radius = root.size/2 - root.lineWidth 213 | var startAngle = (Math.PI/180) * 270; 214 | var fullAngle = (Math.PI/180) * (270 + 360); 215 | var progressAngle = (Math.PI/180) * (270 + degree); 216 | 217 | ctx.reset() 218 | 219 | ctx.lineCap = 'round'; 220 | ctx.lineWidth = root.lineWidth; 221 | 222 | ctx.beginPath(); 223 | ctx.arc(x, y, radius, startAngle, fullAngle); 224 | ctx.strokeStyle = root.secondaryColor; 225 | ctx.stroke(); 226 | 227 | ctx.beginPath(); 228 | ctx.arc(x, y, radius, startAngle, progressAngle); 229 | ctx.strokeStyle = root.primaryColor; 230 | ctx.stroke(); 231 | } 232 | 233 | Behavior on degree { 234 | NumberAnimation { 235 | duration: root.animationDuration 236 | easing: Easing.OutCubic 237 | } 238 | } 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /src/interfaces/fingerboard_cpp_interface.cpp: -------------------------------------------------------------------------------- 1 | #include "fingerboard_cpp_interface.h" 2 | 3 | #include 4 | #include 5 | 6 | FingerboardCppInterface::FingerboardCppInterface(Finger *fingerObj, 7 | Logger *logger, 8 | AppState *appState, 9 | QObject *parent) 10 | : QObject(parent) { 11 | this->fingerObj = fingerObj; 12 | this->appState = appState; 13 | this->logger = logger; 14 | 15 | connect(logger, &Logger::writeLog, [=](Logger::Level logLevel, QString msg) { 16 | emit log(logLevel, msg); 17 | }); 18 | } 19 | 20 | QString FingerboardCppInterface::getDeviceName() { return _deviceName; } 21 | 22 | QString FingerboardCppInterface::getScanType() { return _scanType; } 23 | 24 | int FingerboardCppInterface::getNumEnrollStages() { return _numEnrollStages; } 25 | 26 | void FingerboardCppInterface::init() { 27 | logger->log(Logger::INFO, QString("Log Location : %1").arg(logger->path())); 28 | logger->log(Logger::INFO, "Initializing Fingerboard"); 29 | 30 | QDBusConnection bus = QDBusConnection::systemBus(); 31 | fprintdInterfaceManager = new net::reactivated::Fprint::Manager( 32 | QString(FPRINTD_SERVICE), QString("/net/reactivated/Fprint/Manager"), bus, 33 | this); 34 | 35 | QDBusPendingReply defaultDevicePathReply = 36 | fprintdInterfaceManager->GetDefaultDevice(); 37 | defaultDevicePathReply.waitForFinished(); 38 | defaultDevicePath = defaultDevicePathReply.value().path(); 39 | 40 | if (defaultDevicePath.size() > 0) { 41 | logger->log( 42 | Logger::DEBUG, 43 | QString("Default Device Object Path : %1").arg(defaultDevicePath)); 44 | 45 | fprintdInterfaceDevice = new net::reactivated::Fprint::Device( 46 | QString(FPRINTD_SERVICE), defaultDevicePath, bus, this); 47 | fprintdDevicePropertiesInterface = new QDBusInterface( 48 | QString(FPRINTD_SERVICE), defaultDevicePath, 49 | QString("org.freedesktop.DBus.Properties"), bus, this); 50 | 51 | connect(fprintdInterfaceDevice, SIGNAL(EnrollStatus(QString, bool)), this, 52 | SLOT(enrollStatusSlot(QString, bool))); 53 | connect(fprintdInterfaceDevice, SIGNAL(VerifyStatus(QString, bool)), this, 54 | SLOT(verifyStatusSlot(QString, bool))); 55 | 56 | deviceInfo(); 57 | listFp(); 58 | } else { 59 | logger->log(Logger::ERROR, appState->errorStatusString( 60 | AppState::ErrorStatus::ERROR_NO_DEVICE)); 61 | appState->raiseError(AppState::ErrorStatus::ERROR_NO_DEVICE); 62 | } 63 | } 64 | 65 | void FingerboardCppInterface::deviceInfo() { 66 | if (claimFpDevice()) { 67 | _deviceName = fprintdDevicePropertiesInterface->call("Get", "", "name") 68 | .arguments() 69 | .at(0) 70 | .value() 71 | .variant() 72 | .toString(); 73 | _scanType = fprintdDevicePropertiesInterface->call("Get", "", "scan-type") 74 | .arguments() 75 | .at(0) 76 | .value() 77 | .variant() 78 | .toString(); 79 | _numEnrollStages = 80 | fprintdDevicePropertiesInterface->call("Get", "", "num-enroll-stages") 81 | .arguments() 82 | .at(0) 83 | .value() 84 | .variant() 85 | .toInt(); 86 | 87 | emit deviceNameChanged(_deviceName); 88 | emit scanTypeChanged(_scanType); 89 | emit numEnrollStagesChanged(_numEnrollStages); 90 | 91 | logger->log(Logger::INFO, QString("-----------")); 92 | logger->log(Logger::INFO, QString("Device Info")); 93 | logger->log(Logger::INFO, QString("-----------")); 94 | logger->log(Logger::INFO, 95 | QString(" Name : %1").arg(_deviceName)); 96 | logger->log(Logger::INFO, QString(" Scan Type : %1").arg(_scanType)); 97 | logger->log(Logger::INFO, 98 | QString(" Enroll Stages : %1").arg(_numEnrollStages)); 99 | 100 | releaseFpDevice(); 101 | } 102 | } 103 | 104 | void FingerboardCppInterface::listFp() { 105 | if (claimFpDevice()) { 106 | logger->log(Logger::VERBOSE, "Start Listing FP"); 107 | logger->log(Logger::INFO, "Listing Fingerprints"); 108 | 109 | emit appState->listingStarted(); 110 | 111 | QDBusPendingReply listEnrolledFingersReply = 112 | fprintdInterfaceDevice->ListEnrolledFingers(username); 113 | listEnrolledFingersReply.waitForFinished(); 114 | 115 | if (listEnrolledFingersReply.error().isValid()) { 116 | logger->log(Logger::ERROR, 117 | QString("%1 : %2") 118 | .arg(listEnrolledFingersReply.error().name()) 119 | .arg(listEnrolledFingersReply.error().message())); 120 | 121 | if (appState->errorStatusFromRawString( 122 | listEnrolledFingersReply.error().name()) == 123 | AppState::ErrorStatus::ERROR_NO_ENROLLED_PRINTS) { 124 | emit enrolledFingerprintsList(QList()); 125 | } else { 126 | appState->raiseError(listEnrolledFingersReply.error().name()); 127 | } 128 | } else { 129 | QStringList rawEnrolledFingersList = listEnrolledFingersReply.value(); 130 | QList enrolledFingers; 131 | 132 | logger->log(Logger::DEBUG, "ENROLLED FINGERPRINTS"); 133 | for (QString finger : rawEnrolledFingersList) { 134 | logger->log(Logger::DEBUG, QString(" - %1").arg(finger)); 135 | enrolledFingers.append(fingerObj->fromName(finger)); 136 | } 137 | 138 | emit enrolledFingerprintsList(enrolledFingers); 139 | } 140 | 141 | logger->log(Logger::VERBOSE, "End Listing FP"); 142 | releaseFpDevice(); 143 | 144 | emit appState->listingCompleted(); 145 | } 146 | } 147 | 148 | void FingerboardCppInterface::enrollFp(int finger) { 149 | if (claimFpDevice()) { 150 | logger->log(Logger::VERBOSE, 151 | QString("Start Enrolling FP : [%1]").arg(finger)); 152 | logger->log(Logger::INFO, "Starting Enrolling Fingerprint"); 153 | 154 | QDBusPendingReply enrollStartReply = 155 | fprintdInterfaceDevice->EnrollStart(fingerObj->rawFingerName(finger)); 156 | enrollStartReply.waitForFinished(); 157 | 158 | if (enrollStartReply.error().isValid()) { 159 | logger->log(Logger::ERROR, QString("%1 : %2") 160 | .arg(enrollStartReply.error().name()) 161 | .arg(enrollStartReply.error().message())); 162 | 163 | appState->raiseError(enrollStartReply.error().name()); 164 | logger->log(Logger::VERBOSE, "End Enrolling FP"); 165 | releaseFpDevice(); 166 | } else { 167 | logger->log(Logger::VERBOSE, "Touch/Swipe to start Enrolling"); 168 | appState->setEnrollStatus(AppState::ENROLL_START); 169 | 170 | emit appState->enrollStarted(); 171 | } 172 | } 173 | } 174 | 175 | void FingerboardCppInterface::verifyFp(QString finger) { 176 | if (claimFpDevice()) { 177 | logger->log(Logger::VERBOSE, 178 | QString("Start Verifying FP : [%1]").arg(finger)); 179 | logger->log(Logger::INFO, "Starting Verifying Fingerprint"); 180 | 181 | QDBusPendingReply verifyStartReply = 182 | fprintdInterfaceDevice->VerifyStart(finger); 183 | verifyStartReply.waitForFinished(); 184 | 185 | if (verifyStartReply.error().isValid()) { 186 | logger->log(Logger::ERROR, QString("%1 : %2") 187 | .arg(verifyStartReply.error().name()) 188 | .arg(verifyStartReply.error().message())); 189 | 190 | appState->raiseError(verifyStartReply.error().name()); 191 | logger->log(Logger::VERBOSE, "End Verifying FP"); 192 | releaseFpDevice(); 193 | } else { 194 | logger->log(Logger::VERBOSE, "Touch/Swipe to continue Verifying"); 195 | appState->setVerifyStatus(AppState::VERIFY_START); 196 | 197 | emit appState->verifyStarted(); 198 | } 199 | } 200 | } 201 | 202 | void FingerboardCppInterface::deleteFp() { 203 | if (claimFpDevice()) { 204 | logger->log(Logger::VERBOSE, "Start Deleting FP"); 205 | logger->log(Logger::INFO, "Deleting Fingerprints"); 206 | 207 | emit appState->deleteStarted(); 208 | 209 | logger->log( 210 | Logger::INFO, 211 | QString("Deleting all fingerprints of user [%1] for device [%2]") 212 | .arg(username) 213 | .arg(defaultDevicePath)); 214 | 215 | QDBusPendingReply deleteEnrolledFingers2Reply = 216 | fprintdInterfaceDevice->DeleteEnrolledFingers2(); 217 | deleteEnrolledFingers2Reply.waitForFinished(); 218 | 219 | if (deleteEnrolledFingers2Reply.error().isValid()) { 220 | logger->log(Logger::ERROR, 221 | QString("%1 : %2") 222 | .arg(deleteEnrolledFingers2Reply.error().name()) 223 | .arg(deleteEnrolledFingers2Reply.error().message())); 224 | appState->raiseError(deleteEnrolledFingers2Reply.error().name()); 225 | } 226 | 227 | logger->log(Logger::VERBOSE, "End Deleting FP"); 228 | releaseFpDevice(); 229 | 230 | emit appState->deleteCompleted(); 231 | } 232 | } 233 | 234 | void FingerboardCppInterface::enrollStatusSlot(QString result, bool done) { 235 | logger->log( 236 | Logger::DEBUG, 237 | QString("ENROLL STATUS : %1, ENROLL DONE : %2").arg(result).arg(done)); 238 | 239 | appState->setEnrollStatus(appState->enrollStatusFromRawString(result)); 240 | 241 | if (result == "enroll-completed" || result == "enroll-failed" || 242 | result == "enroll-data-full" || result == "enroll-unknown-error" || 243 | done) { 244 | QDBusPendingReply enrollStopReply = fprintdInterfaceDevice->EnrollStop(); 245 | enrollStopReply.waitForFinished(); 246 | logger->log(Logger::INFO, 247 | QString("Enroll Ended with status [%1]").arg(result)); 248 | logger->log(Logger::VERBOSE, "End Enrolling FP"); 249 | releaseFpDevice(); 250 | 251 | if (result == "enroll-completed") { 252 | emit appState->enrollCompleted(); 253 | } else { 254 | emit appState->enrollErrored(); 255 | } 256 | } 257 | } 258 | 259 | void FingerboardCppInterface::verifyStatusSlot(QString result, bool done) { 260 | logger->log( 261 | Logger::DEBUG, 262 | QString("VERIFY STATUS : %1, VERIFY DONE : %2").arg(result).arg(done)); 263 | 264 | appState->setVerifyStatus(appState->verifyStatusFromRawString(result)); 265 | 266 | if (result == "verify-no-match" || result == "verify-match" || 267 | result == "verify-unknown-error" || done) { 268 | QDBusPendingReply verifyStopReply = fprintdInterfaceDevice->VerifyStop(); 269 | verifyStopReply.waitForFinished(); 270 | logger->log(Logger::INFO, 271 | QString("Verify Ended with status [%1]").arg(result)); 272 | logger->log(Logger::VERBOSE, "End Verifying FP"); 273 | releaseFpDevice(); 274 | 275 | if (result == "verify-match") { 276 | emit appState->verifyCompleted(); 277 | } else { 278 | emit appState->verifyErrored(); 279 | } 280 | } 281 | } 282 | 283 | bool FingerboardCppInterface::claimFpDevice() { 284 | logger->log(Logger::DEBUG, "Claiming Fingerprint Device"); 285 | 286 | if (defaultDevicePath.size() <= 0) { 287 | logger->log(Logger::ERROR, appState->errorStatusString( 288 | AppState::ErrorStatus::ERROR_NO_DEVICE)); 289 | appState->raiseError(AppState::ErrorStatus::ERROR_NO_DEVICE); 290 | 291 | return false; 292 | } else { 293 | QDBusPendingReply claimReply = fprintdInterfaceDevice->Claim(QString()); 294 | claimReply.waitForFinished(); 295 | 296 | if (claimReply.error().isValid()) { 297 | logger->log(Logger::ERROR, QString("%1 : %2") 298 | .arg(claimReply.error().name()) 299 | .arg(claimReply.error().message())); 300 | 301 | appState->raiseError(claimReply.error().name()); 302 | return false; 303 | } 304 | } 305 | 306 | return true; 307 | } 308 | 309 | void FingerboardCppInterface::releaseFpDevice() { 310 | logger->log(Logger::DEBUG, "Releasing Fingerprint Device"); 311 | 312 | QDBusPendingReply releaseReply = fprintdInterfaceDevice->Release(); 313 | 314 | if (releaseReply.error().isValid()) { 315 | logger->log(Logger::ERROR, QString("%1 : %2") 316 | .arg(releaseReply.error().name()) 317 | .arg(releaseReply.error().message())); 318 | 319 | appState->raiseError(releaseReply.error().name()); 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /src/fprintd-dbus-interface-xml/fprintddevice.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ]> 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | PolicyKit integration 21 | 22 | 23 | fprintd uses PolicyKit to check whether users are allowed to access fingerprint data, or the 24 | fingerprint readers itself. 25 | 26 | 27 | net.reactivated.fprint.device.verify 28 | 29 | Whether the user is allowed to verify fingers against saved fingerprints. 30 | 31 | 32 | 33 | net.reactivated.fprint.device.enroll 34 | 35 | Whether the user is allowed to enroll new fingerprints. 36 | 37 | 38 | 39 | net.reactivated.fprint.device.setusername 40 | 41 | Whether the user is allowed to query, verify, or enroll fingerprints for users other than itself. 42 | 43 | 44 | 45 | 46 | 47 | 48 | Usernames 49 | 50 | 51 | When a username argument is used for a method, a PolicyKit check is done on the 52 | net.reactivated.fprint.device.setusername PolicyKit 53 | action to see whether the user the client is running as is allowed to access data from other users. 54 | 55 | 56 | By default, only root is allowed to access fingerprint data for users other than itself. For a normal user, 57 | it is recommended that you use an empty string for the username, which will mean "the client the user is 58 | running as". 59 | 60 | 61 | See PolicyKit integration. 62 | 63 | 64 | 65 | Fingerprint names 66 | 67 | 68 | When a finger name argument is used for a method, it refers to either a single finger, or 69 | "any" finger. See the list of possible values below: 70 | 71 | 72 | left-thumb 73 | 74 | Left thumb 75 | 76 | 77 | 78 | left-index-finger 79 | 80 | Left index finger 81 | 82 | 83 | 84 | left-middle-finger 85 | 86 | Left middle finger 87 | 88 | 89 | 90 | left-ring-finger 91 | 92 | Left ring finger 93 | 94 | 95 | 96 | left-little-finger 97 | 98 | Left little finger 99 | 100 | 101 | 102 | right-thumb 103 | 104 | Right thumb 105 | 106 | 107 | 108 | right-index-finger 109 | 110 | Right index finger 111 | 112 | 113 | 114 | right-middle-finger 115 | 116 | Right middle finger 117 | 118 | 119 | 120 | right-ring-finger 121 | 122 | Right ring finger 123 | 124 | 125 | 126 | right-little-finger 127 | 128 | Right little finger 129 | 130 | 131 | 132 | any 133 | 134 | Any finger. This is only used for Device.VerifyStart 135 | (select the first finger with a fingerprint associated, or all the fingerprints available for the user when 136 | the device supports it) and Device::VerifyFingerSelected 137 | (any finger with an associated fingerprint can be used). 138 | 139 | 140 | 141 | 142 | 143 | 144 | Verify Statuses 145 | 146 | 147 | 148 | Possible values for the result passed through Device::VerifyResult are: 149 | 150 | verify-no-match 151 | 152 | The verification did not match, Device.VerifyStop should now be called. 153 | 154 | 155 | 156 | verify-match 157 | 158 | The verification succeeded, Device.VerifyStop should now be called. 159 | 160 | 161 | 162 | verify-retry-scan 163 | 164 | The user should retry scanning their finger, the verification is still ongoing. 165 | 166 | 167 | 168 | verify-swipe-too-short 169 | 170 | The user's swipe was too short. The user should retry scanning their finger, the verification is still ongoing. 171 | 172 | 173 | 174 | verify-finger-not-centered 175 | 176 | The user's finger was not centered on the reader. The user should retry scanning their finger, the verification is still ongoing. 177 | 178 | 179 | 180 | verify-remove-and-retry 181 | 182 | The user should remove their finger from the reader and retry scanning their finger, the verification is still ongoing. 183 | 184 | 185 | 186 | verify-disconnected 187 | 188 | The device was disconnected during the verification, no other actions should be taken, and you shouldn't use the device any more. 189 | 190 | 191 | 192 | verify-unknown-error 193 | 194 | An unknown error occurred (usually a driver problem), Device.VerifyStop should now be called. 195 | 196 | 197 | 198 | 199 | 200 | 201 | Enroll Statuses 202 | 203 | 204 | 205 | Possible values for the result passed through Device::EnrollResult are: 206 | 207 | enroll-completed 208 | 209 | The enrollment successfully completed, Device.EnrollStop should now be called. 210 | 211 | 212 | 213 | enroll-failed 214 | 215 | The enrollment failed, Device.EnrollStop should now be called. 216 | 217 | 218 | 219 | enroll-stage-passed 220 | 221 | One stage of the enrollment passed, the enrollment is still ongoing. 222 | 223 | 224 | 225 | enroll-retry-scan 226 | 227 | The user should retry scanning their finger, the enrollment is still ongoing. 228 | 229 | 230 | 231 | enroll-swipe-too-short 232 | 233 | The user's swipe was too short. The user should retry scanning their finger, the enrollment is still ongoing. 234 | 235 | 236 | 237 | enroll-finger-not-centered 238 | 239 | The user's finger was not centered on the reader. The user should retry scanning their finger, the enrollment is still ongoing. 240 | 241 | 242 | 243 | enroll-remove-and-retry 244 | 245 | The user should remove their finger from the reader and retry scanning their finger, the enrollment is still ongoing. 246 | 247 | 248 | 249 | enroll-data-full 250 | 251 | No further prints can be enrolled on this device, Device.EnrollStop should now be called. 252 | 253 | Delete other prints from the device first to continue 254 | (e.g. from other users). Note that old prints or prints from other operating systems may be deleted automatically 255 | to resolve this error without any notification. 256 | 257 | 258 | 259 | enroll-disconnected 260 | 261 | The device was disconnected during the enrollment, no other actions should be taken, and you shouldn't use the device any more. 262 | 263 | 264 | 265 | 266 | enroll-unknown-error 267 | 268 | An unknown error occurred (usually a driver problem), Device.EnrollStop should now be called. 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | The username for whom to list the enrolled fingerprints. See Usernames. 281 | 282 | 283 | An array of strings representing the enrolled fingerprints. See Fingerprint names. 284 | 285 | 286 | 287 | 288 | 289 | 290 | List all the enrolled fingerprints for the chosen user. 291 | 292 | 293 | 294 | 295 | if the caller lacks the appropriate PolicyKit authorization 296 | if the chosen user doesn't have any fingerprints enrolled 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | The username for whom to delete the enrolled fingerprints. See Usernames. 306 | 307 | 308 | 309 | 310 | 311 | 312 | Delete all the enrolled fingerprints for the chosen user. 313 | 314 | 315 | This call only exists for compatibility reasons, you should instead claim the device using 316 | Device.Claim and then call 317 | DeleteEnrolledFingers2. 318 | 319 | 320 | 321 | 322 | if the caller lacks the appropriate PolicyKit authorization 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | Delete all the enrolled fingerprints for the user currently claiming the device with Device.Claim. 336 | 337 | 338 | 339 | 340 | if the caller lacks the appropriate PolicyKit authorization 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | The username for whom to claim the device. See Usernames. 350 | 351 | 352 | 353 | 354 | 355 | 356 | Claim the device for the chosen user. 357 | 358 | 359 | 360 | 361 | if the caller lacks the appropriate PolicyKit authorization 362 | if the device is already claimed 363 | if the device couldn't be claimed 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | Release a device claimed with Device.Claim. 377 | 378 | 379 | 380 | 381 | if the caller lacks the appropriate PolicyKit authorization 382 | if the device was not claimed 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | A string representing the finger to verify. See Fingerprint names. 392 | 393 | 394 | 395 | 396 | 397 | 398 | Check the chosen finger against a saved fingerprint. You need to have claimed the device using 399 | Device.Claim. The finger selected is sent to the front-end 400 | using Device::VerifyFingerSelected and 401 | verification status through Device::VerifyStatus. 402 | 403 | 404 | 405 | 406 | if the caller lacks the appropriate PolicyKit authorization 407 | if the device was not claimed 408 | if the device was already being used 409 | if there are no enrolled prints for the chosen user 410 | if there was an internal error 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | Stop an on-going fingerprint verification started with Device.VerifyStart. 424 | 425 | 426 | 427 | 428 | if the caller lacks the appropriate PolicyKit authorization 429 | if the device was not claimed 430 | if there was no ongoing verification 431 | if there was an internal error 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | A string representing the finger select to be verified. 444 | 445 | 446 | 447 | 448 | 449 | 450 | Fingerprint names. 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | A string representing the status of the verification. 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | Whether the verification finished and can be stopped. 470 | 471 | 472 | 473 | 474 | 475 | 476 | Verify Statuses and Device.VerifyStop. 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | A string representing the finger to enroll. See 486 | Fingerprint names. 487 | Note that "any" is not a valid finger name for this method. 488 | 489 | 490 | 491 | 492 | 493 | 494 | Start enrollment for the selected finger. You need to have claimed the device using 495 | Device.Claim before calling 496 | this method. Enrollment status is sent through Device::EnrollStatus. 497 | 498 | 499 | 500 | 501 | if the caller lacks the appropriate PolicyKit authorization 502 | if the device was not claimed 503 | if the device was already being used 504 | if the finger name passed is invalid 505 | if there was an internal error 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | Stop an on-going fingerprint enrollment started with Device.EnrollStart. 520 | 521 | 522 | 523 | 524 | if the caller lacks the appropriate PolicyKit authorization 525 | if the device was not claimed 526 | if there was no ongoing verification 527 | if there was an internal error 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | A string representing the status of the enrollment. 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | Whether the enrollment finished and can be stopped. 547 | 548 | 549 | 550 | 551 | 552 | 553 | Enrollment Statuses and Device.EnrollStop. 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | The product name of the device. 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | The number of enrollment stages for the device. This is only available when the device has been claimed, otherwise it will be undefined (-1). 577 | 578 | 579 | Device.Claim and Device.EnrollStart. 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | The scan type of the device, either "press" if you place your finger on the device, or "swipe" if you have to swipe your finger. 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | --------------------------------------------------------------------------------