#include "upgradeapkdialog.h" #include "gutil/qcore.h" #include "gutil/qgui.h" #include "gutil/qnetwork.h" #include "gutil/qwaitingdlg.h" #include "devicepanel.h" #include "deviceitem.h" #include #include #include #include #include #include #include #include #include #include #include UpgradeApkDialog::UpgradeApkDialog(QWidget *parent) : QDialog(parent) { resize(1280, 720); setWindowFlag(Qt::WindowMaximizeButtonHint); setWindowTitle(tr("Update APK")); auto vBox = new VBox(this); vBox->setContentsMargins(6, 0, 6, 0); auto hBox = new HBox(vBox); auto btnSelectOnlineApk = new QPushButton(tr("Select Online APK")); hBox->addWidget(btnSelectOnlineApk); auto btnSelectApk = new QPushButton(tr("Select apk")); hBox->addWidget(btnSelectApk); auto btnSelectFpga = new QPushButton(tr("Select Fpga")); hBox->addWidget(btnSelectFpga); auto fdFileName = new QLineEdit; fdFileName->setReadOnly(true); fdFileName->setMinimumWidth(200); hBox->addWidget(fdFileName); connect(btnSelectApk, &QPushButton::clicked, this, [=] { auto aaa = QFileDialog::getOpenFileName(this, "Open file", gApkHome, "apk package (*.apk *.zip)"); if(aaa.isEmpty()) return; QFileInfo info(filePath = aaa); gApkHome = info.absolutePath(); fdFileName->setText(info.fileName()); fileId = ""; }); connect(btnSelectFpga, &QPushButton::clicked, this, [=] { auto aaa = QFileDialog::getOpenFileName(this, "Open File", gApkHome, "rpd package (*.rpd)"); if(aaa.isEmpty()) return; QFileInfo info(filePath = aaa); gApkHome = info.absolutePath(); fdFileName->setText(info.fileName()); fileId = ""; }); connect(btnSelectOnlineApk, &QPushButton::clicked, this, [=] { NetReq req("https://www.ledokcloud.com/aips4/screen/upgrade/getGeneric?type=0&page=1&limit=10"); req.setRawHeader("token","e183653f716cb150ebf3b4f8a83c95e7"); auto reply = req.timeout(60000).post(""); ConnReply(reply, this) [=] { JValue json; auto err = errStrWithData(reply, &json); if(! err.isEmpty()) { QMessageBox::critical(this, "Error", err); return; } if(json["code"].toInt()) { QMessageBox::critical(this, "Error", json["msg"].toString()); return; } auto files = json["page"]["list"].toArray(); if(files.empty()) { QMessageBox::critical(this, "Error", tr("No Files")); return; } QDialog dlg(this); #ifdef Q_OS_WIN dlg.setWindowFlag(Qt::WindowContextHelpButtonHint, 0); #endif dlg.setWindowTitle(tr("Select Online APK")); dlg.resize(800, 500); auto vBox = new VBox(&dlg); vBox->setContentsMargins(0,0,0,0); auto table = new TreeWidget; table->addCol("#", "", 20); table->addCol("name", tr("Name"), 200, QHeaderView::Stretch); table->addCol("size", tr("Size"), 80).alignR().margin(4); table->addCol("createTime", tr("Create Time"), 150).margin(2); table->setDefs()->setHeaderAlignC(); table->minRowHeight = 28; for(auto &file : files) { auto item = new TreeWidgetItem(table); item->setText("name", file["fileName"].toString()+"."+file["suffix"].toString()); item->setText("size", byteSizeStr(file["fileSize"].toInt())); item->setText("createTime", file["createTime"].toString()); item->setData(0, file["fileId"].toString()); } connect(table, &TreeWidget::itemDoubleClicked, &dlg, [=, &dlg](QTreeWidgetItem *itm) { auto item = (TreeWidgetItem*) itm; fdFileName->setText(item->text("name")); fileId = item->data(0).toString(); filePath = ""; dlg.accept(); }); vBox->addWidget(table); auto btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Close); connect(btnBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject); connect(btnBox, &QDialogButtonBox::accepted, &dlg, [=, &dlg] { auto item = table->selectedItem(); if(item==0) { QMessageBox::warning(&dlg, "Warning", tr("Please select a file")); return; } fdFileName->setText(item->text("name")); fileId = item->data(0).toString(); filePath = ""; dlg.accept(); }); vBox->addWidget(btnBox); dlg.exec(); }); }); auto btnUpdate = new QPushButton(tr("Upgrade")); connect(btnUpdate, &QPushButton::clicked, this, [=] { auto fileName = fdFileName->text(); if(fileName.length() < 3) return; int cnt = table->topLevelItemCount(); QList items; UpdateApkItem *item; for(int rr=0; rrtopLevelItem(rr))->isHidden() && item->checkState("id") == Qt::Checked && ! item->isUpdating) { if(item->isLocked) item->setResult(tr("This screen is encrypted"), Qt::red); else items.append(item); } if(items.isEmpty()) { QMessageBox::information(this, tr("Tip"), tr("NoSelectedController")); return; } QByteArray fileData; if(! filePath.isEmpty()) { QFile file(filePath); if(! file.exists()) return; if(! file.open(QIODevice::ReadOnly)) return; fileData = file.readAll(); file.close(); if(fileData.size() != file.size()) { QMessageBox::information(this, tr("Tip"), tr("File Read Fail")); return; } } else if(! fileId.isEmpty()) { auto waitingDlg = new WaitingDlg(this, tr("Downloading Online File")+" ..."); waitingDlg->show(); auto reply = NetReq("https://www.ledokcloud.com/aips4/sys/file/download/"+fileId).timeout(60000).get(); connect(reply, &QNetworkReply::downloadProgress, waitingDlg, [=](qint64 bytesReceived, qint64 bytesTotal) { if(bytesTotal==0) return; waitingDlg->fdText->setText(tr("Downloading Online File")+" "+QString::number(bytesReceived*100/bytesTotal)+" %"); }); if(waitFinished(reply, waitingDlg)) return; waitingDlg->close(); auto err = errStr(reply); fileData = reply->readAll(); if(! err.isEmpty()) { if(! fileData.isEmpty()) err += "\n"+fileData; QMessageBox::critical(this, tr("Error"), err); return; } if(fileData.isEmpty()) { QMessageBox::critical(this, tr("Error"), tr("Online file is empty")); return; } } else { QMessageBox::critical(this, tr("Error"), tr("File is empty")); return; } auto nameBytes = fileName.toUtf8(); auto Boundary = "----QtLedOK_.oOo._"+QUuid::createUuid().toByteArray(QUuid::WithoutBraces); QByteArray data; data.append("--").append(Boundary).append("\r\nContent-Disposition: form-data; name=\"username\"\r\n\r\n10005\r\n"); data.append("--").append(Boundary).append("\r\nContent-Disposition: form-data; name=\"").append(nameBytes).append("\"; filename=\"").append(nameBytes).append("\"\r\n\r\n").append(fileData).append("\r\n"); data.append("--").append(Boundary).append("--\r\n"); bool isApk = ! fileName.endsWith(".rpd", Qt::CaseInsensitive); for(auto item : items) { item->isUpdating = true; item->setResult(tr("Uploading")+" ..."); item->fdProgress->setValue(0); NetReq req("http://"+item->text("ip")+":2016/upload?type="+(isApk ? "software":"hardware")); auto reply = req.timeout(60000).type("multipart/form-data; boundary="+Boundary).post(data); connect(reply, &QNetworkReply::uploadProgress, item, [item](qint64 bytesSent, qint64 bytesTotal) { if(bytesTotal==0) return; item->fdProgress->setValue(bytesSent*100/bytesTotal); }); ConnReply(reply, item) [=] { auto err = errStrWithData(reply); if(! err.isEmpty()) { item->setResult(tr("Upload error")+": "+err, Qt::red); item->isUpdating = false; return; } item->fdProgress->setValue(100); auto info = tr("Upgrading")+" ..."; QJsonObject json; if(isApk) { json.insert("_id", "UpgradeSoftware"); json.insert("_type", "UpgradeSoftware"); json.insert("fileName", fileName); json.insert("isCustom", true); } else { info += " ("+tr("Don't power off during this process")+")"; json.insert("_id", "SynchronousHardwareVersion"); json.insert("_type", "SynchronousHardwareVersion"); } item->setResult(info); auto reply = NetReq("http://"+item->text("ip")+":2016/settings").timeout(60000).post(json); ConnReply(reply, item) [=] { if(item->treeWidget()==0) return; QJsonDocument json; auto err = checkReplyForJson(reply, &json); if(! err.isEmpty()) { item->isUpdating = false; item->setResult(tr("Install error")+": "+err, Qt::red); return; } if(isApk || ! json["hasProgress"].toBool()) { item->isUpdating = false; item->setResult(tr("Install Success"), Qt::darkGreen); if(isApk) item->OnCheckSoftVersions(1); else item->OnCheckFpgaVersions(); } else { sendProgress(item); item->fdProgress->setValue(0); } }); }); } }); hBox->addWidget(btnUpdate); hBox->addStretch(); hBox->addWidget(new QLabel("APK:")); auto fdApk = new QComboBox; fdApk->setEditable(true); fdApk->addItem("com.xixun.xixunplayer"); fdApk->addItem("com.xixun.joey.cardsystem"); fdApk->addItem("com.xixun.joey.systemcore"); fdApk->addItem("net.sysolution.taxiapp"); fdApk->addItem("net.sysolution.starter"); fdApk->addItem("com.xixun.display"); fdApk->addItem("com.xixun.xy.conn"); fdApk->addItem("com.xixun.xy.update"); fdApk->addItem("net.sysolution.basicapp"); hBox->addWidget(fdApk); auto btnUninstall = new QPushButton(tr("Uninstall")); connect(btnUninstall, &QPushButton::clicked, this, [this, fdApk] { auto strApkName = fdApk->currentText(); if(strApkName.isEmpty()) { QMessageBox::information(this, tr("Tip"), "APK is Empty"); return; } if(! strApkName.endsWith(".xixunplayer") && ! strApkName.endsWith(".taxiapp") && QMessageBox::warning(this, tr("Reminder"), tr("Reminder: Uninstalling this program may cause the device to offline, cannot be found, lost configs and have a black screen. Please uninstall with caution!")+"\n"+tr("Do you want to continue?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) return; int cnt = table->topLevelItemCount(); for(int i=0; iitem(i)->checkState("id") == Qt::Checked) { auto item = (UpdateApkItem *) table->topLevelItem(i); item->setResult(tr("Uninstalling")+" ..."); QJsonObject json; json.insert("_id", "UninstallSoftware"); json.insert("_type", "UninstallSoftware"); json.insert("packageName", strApkName); auto reply = NetReq("http://"+item->text("ip")+":2016/settings").timeout(60000).post(json); ConnReply(reply, item) [reply, item, strApkName] { QString err = checkReplyForJson(reply, "error"); if(! err.isEmpty()) { item->setResult(tr("Uninstall error")+": "+err, Qt::red); return; } item->setResult(tr("Uninstall success"), Qt::darkGreen); }); } }); hBox->addWidget(btnUninstall); auto btnCheck = new QPushButton(tr("check running state")); connect(btnCheck, &QPushButton::clicked, this, [this, fdApk] { QString strApkName = fdApk->currentText(); int cnt = table->topLevelItemCount(); for(int i=0; iitem(i)->checkState("id") == Qt::Checked) { auto item = (UpdateApkItem *) table->topLevelItem(i); item->setResult(tr("Check apk running status")); QJsonObject json; json.insert("_id", "IsSoftwareRunning"); json.insert("_type", "IsSoftwareRunning"); json.insert("packageName", strApkName); auto reply = NetReq("http://"+item->text("ip")+":2016/settings").timeout(60000).post(json); ConnReply(reply, item) [reply, item, strApkName] { QJsonDocument json; auto err = errStrWithData(reply, &json); if(! err.isEmpty()) { item->setResult(tr("Check error")+": "+err, Qt::red); return; } if(json["running"].toBool()) item->setResult(tr("Running"), Qt::darkGreen); else item->setResult(tr("Not running"), Qt::red); }); } }); hBox->addWidget(btnCheck); hBox = new HBox(vBox); auto label = new QLabel; hBox->addWidget(label); hBox->addStretch(); auto btnRefresh = new QPushButton(tr("Refresh")); connect(btnRefresh, &QPushButton::clicked, this, [=] { table->clear(); table->fdCheckAll->setCheckState(Qt::Unchecked); int cnt = gDevicePanel->mDeviceTable->topLevelItemCount(); for(int cc=0; ccmDeviceTable->topLevelItem(cc))->mCard; int cnt = table->topLevelItemCount(); UpdateApkItem* item; for(int rr=0; rrtopLevelItem(rr))->text("id") == card.id) goto end; item = new UpdateApkItem(table); item->setFlags(item->flags() & ~Qt::ItemIsUserCheckable); item->setCheckState("id", Qt::Unchecked); item->setText("id", card.id); { item->fdOnline = new QLabel; item->fdOnline->setScaledContents(true); item->fdOnline->setFixedSize(24, 24); auto wgt = new QWidget; auto hhh = new HBox(wgt); hhh->setContentsMargins(0,0,0,0); hhh->addWidget(item->fdOnline); item->setCellWidget("online", wgt); } item->fdProgress = new QProgressBar; item->fdProgress->setAlignment(Qt::AlignCenter); item->fdProgress->setStyleSheet("QProgressBar {margin-top: 6px; margin-bottom: 6px;}"); item->setCellWidget("progress", item->fdProgress); end: item->setText("ip", card.ip); item->setText("alias", card.alias); item->setText("firmware", card.firmwareVer); item->fdOnline->setPixmap({card.isOnline ? ":/res/online.png" : ":/res/offline.png"}); item->OnCheckSoftVersions(); item->OnCheckFpgaVersions(); if(! card.hasPassword) { item->isLocked = false; item->setCellWidget("encrypt", item->btnUnlock = 0); } else { item->isLocked = card.isLocked; if(item->btnUnlock==0) { item->btnUnlock = new QPushButton; item->btnUnlock->setMaximumHeight(36); item->setCellWidget("encrypt", item->btnUnlock); connect(item->btnUnlock, &QPushButton::clicked, item, [=] { if(! item->isLocked) return; bool ok; auto pwd = QInputDialog::getText(this, tr("Input password"), tr("Input password"), QLineEdit::Password, QString(), &ok); if(! ok) return; QJsonObject json; json.insert("_id", "VerifyPassword"); json.insert("_type", "VerifyPassword"); json.insert("pwd", pwd); auto waitingDlg = new WaitingDlg(item->btnUnlock, tr("VerifyPassword")+" ..."); waitingDlg->show(); auto reply = NetReq("http://"+card.ip+":2016/settings").timeout(30000).post(json); ConnReply(reply, waitingDlg) [=] { QJsonDocument json; auto err = checkReplyForJson(reply, &json); if(! err.isEmpty()) { waitingDlg->close(); QMessageBox::critical(this, tr("Error"), err); return; } if(! json["result"].toBool()) { waitingDlg->close(); QMessageBox::warning(this, tr("Tip Info"), tr("password is wrong")); return; } waitingDlg->success(); item->isLocked = false; item->btnUnlock->setIcon(QIcon(":/res/UnLock.png")); auto item = findItem(card.id); if(item) { item->mCard.isLocked = false; item->btnUnlock->setIcon(QIcon(":/res/UnLock.png")); } }); }); } item->btnUnlock->setIcon(QIcon(card.isLocked ? ":/res/Lock.png" : ":/res/UnLock.png")); //已验证显示绿色 没验证蓝色 } } label->setText(tr("All")+": "+QString::number(cnt)); }); hBox->addWidget(btnRefresh); auto fdSearch = new QLineEdit; fdSearch->setClearButtonEnabled(true); fdSearch->setMaximumWidth(160); fdSearch->addAction(new QAction(QIcon(":/res/program/bnSearch.png"), ""), QLineEdit::LeadingPosition); connect(fdSearch, &QLineEdit::textChanged, this, [this](const QString &text) { auto cnt = table->topLevelItemCount(); if(text.isEmpty()) { for(int rr=0; rritem(rr)->setHidden(false); return; } bool isEmpty = true; for(int rr=0; rritem(rr); bool contain = item->text("id").contains(text) || item->text("alias").contains(text) || item->text("remarks").contains(text) || item->text("ip").contains(text); item->setHidden(! contain); if(contain) isEmpty = false; } if(isEmpty) for(int rr=0; rritem(rr); item->setHidden(! (item->text("playerVer").contains(text) || item->text("cardsystem").contains(text) || item->text("starter").contains(text) || item->text("taxiapp").contains(text) || item->text("displayer").contains(text) || item->text("fpga").contains(text) || item->text("connection").contains(text) || item->text("update").contains(text) )); } }); hBox->addWidget(fdSearch); table = new LoQTreeWidget; table->addCol("#", "", 20); table->addCol("id", "ID", 125).margin(4); table->addCol("online", tr("Online"), 40); table->addCol("ip", "IP", 95); table->addCol("alias", tr("Alias"), 80); table->addCol("encrypt", tr("Security"), 40); table->addCol("progress", tr("Progress"), 100); table->addCol("remarks", tr("State"), 200); table->addCol("playerVer", "XixunPlayer", 70); table->addCol("cardsystem", "cardsystem", 70); table->addCol("starter", "starter", 70); table->addCol("taxiapp", "taxiapp", 70); table->addCol("displayer", "displayer", 70); table->addCol("fpga", "FPGA", 70); table->addCol("connection", "connection", 70); table->addCol("update", "update", 40); table->addCol("firmware", "Firmware", 100); table->setDefs()->setHeaderAlignC(); table->addFd(); table->setSelectionMode(QAbstractItemView::NoSelection); table->setSortingEnabled(true); vBox->addWidget(table); auto sortField = gDevicePanel->mDeviceTable->sortField(); if(sortField=="id" || sortField=="ip" || sortField=="alias") table->sortItems(sortField, gDevicePanel->mDeviceTable->header()->sortIndicatorOrder()); else table->sortItems("id"); setAttribute(Qt::WA_DeleteOnClose); setModal(true); show(); emit btnRefresh->clicked(); // int ccs[]{"playerVer"**table, "firmware"**table}; // for(auto cc : ccs) { // auto size = table->sizeHintForColumn(cc); // if(size==0) { // int cnt = 8; // do { // wait(50); // size = table->sizeHintForColumn(cc); // } while(size==0 && --cnt); // } // if(size>table->header()->sectionSize(cc)) table->header()->resizeSection(cc, size); // } } void UpgradeApkDialog::sendProgress(UpdateApkItem *item) { QJsonObject json; json.insert("_id", "GetFpgaUpdateProgress"); json.insert("_type", "GetFpgaUpdateProgress"); auto reply = NetReq("http://"+item->text("ip")+":2016/settings").timeout(30000).post(json); ConnReply(reply, item) [=] { if(item->treeWidget()==0) return; QJsonDocument json; auto err = checkReplyForJson(reply, &json); if(! err.isEmpty()) { item->isUpdating = false; item->setResult("GetFpgaUpdateProgress "+tr("Error")+": "+err, Qt::red); return; } auto progre = json["progress"].toInt(); if(progre >= 100) { item->isUpdating = false; item->fdProgress->setValue(100); item->setResult("FPGA "+tr("Install Success"), Qt::darkGreen); item->OnCheckFpgaVersions(); } else if(progre == -1) { item->isUpdating = false; item->fdProgress->setValue(100); item->setResult(tr("Same version, needn't update"), Qt::darkGreen); } else if(progre == -2) { item->isUpdating = false; item->setResult(tr("Install Failed")+" (-2)", Qt::red); } else { item->fdProgress->setValue(progre); wait(250); sendProgress(item); } }); } void UpgradeApkDialog::keyPressEvent(QKeyEvent *event) { if(event->key() == Qt::Key_F3) { QMessageBox::warning(this, "Tip", tr("The encrypted control card can be upgraded directly")); auto cnt = table->topLevelItemCount(); for(int i=0; itopLevelItem(i))->isLocked = false; } } void UpdateApkItem::OnCheckFpgaVersions() { QJsonObject json; json.insert("_id", "CheckHardwareVersions"); json.insert("_type", "CheckHardwareVersions"); auto reply = NetReq("http://"+text("ip")+":2016/settings").timeout(60000).post(json); ConnReply(reply, fdProgress) [=] { if(treeWidget()==0) return; JValue json; auto err = errStrWithJson(reply, &json); if(! err.isEmpty()) return; QString strBuf; auto vers = json["versions"]; for(auto &ver : vers) { if(! strBuf.isEmpty()) strBuf += ", "; strBuf += ver.toStr(); } setText("fpga", strBuf); auto item = findItem(text("id")); if(item) item->mCard.HardVersion = strBuf; }); } void UpdateApkItem::OnCheckSoftVersions(int repeat) { QJsonObject json; json.insert("_id", "CheckSoftVersions"); json.insert("_type", "CheckSoftVersions"); auto reply = NetReq("http://"+text("ip")+":2016/settings").timeout(60000).post(json); ConnReply(reply, fdProgress) [=] { if(treeWidget()==0) return; JValue json; auto err = errStrWithJson(reply, &json); if(! err.isEmpty()) return; QString playerVer; auto apps = json["apps"]; for(auto &app : apps) { auto packageName = app["packageName"].toStr(); if(packageName=="com.xixun.xixunplayer") playerVer = app["versionName"].toStr(); else if(packageName=="com.xixun.joey.cardsystem") setText("cardsystem", app["versionName"].toStr()); else if(packageName=="net.sysolution.starter") setText("starter", app["versionName"].toStr()); else if(packageName=="net.sysolution.taxiapp") setText("taxiapp", app["versionName"].toStr()); else if(packageName=="com.xixun.display") setText("displayer", app["versionName"].toStr()); else if(packageName=="com.xixun.xy.conn") setText("connection", app["versionName"].toStr()); else if(packageName=="com.xixun.xy.update") setText("update", app["versionName"].toStr()); } setText("playerVer", playerVer); auto item = findItem(text("id")); if(item) item->mCard.playerVer = playerVer; if(playerVer.isEmpty() && repeat) OnCheckSoftVersions(repeat-1); }); }