#include "DeviceScreener.h" #include #include #include #include #include #include #include #include DeviceScreener::DeviceScreener(QObject *parent) : QObject(parent) { } DeviceScreener::~DeviceScreener() = default; void DeviceScreener::start() { // qDebug() << "Worker started in thread:" << QThread::currentThread(); while (m_running) { QList> devices = readAdbDevices(); QStringList onlineIds; for (const auto&[id, status] : devices) { // qDebug() << "Id:" << id << ", Status:" << status; DeviceInfo device; device.id = id; if (status == "device") { onlineIds << device.id; device = readDeviceInfo(id); takeScreenshot(id); } device.status = status; device.updateTime = QDateTime::currentDateTime(); // qDebug() << "Update device: " << DeviceDAO::upsertDevice(device); } // qDebug() << "All devices offline: " << DeviceDAO::markDevicesOfflineExcept(onlineIds); QThread::sleep(3); } emit finished(); } QByteArray convertPngToJpeg(const QByteArray& pngData, const int quality = 90) { QImage image; if (!image.loadFromData(pngData, "PNG")) { qWarning() << "Не удалось загрузить PNG из байт"; return {}; } // if (!image.save("test.jpg", "JPG", quality)) { // qWarning() << "Не удалось сохранить как JPG:" << "test.jpg"; // return {}; // } QByteArray jpgData; QBuffer buffer(&jpgData); buffer.open(QIODevice::WriteOnly); image.save(&buffer, "JPG", quality); return jpgData; } bool DeviceScreener::takeScreenshot(const QString& deviceId) { QProcess process; QStringList arguments; arguments << "-s" << deviceId << "exec-out" << "screencap" << "-p"; process.start("adb", arguments); if (!process.waitForFinished(5000)) { qWarning() << "ADB скриншот не завершился для" << deviceId; return false; } const QByteArray imageData = process.readAllStandardOutput(); if (imageData.isEmpty()) { qWarning() << "Скриншот пустой для " << deviceId; return false; } // Обновляем изображение в БД if (!DeviceDAO::updateImage(deviceId, convertPngToJpeg(imageData, 90))) { qWarning() << "Не удалось записать изображение в БД для" << deviceId; return false; } qDebug() << "Screenshot saved, device: " << deviceId; return true; } QList> DeviceScreener::readAdbDevices() { QProcess process; process.start("adb", QStringList() << "devices"); process.waitForFinished(); const QString output = process.readAllStandardOutput(); // qDebug() << "[adb devices output]:\n" << output; QList> devices; const QStringList lines = output.split('\n'); for (int i = 1; i < lines.size(); ++i) { QString line = lines.at(i).trimmed(); if (line.isEmpty()) { continue; } /** * device — устройство готово к использованию. * offline — устройство подключено, но не может быть использовано. * unauthorized — устройство не авторизовано для работы с ADB (нужно подтвердить запрос на подключение на самом устройстве). * recovery — устройство в режиме восстановления. */ // Разделяем строку на id и type по табуляции if (QStringList parts = line.split('\t'); parts.size() == 2) { const QString& id = parts.at(0); const QString& status = parts.at(1); devices.append(qMakePair(id, status)); } } return devices; } static const QRegularExpression screenRegex(R"(Physical size: (\d+)x(\d+))"); static const QRegularExpression batteryRegex(R"(level:\s*(\d+))"); DeviceInfo DeviceScreener::readDeviceInfo(const QString& deviceId) { DeviceInfo info; info.id = deviceId; info.screenWidth = 0; info.screenHeight = 0; info.battery = 0; auto runAdbCommand = [&](const QStringList& args) -> QString { QProcess process; process.start("adb", QStringList{"-s", deviceId} + args); process.waitForFinished(); return QString::fromUtf8(process.readAllStandardOutput()).trimmed(); }; info.name = runAdbCommand({"shell", "getprop", "ro.product.model"}); info.android = runAdbCommand({"shell", "getprop", "ro.build.version.release"}); // Размер экрана const QString screenOutput = runAdbCommand({"shell", "wm", "size"}); QRegularExpressionMatch match = screenRegex.match(screenOutput); if (match.hasMatch()) { info.screenWidth = match.captured(1).toInt(); info.screenHeight = match.captured(2).toInt(); } // Уровень батареи const QString batteryOutput = runAdbCommand({"shell", "dumpsys", "battery"}); match = batteryRegex.match(batteryOutput); if (match.hasMatch()) { info.battery = match.captured(1).toInt(); } info.updateTime = QDateTime::currentDateTime(); return info; } void DeviceScreener::stop() { m_running = false; }