/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt OTA Update module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 or (at your option) any later version ** approved by the KDE Free Qt Foundation. The licenses are as published by ** the Free Software Foundation and appearing in the file LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import QtQuick 2.7 import QtQuick.Window 2.2 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.3 import QtOtaUpdate 1.0 Window { visible:true function log(message) { logFormatted(message, "black") } function logError(message) { logFormatted(message, "red") } function logWithCondition(message, condition) { var color = condition ? "black" : "red" var suffix = condition ? " finished" : " failed" logFormatted(message + suffix, color) } function logFormatted(message, color) { logRecords.append({ "record" : "" + (logRecords.count + 1) + " " + message, "textcolor" : color }) logView.positionViewAtEnd() } function otaEnabled() { if (!OtaClient.otaEnabled) { log("OTA Update functionality is not enabled on this device") return false; } return true; } function configureRepository(config, silent) { if (OtaClient.isRepositoryConfigSet(config)) { if (!silent) log("The configuration is already set") return false; } else { if (!OtaClient.removeRepositoryConfig()) { logError("Failed to remove repository configuration") return false; } } if (!OtaClient.setRepositoryConfig(config)) { logError("Failed to update repository configuration") return false; } if (!silent) log("Successfully updated repository configuration") return true; } function updateConfigView(config) { repoConfigLabel.text = "URL: " + (config ? config.url : "not set") repoConfigLabel.text += "
GPG Verify: " + (config ? config.gpgVerify : "not set") repoConfigLabel.text += "
TLS Client Cert: " + (config ? config.tlsClientCertPath : "not set") repoConfigLabel.text += "
TLS Client Key: " + (config ? config.tlsClientKeyPath : "not set") repoConfigLabel.text += "
TLS Permissive: " + (config ? config.tlsPermissive : "not set") repoConfigLabel.text += "
TLS CA: " + (config ? config.tlsCaPath : "not set") } function updateMetadataLabel(label, metadata, rev) { if (metadata.length === 0) { label.text = "No metadata available" return } var metadataObj = JSON.parse(metadata) label.text = "" for (var property in metadataObj) label.text += "" + property.charAt(0).toUpperCase() + property.slice(1) + ": " + metadataObj[property] + "
" label.text += "Revision: " + rev } function updateBootedMetadataLabel() { updateMetadataLabel(bootedMetadataLabel, OtaClient.bootedMetadata, OtaClient.bootedRevision) } function updateRemoteMetadataLabel() { updateMetadataLabel(remoteMetadataLabel, OtaClient.remoteMetadata, OtaClient.remoteRevision) } function updateRollbackMetadataLabel() { updateMetadataLabel(rollbackMetadataLabel, OtaClient.rollbackMetadata, OtaClient.rollbackRevision) } function updateDefaultMetadataLabel() { updateMetadataLabel(defaultMetadataLabel, OtaClient.defaultMetadata, OtaClient.defaultRevision) } Flickable { anchors.fill: parent contentHeight: topLayout.implicitHeight + topLayout.anchors.bottomMargin * 2 flickableDirection: Flickable.VerticalFlick ScrollBar.vertical: ScrollBar { } ColumnLayout { id: topLayout anchors.fill: parent anchors.margins: 10 Label { text: "BOOTED"; Layout.bottomMargin: 14; font.underline: true; } Label { id: bootedMetadataLabel; lineHeight : 1.3 } Label { text: "REMOTE"; Layout.bottomMargin: 14; Layout.topMargin: 14; font.underline: true } Label { id: remoteMetadataLabel; lineHeight : 1.3 } Label { text: "ROLLBACK"; Layout.bottomMargin: 14; Layout.topMargin: 14; font.underline: true } Label { id: rollbackMetadataLabel; lineHeight : 1.3 } Label { text: "DEFAULT"; Layout.bottomMargin: 14; Layout.topMargin: 14; font.underline: true } Label { id: defaultMetadataLabel; lineHeight : 1.3 } Label { text: "REPOSITORY CONFIGURATION"; Layout.bottomMargin: 14; Layout.topMargin: 14; font.underline: true } Label { id: repoConfigLabel; lineHeight : 1.3 } RowLayout { Layout.topMargin: 20 Layout.bottomMargin: 10 Button { text: "Use basic config" onClicked: { if (!otaEnabled()) return; configureRepository(basicConfig, false) } } Button { text: "Use secure config" onClicked: { if (!otaEnabled()) return; configureRepository(secureConfig, false) } } Button { text: "Fetch OTA Metadata" onClicked: { if (!otaEnabled()) return; log("Fetcing OTA Metadata...") OtaClient.fetchRemoteMetadata() } } Button { text: "Update from Package" onClicked: { if (!otaEnabled()) return; log("Starting update from the package ...") OtaClient.updateOffline("/var/superblock") } } Button { visible: OtaClient.rollbackAvailable text: "Rollback" onClicked: { if (!otaEnabled()) return; log("Roolback...") OtaClient.rollback() } } Button { visible: OtaClient.updateAvailable text: "Update" onClicked: { if (!otaEnabled()) return; log("Updating...") OtaClient.update() } } Button { visible: OtaClient.restartRequired text: "Restart" onClicked: { if (!otaEnabled()) return; log("Restarting (unimplemented) ...") } } } Frame { Layout.preferredHeight: bootedMetadataLabel.font.pixelSize * 12 Layout.preferredWidth: { Screen.width < 800 ? Screen.width - topLayout.anchors.leftMargin * 2 : Screen.width * 0.5 > 800 ? 800 : Screen.width * 0.5 } padding: 6 ListView { id: logView anchors.fill: parent clip: true model: ListModel { id: logRecords } delegate: Label { text: record color: textcolor width: parent.width wrapMode: Text.WordWrap } } } } } OtaRepositoryConfig { id: basicConfig url: "http://www.b2qtupdate.com/ostree-repo" } OtaRepositoryConfig { id: secureConfig gpgVerify: true url: "https://www.b2qtupdate.com/ostree-repo" tlsClientCertPath: "/usr/share/ostree/certs/clientcert.pem" tlsClientKeyPath: "/usr/share/ostree/certs/clientkey.pem" tlsPermissive: false tlsCaPath: "/usr/share/ostree/certs/servercert.pem" } Connections { target: OtaClient onErrorChanged: logError(error) onStatusChanged: log(status) onFetchRemoteMetadataFinished: { logWithCondition("Fetching metadata from a remote server", success) if (success) log("Update available: " + OtaClient.updateAvailable) } onUpdateOfflineFinished: logWithCondition("Update from package", success) onRollbackFinished: logWithCondition("Rollback", success) onUpdateFinished: logWithCondition("Update", success) onRepositoryConfigChanged: updateConfigView(config) onRemoteMetadataChanged: updateRemoteMetadataLabel() onRollbackMetadataChanged: updateRollbackMetadataLabel() onDefaultMetadataChanged: updateDefaultMetadataLabel() } Component.onCompleted: { if (!OtaClient.otaEnabled) { log("OTA Update functionality is not enabled on this device") return; } var configuredOk = configureRepository(basicConfig, true); if (!configuredOk) // Already configured, so won't be handled by onRepositoryConfigChanged. // But config view still needs to be updated. updateConfigView(OtaClient.repositoryConfig()) updateBootedMetadataLabel() updateRemoteMetadataLabel() updateRollbackMetadataLabel() updateDefaultMetadataLabel() } }