From ccfe94196fefca469284ddf059c21f36e7930b12 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Burak=20Han=C3=A7erli?= <burak.hancerli@qt.io>
Date: Thu, 30 Nov 2023 10:00:21 +0000
Subject: [PATCH] QDS-11411 Material Bundle crashes

---
 android/AndroidManifest.xml |  2 +-
 src/backend.cpp             | 67 +++++++++++++++++++++++++------------
 src/backend.h               |  5 ++-
 src/projectManager.cpp      | 11 ++----
 src/projectManager.h        |  2 +-
 5 files changed, 54 insertions(+), 33 deletions(-)

diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index 9a8ef31..fa8a215 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.qt.qtdesignviewer"
-    android:installLocation="auto" android:versionCode="18" android:versionName="1.2">
+    android:installLocation="auto" android:versionCode="19" android:versionName="1.2">
     <!-- %%INSERT_PERMISSIONS -->
     <!-- %%INSERT_FEATURES -->
     <supports-screens android:anyDensity="true" android:largeScreens="true"
diff --git a/src/backend.cpp b/src/backend.cpp
index 7f59810..5562cc9 100644
--- a/src/backend.cpp
+++ b/src/backend.cpp
@@ -74,11 +74,10 @@ void Backend::initialize()
         updateUserProjectList();
     }
 
-    connect(&m_serviceConnector, &ServiceConnector::downloadProgress, this, &Backend::downloadProgress);
-    connect(&m_projectManager,
-            &ProjectManager::projectStateChanged,
+    connect(&m_serviceConnector,
+            &ServiceConnector::downloadProgress,
             this,
-            &Backend::popupTextChanged);
+            &Backend::downloadProgress);
 
     qDebug("Initialization complete");
 }
@@ -87,7 +86,23 @@ void Backend::updatePopup(const QString &text, bool indeterminate)
 {
     emit popupTextChanged(text);
     emit popupProgressIndeterminateChanged(indeterminate);
-    QEventLoop().processEvents(QEventLoop::AllEvents, 100);
+    QEventLoop().processEvents(QEventLoop::AllEvents, 1000);
+}
+
+void Backend::initializeProjectManager()
+{
+    if (m_projectManager)
+        return;
+
+    qDebug() << "Initializing Project Manager";
+    m_projectManager.reset(new ProjectManager);
+    connect(m_projectManager.data(), &ProjectManager::closingProject, this, [&] {
+        emit popupClose();
+        qDebug() << "Project Manager is closing";
+        m_projectManager.reset();
+    });
+
+    qDebug() << "Project Manager is initialized";
 }
 
 bool Backend::connectDesignStudio()
