1
0
forked from BRT/arc
arc/services/DeviceScreener.cpp
slava c3fed927fc Remove macOS-specific Scrcpy embedding and cleanup debug logs
Removed Scrcpy embedding code and related configurations for macOS. Commented out excessive debug logging in multiple files to reduce console noise. Simplified CMakeLists.txt by unifying platform-specific sections for improved build system clarity.
2025-04-26 15:16:42 +07:00

165 lines
5.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "DeviceScreener.h"
#include <QRegularExpression>
#include <QProcess>
#include <QFile>
#include <QBuffer>
#include <QThread>
#include <QImage>
#include <dao/DeviceDAO.h>
#include <db/DeviceInfo.h>
DeviceScreener::DeviceScreener(QObject *parent) : QObject(parent) {
}
DeviceScreener::~DeviceScreener() = default;
void DeviceScreener::start() {
// qDebug() << "Worker started in thread:" << QThread::currentThread();
while (m_running) {
QList<QPair<QString, QString>> 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<QPair<QString, QString>> DeviceScreener::readAdbDevices() {
QProcess process;
process.start("adb", QStringList() << "devices");
process.waitForFinished();
const QString output = process.readAllStandardOutput();
// qDebug() << "[adb devices output]:\n" << output;
QList<QPair<QString, QString>> 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;
}