@@ -112,13 +127,14 @@ bool Backend::connectDesignStudio()
 
             connect(m_designStudioConnector.data(),
                     &DesignStudioConnector::projectReceived,
-                    &m_projectManager,
+                    this,
                     [this](const QByteArray &projectData) {
                         qDebug() << "Project received from Design Studio";
+                        initializeProjectManager();
                         emit popupOpen();
                         updatePopup("Unpacking project...");
                         qDebug() << "Project data size: " << projectData.size();
-                        const QString projectPath = m_projectManager.unpackProject(projectData);
+                        const QString projectPath = m_projectManager->unpackProject(projectData);
 
                         if (projectPath.isEmpty()) {
                             qCritical()
@@ -131,11 +147,11 @@ bool Backend::connectDesignStudio()
                         qDebug() << "Project unpacked to " << projectPath;
                         updatePopup("Running project...");
 
-                        if (!m_projectManager.runProject(projectPath)) {
+                        if (!m_projectManager->runProject(projectPath)) {
                             qCritical() << "Could not run project. Please check the logs for more "
                                            "information.";
                         } else {
-                            m_projectManager.showAppWindow();
+                            m_projectManager->showAppWindow();
                         }
                         emit popupClose();
                     });
@@ -178,10 +194,11 @@ void Backend::disconnectDesignStudio()
 
 void Backend::runDemoProject(const QString &projectName)
 {
+    initializeProjectManager();
     qDebug() << "Checking if demo project is cached for " << projectName;
     emit popupOpen();
 
-    const bool cached = m_projectManager.isDemoProjectCached(projectName);
+    const bool cached = m_projectManager->isDemoProjectCached(projectName);
 
     if (!cached) {
         updatePopup("Downloading demo project...", false);
@@ -191,7 +208,7 @@ void Backend::runDemoProject(const QString &projectName)
         qDebug() << "Demo project is not cached. Trying to download from " << url << " ...";
 
         updatePopup("Caching demo project...");
-        if (!m_projectManager.cacheDemoProject(project, projectName)) {
+        if (!m_projectManager->cacheDemoProject(project, projectName)) {
             qCritical()
                 << "Could not cache demo project. Please check the logs for more information.";
             emit popupClose();
@@ -202,10 +219,12 @@ void Backend::runDemoProject(const QString &projectName)
     }
 
     updatePopup("Running demo project...");
-    if (!m_projectManager.runDemoProject(projectName))
+    if (!m_projectManager->runDemoProject(projectName))
         qCritical() << "Could not run demo project. Please check the logs for more information.";
-    else
-        m_projectManager.showAppWindow();
+    else {
+        updatePopup("Showing the app window...");
+        m_projectManager->showAppWindow();
+    }
 
     emit popupClose();
 }
@@ -214,12 +233,15 @@ void Backend::clearDemoCaches()
 {
     emit popupOpen();
     updatePopup("Clearing demo caches...");
-    m_projectManager.clearDemoCaches();
+    m_projectManager.reset(new ProjectManager);
+    m_projectManager->clearDemoCaches();
+    m_projectManager.reset();
     emit popupClose();
 }
 
 void Backend::runUserProject(const QString &url)
 {
+    initializeProjectManager();
     updatePopup("Running user project");
     emit popupOpen();
 
@@ -236,7 +258,7 @@ void Backend::runUserProject(const QString &url)
         }
     }
 
-    const bool projectCached = m_projectManager.isProjectCached(projectInfo);
+    const bool projectCached = m_projectManager->isProjectCached(projectInfo);
 
     if (!projectCached) {
         qDebug("Project is not cached. Downloading...");
@@ -244,20 +266,21 @@ void Backend::runUserProject(const QString &url)
         QByteArray projectData = m_serviceConnector.fetchProject(url);
 
         updatePopup("Caching user project...");
-        if (!m_projectManager.cacheProject(projectData, projectInfo)) {
+        if (!m_projectManager->cacheProject(projectData, projectInfo)) {
             qCritical() << "Could not cache project. Please check the logs for more information.";
             emit popupClose();
             return;
         }
-    } else {
-        qDebug("Project is cached. Running cached project...");
     }
 
+    qDebug("Project is cached. Running cached project...");
     updatePopup("Running cached project...");
-    if (!m_projectManager.runCachedProject(projectInfo))
+    if (!m_projectManager->runCachedProject(projectInfo))
         qCritical() << "Could not run project. Please check the logs for more information.";
-    else
-        m_projectManager.showAppWindow();
+    else {
+        updatePopup("Showing the app window...");
+        m_projectManager->showAppWindow();
+    }
 
     emit popupClose();
 }
diff --git a/src/backend.h b/src/backend.h
index 4d9dae1..13aa6a5 100644
--- a/src/backend.h
+++ b/src/backend.h
@@ -58,7 +58,7 @@ private:
     // Other members
     QString m_userHash;
     ServiceConnector m_serviceConnector;
-    ProjectManager m_projectManager;
+    QScopedPointer<ProjectManager> m_projectManager;
     QScopedPointer<DesignStudioConnector> m_designStudioConnector;
     QThread m_dsConnectorThread;
 
@@ -86,6 +86,9 @@ public slots:
     void registerUser(const QUrl &url);
     bool connectDesignStudio();
     void disconnectDesignStudio();
+
+private slots:
+    void initializeProjectManager();
 };
 
 #endif // DV_ANDROID_H
diff --git a/src/projectManager.cpp b/src/projectManager.cpp
index 83c4734..090b8de 100644
--- a/src/projectManager.cpp
+++ b/src/projectManager.cpp
@@ -241,9 +241,6 @@ bool ProjectManager::runProject(const QString &projectPath)
                          }
                      });
 
-    emit projectStateChanged("Loading project...");
-    QEventLoop().processEvents(QEventLoop::AllEvents, 1000);
-
     qDebug() << "Loading mainQmlUrl: " << mainQmlUrl.toString();
     m_qmlComponent.reset(new QQmlComponent(m_qmlEngine.data()));
 
@@ -265,9 +262,6 @@ bool ProjectManager::runProject(const QString &projectPath)
         return false;
     }
 
-    emit projectStateChanged("Setting up the quickWindow...");
-    QEventLoop().processEvents(QEventLoop::AllEvents, 1000);
-
     qDebug() << "Setting up the quickWindow";
     m_quickWindow.reset(qobject_cast<QQuickWindow *>(topLevel));
     if (m_quickWindow) {
@@ -503,9 +497,10 @@ void ProjectManager::showAppWindow()
 
     connect(m_quickWindow.data(), &QQuickWindow::closing, this, [this, screen]() {
         qDebug() << "QML app window is closing";
-        m_qmlEngine.reset();
-        m_qmlComponent.reset();
         disconnect(screen, &QScreen::orientationChanged, this, &ProjectManager::orientateWindow);
+        // this signal is connected to the lambda in the backend
+        // which will reset the project manager
+        emit closingProject();
     });
 
     m_quickWindow->setFlags(Qt::Window | Qt::WindowStaysOnTopHint);
diff --git a/src/projectManager.h b/src/projectManager.h
index 6fad257..6bfbf14 100644
--- a/src/projectManager.h
+++ b/src/projectManager.h
@@ -80,7 +80,7 @@ private:
     void cacheProject(const QString &projectName, const QString &projectPath);
 
 signals:
-    void projectStateChanged(const QString &state);
+    void closingProject();
 };
 
 #endif // PROJECTMANAGER_H
-- 
GitLab