[PWE] Implement PWA installation process for PWA mode 67/131367/7
authorPawel Niemirski <p.niemirski@samsung.com>
Fri, 2 Jun 2017 09:20:31 +0000 (11:20 +0200)
committerPawel Niemirski <p.niemirski@samsung.com>
Tue, 13 Jun 2017 08:49:33 +0000 (10:49 +0200)
This CL allows browser to handle installation requests triggered by
window.navigator.installApp JS API also in PWA mode.

To avoid code duplication, we've introduced PWAHandler class which is
used in both browser modes (standard and PWA).

Bug: http://suprem.sec.samsung.net/jira/browse/RWASP-1434

Change-Id: If3067479836b53f8f74a0fe9a288b81a21c6dd83
Signed-off-by: Pawel Niemirski <p.niemirski@samsung.com>
core/AbstractWebEngine/AbstractWebEngine.h
core/CMakeLists.txt
core/Tools/PWAHandler.cpp [new file with mode: 0644]
core/Tools/PWAHandler.h [new file with mode: 0644]
services/SimpleUI/SimpleUI.cpp
services/WebEngineMin/WebEngineMin.cpp
services/WebEngineMin/WebEngineMin.h
services/WebEngineService/WebEngineService.cpp
services/WebEngineService/WebEngineService.h
services/WebEngineService/WebView.cpp
services/WebEngineService/WebView.h

index 76fd4a9a6c978770500452873192dd8af8baf9d8..cd6aab097b5f2314a224c516eeb79ac36c2b2328 100755 (executable)
@@ -82,7 +82,7 @@ public:
     /**
      * Prepare data for PWA.
      */
-    virtual void setPWAData() = 0;
+    virtual void AddToHomescreen() = 0;
 
     /**
      * @return title of page opened in current tab.
index 0c4e0824050a3bba12e0ab3a4cd734d54ff4cc01..665ebdb052b8363e4e3d3ce97e6e0c5c446fe520 100755 (executable)
@@ -40,6 +40,7 @@ set(browserCore_SRCS
     Tools/CapiWebErrorCodes.cpp
     Tools/StringTools.cpp
     Tools/GengridWrapper.cpp
+    Tools/PWAHandler.cpp
     )
 
 if(${PROFILE} MATCHES "mobile")
diff --git a/core/Tools/PWAHandler.cpp b/core/Tools/PWAHandler.cpp
new file mode 100644 (file)
index 0000000..8720c87
--- /dev/null
@@ -0,0 +1,238 @@
+#include "PWAHandler.h"
+
+#include <curl/curl.h>
+#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_generators.hpp>
+#include <boost/uuid/uuid_io.hpp>
+#include <fcntl.h>
+#include <shortcut_manager.h>
+
+#include "BrowserLogger.h"
+
+using namespace std;
+
+namespace
+{
+string shortcutString;
+string pwaName;
+string iconPath;
+
+const string DOWNLOAD_PATH = app_get_shared_data_path();
+
+void MakeShortcut(const string& name, const string& pwaData, const string& icon)
+{
+    if (shortcut_add_to_home(name.c_str(), LAUNCH_BY_URI, pwaData.c_str(),
+            icon.c_str(), 0, PWAHandler::OnDidMakeShortcutCb, nullptr) != SHORTCUT_ERROR_NONE) {
+        BROWSER_LOGE("[%s:%d] Fail to add to homescreen", __PRETTY_FUNCTION__, __LINE__);
+    } else {
+        BROWSER_LOGE("[%s:%d] Success to add to homescreen", __PRETTY_FUNCTION__, __LINE__);
+    }
+}
+
+void SoupSessionCb(SoupSession *session, SoupMessage *msg, gpointer data)
+{
+    BROWSER_LOGD("[%s:%d] session : %s", __PRETTY_FUNCTION__, __LINE__, session);
+
+    if (data) {
+        DownloadRequest *request = static_cast<DownloadRequest *>(data);
+        SoupBuffer *body = soup_message_body_flatten(msg->response_body);
+        int fd = 0;
+        int oflags = O_CREAT | O_WRONLY;
+        int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+        const char* filePath = request->filePath.c_str();
+
+        if (body->data && (body->length > 0) && ((fd = open(filePath, oflags, mode)) >= 0)) {
+            unsigned int write_len = write(fd, body->data, body->length);
+            close(fd);
+            if (write_len == body->length)
+                request->cb(filePath);
+            else
+                unlink(filePath);
+        }
+        g_object_unref(msg);
+        soup_buffer_free(body);
+        delete request;
+    }
+    MakeShortcut(pwaName, shortcutString, iconPath);
+}
+
+void OnDidDownloadCb(const char *filePath)
+{
+    BROWSER_LOGD("[%s:%d] filePath = [%s]", __PRETTY_FUNCTION__, __LINE__, filePath);
+    BROWSER_LOGD("[%s:%d] complete !", __PRETTY_FUNCTION__, __LINE__);
+}
+
+} // anonymous namespace
+
+int PWAHandler::OnDidMakeShortcutCb(int ret, void *data)
+{
+    if (data)
+        BROWSER_LOGD("[%s:%d] ret : %d, data : %s", __PRETTY_FUNCTION__, __LINE__, ret, data);
+    else
+        BROWSER_LOGW("[%s] result_cb_data = nullptr", __PRETTY_FUNCTION__);
+
+    return 0;
+}
+
+void PWAHandler::ConnectWebView(Evas_Object *webView)
+{
+    ewk_view_app_installation_request_callback_set(
+        webView, OnDidGetInstallationRequestCb, this);
+}
+
+void PWAHandler::OnDidGetInstallationRequestCb(Evas_Object* ewkView, Ewk_App_Installation_Request* request, void* userData)
+{
+    BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
+    if (!ewkView) {
+        BROWSER_LOGD("View no longer exists!");
+        return;
+    }
+    auto pwaHandler = static_cast<PWAHandler*>(userData);
+    Ewk_View_Request_Manifest* manifest = ewk_app_installation_request_manifest_get(request);
+    ManifestData manifestData = pwaHandler->GetManifestData(manifest);
+
+    const char* tmp = ewk_app_installation_request_service_worker_url_get(request);
+    manifestData.serviceWorkerURL = (tmp) ? tmp : "";
+    pwaHandler->TriggerPWAInstallation(manifestData);
+}
+
+ManifestData PWAHandler::GetManifestData(Ewk_View_Request_Manifest *manifest)
+{
+    ManifestData data;
+    const char *tmp;
+    data.pushId = ((tmp = ewk_manifest_push_sender_id_get(manifest)) ? tmp : "");
+    if (data.pushId.empty())
+        BROWSER_LOGW("[%s:%d] unknown Push ID value!", __PRETTY_FUNCTION__, __LINE__);
+
+    data.shortName = ((tmp = ewk_manifest_short_name_get(manifest)) ? tmp : "");
+    data.name = ((tmp = ewk_manifest_name_get(manifest)) ? tmp : "");
+    data.startUrl = ((tmp = ewk_manifest_start_url_get(manifest)) ? tmp : "");
+    data.orientationType = ewk_manifest_orientation_type_get(manifest);
+    data.webDisplayMode = ewk_manifest_web_display_mode_get(manifest);
+    data.themeColor.colorExist = ewk_manifest_theme_color_get(
+        manifest, &data.themeColor.r,
+        &data.themeColor.g,
+        &data.themeColor.b,
+        &data.themeColor.a);
+    data.backgroundColor.colorExist = ewk_manifest_background_color_get(
+        manifest,
+        &data.backgroundColor.r,
+        &data.backgroundColor.g,
+        &data.backgroundColor.b,
+        &data.backgroundColor.a);
+    data.iconsCount = ewk_manifest_icons_count_get(manifest);
+    for (size_t iconNumber = 0; iconNumber < data.iconsCount; iconNumber++)
+    {
+        ManifestData::Icon icon;
+        icon.src = ((tmp = ewk_manifest_icons_src_get(manifest, iconNumber)) ? tmp : "");
+        icon.type = ((tmp = ewk_manifest_icons_type_get(manifest, iconNumber)) ? tmp : "");
+        icon.sizesCount = ewk_manifest_icons_sizes_count_get(manifest, iconNumber);
+        for (size_t sizeNumber = 0; sizeNumber < icon.sizesCount; sizeNumber++)
+        {
+            ManifestData::Icon::Size size;
+            size.width = ewk_manifest_icons_width_get(manifest, iconNumber, sizeNumber);
+            size.height = ewk_manifest_icons_height_get(manifest, iconNumber, sizeNumber);
+            icon.sizes.push_back(size);
+        }
+        data.icons.push_back(icon);
+    }
+    return data;
+}
+
+void OnDidGetInstallationRequestCb(Evas_Object* ewkView, Ewk_App_Installation_Request* request, void* userData)
+{
+    BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
+    if (!ewkView) {
+        BROWSER_LOGD("View no longer exists!");
+        return;
+    }
+    auto pwaHandler = static_cast<PWAHandler*>(userData);
+    Ewk_View_Request_Manifest* manifest = ewk_app_installation_request_manifest_get(request);
+    ManifestData manifestData = pwaHandler->GetManifestData(manifest);
+
+    const char* tmp = ewk_app_installation_request_service_worker_url_get(request);
+    manifestData.serviceWorkerURL = (tmp) ? tmp : "";
+    pwaHandler->TriggerPWAInstallation(manifestData);
+}
+
+void PWAHandler::TriggerPWAInstallation(ManifestData manifest)
+{
+    BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
+
+    if (manifest.name.empty() || manifest.startUrl.empty()) {
+        BROWSER_LOGW("No Name and url in manifest!");
+        return;
+    }
+
+    pwaName = manifest.name;
+
+    CURL *curl = curl_easy_init();
+    char *text;
+    if (!curl) {
+        BROWSER_LOGE("[%s:%d] CURL not initialized", __PRETTY_FUNCTION__, __LINE__);
+        return;
+    }
+
+    iconPath = DOWNLOAD_PATH + boost::uuids::to_string(boost::uuids::random_generator()());
+    RequestFileDownload(manifest.icons.begin()->src, iconPath, OnDidDownloadCb);
+
+    auto id = installPWA(manifest.name, manifest.pushId, manifest.shortName);
+    if (!id) {
+        BROWSER_LOGE("[%s:%d] unknown installPWA value!", __PRETTY_FUNCTION__, __LINE__);
+        curl_easy_cleanup(curl);
+        return;
+    }
+
+    string retVal("multi-instance-shortcut://tizen.org/shortcut/multi-instance?");
+    retVal += "id=" + manifest.shortName + to_string(*id)
+        + "&icon=" + string(text = curl_easy_escape(curl, iconPath.c_str(), iconPath.length()));
+    curl_free(text);
+    retVal += "&name=" + manifest.name + "&uri=" + string(text = curl_easy_escape(curl, manifest.startUrl.c_str(),
+            manifest.startUrl.length()));
+    curl_free(text);
+    retVal += "&pwa_shortName=" + manifest.shortName
+        + "&pwa_name=" + manifest.name
+        + "&pwa_uri=" + string(text = curl_easy_escape(curl, manifest.startUrl.c_str(),
+            manifest.startUrl.length()));
+    curl_free(text);
+    retVal += "&pwa_orientation=" + to_string(static_cast<int>(manifest.orientationType))
+        + "&pwa_displayMode=" + to_string(static_cast<int>(manifest.webDisplayMode))
+        + "&pwa_themeColor=" + to_string(manifest.themeColor.colorExist)
+        + "&pwa_theme_r=" + to_string(manifest.themeColor.r)
+        + "&pwa_theme_g=" + to_string(manifest.themeColor.g)
+        + "&pwa_theme_b=" + to_string(manifest.themeColor.b)
+        + "&pwa_theme_a=" + to_string(manifest.themeColor.a)
+        + "&pwa_backgroundColor=" + to_string(manifest.backgroundColor.colorExist)
+        + "&pwa_bg_r=" + to_string(manifest.backgroundColor.r)
+        + "&pwa_bg_g=" + to_string(manifest.backgroundColor.g)
+        + "&pwa_bg_b=" + to_string(manifest.backgroundColor.b)
+        + "&pwa_bg_a=" + to_string(manifest.backgroundColor.a)
+        + "&pwa_icon_count=" + to_string(manifest.iconsCount)
+        + "&pwa_icon_src=" + string(text = curl_easy_escape(curl,
+            manifest.icons.begin()->src.c_str(), manifest.icons.begin()->src.length()));
+    if (!manifest.serviceWorkerURL.empty())
+        retVal += "&pwa_serviceWorkerUri=" + manifest.serviceWorkerURL;
+
+    curl_free(text);
+    curl_easy_cleanup(curl);
+
+    BROWSER_LOGD("[%s:%d] retVal : %s", __PRETTY_FUNCTION__, __LINE__, retVal.c_str());
+    storePWAShortcut(*id, retVal);
+
+    shortcutString = retVal;
+}
+
+void PWAHandler::RequestFileDownload(const string &uri, const string &filePath, DownloadRequest::DownloadFinishCb cb)
+{
+    BROWSER_LOGD("[%s:%d]", __PRETTY_FUNCTION__, __LINE__);
+    BROWSER_LOGD("uri = [%s], filePath = [%s]", uri.c_str(), filePath.c_str());
+
+    SoupSession *soupSession = soup_session_async_new();
+    SoupMessage *soupMsg = soup_message_new("GET", uri.c_str());
+    g_object_set(soupSession, SOUP_SESSION_TIMEOUT, 15, nullptr);
+
+    DownloadRequest *request = new (nothrow) DownloadRequest(filePath, cb);
+    soup_session_queue_message(soupSession, soupMsg, SoupSessionCb, static_cast<void *>(request));
+
+    g_object_unref(soupSession);
+}
\ No newline at end of file
diff --git a/core/Tools/PWAHandler.h b/core/Tools/PWAHandler.h
new file mode 100644 (file)
index 0000000..0fb9fdc
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef PWAHANDLER_H_
+#define PWAHANDLER_H_
+
+#include <app.h>
+#include <boost/signals2/signal.hpp>
+#include <cstddef>
+#include <EWebKit_internal.h>
+#include <libsoup/soup.h>
+#include <string>
+#include <vector>
+
+struct DownloadRequest
+{
+    using DownloadFinishCb = void (*)(const char* filePath);
+
+    DownloadRequest(const std::string &filePath, DownloadFinishCb cb = nullptr)
+        : filePath(filePath), cb(cb) {}
+
+    std::string filePath;
+    DownloadFinishCb cb;
+};
+
+struct ManifestData
+{
+    std::string shortName;
+    std::string name;
+    std::string startUrl;
+    Ewk_View_Orientation_Type orientationType;
+    Ewk_View_Web_Display_Mode webDisplayMode;
+    struct Color
+    {
+        unsigned colorExist;
+        uint8_t r, g, b, a;
+    } themeColor, backgroundColor;
+
+    size_t iconsCount;
+    struct Icon
+    {
+        std::string src;
+        std::string type;
+        size_t sizesCount;
+        struct Size
+        {
+            int width;
+            int height;
+        };
+        std::vector<Size> sizes;
+    };
+    std::vector<Icon> icons;
+    std::string pushId;
+    std::string serviceWorkerURL;
+};
+
+class PWAHandler
+{
+  public:
+    void TriggerPWAInstallation(ManifestData manifest);
+    ManifestData GetManifestData(Ewk_View_Request_Manifest *manifest);
+    void ConnectWebView(Evas_Object *webView);
+
+    boost::signals2::signal<unsigned(const std::string &, const std::string &, const std::string &)> installPWA;
+    boost::signals2::signal<void(const unsigned &, const std::string &)> storePWAShortcut;
+
+    static int OnDidMakeShortcutCb(int ret, void *data);
+
+  private:
+    static void OnDidGetInstallationRequestCb(Evas_Object* ewkView, Ewk_App_Installation_Request* request, void* userData);
+    void RequestFileDownload(const std::string &uri, const std::string &filePath, DownloadRequest::DownloadFinishCb cb);
+};
+
+#endif /* PWAHANDLER_H_ */
\ No newline at end of file
index 44e0cee5281fa1a175dd3589285602bb39952951..eaca6bd354a3b1d36b6bb48eb47cd125805d44f1 100755 (executable)
@@ -515,7 +515,7 @@ void SimpleUI::connectWebPageSignals() {
     m_webPageUI->requestCurrentPageForWebPageUI.connect(
                     [this] {return requestSettingsCurrentPage();});
     m_webPageUI->pwaRequestManifest.connect(
-                    [this] {m_webEngine->setPWAData();});
+                    [this] {m_webEngine->AddToHomescreen();});
     m_webPageUI->getCountCheckSignal.connect(
                     [this] {return this->countCheckUrl();});
     m_webPageUI->isMostVisited.connect(
@@ -750,10 +750,12 @@ void SimpleUI::connectWebEngineSignals() {
     m_webEngine->changeUIColor.connect([this](int r, int g, int b, int a) {
         m_webPageUI->changeUIColor(r, g, b, a);
     });
-    m_webEngine->installPWA.connect(
-                    [this](const std::string& s, const std::string& p, const std::string& sn) {
-                        return m_storageService->getPWAStorage().installPWAItem(s, p, sn);
-                    });
+    m_webEngine->installPWA.connect([this](const std::string &name,
+                                           const std::string &push_id,
+                                           const std::string &short_name) {
+      return m_storageService->getPWAStorage().installPWAItem(name, push_id,
+                                                              short_name);
+    });
     m_webEngine->storePWAShortcut.connect(
                     [this](const unsigned& id, const std::string& shortcut) {
                         return m_storageService->getPWAStorage().storePWAShortcut(id, shortcut);
@@ -993,6 +995,14 @@ void SimpleUI::connectPWASignals() {
                     [this](const int& id, const bool& state) {
                         return m_storageService->getPWAStorage().updatePermissionState(id, state);
                     });
+    m_webEngine->installPWA.connect(
+                    [this](const std::string& s, const std::string& p, const std::string& sn) {
+                        return m_storageService->getPWAStorage().installPWAItem(s, p, sn);
+                    });
+    m_webEngine->storePWAShortcut.connect(
+                    [this](const unsigned& id, const std::string& shortcut) {
+                        return m_storageService->getPWAStorage().storePWAShortcut(id, shortcut);
+                    });
     m_webEngine->windowCreated.connect([this] {switchViewToWebPage();});
     m_webEngine->getPermissionsMap.connect([this] {
         BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
@@ -1771,7 +1781,7 @@ void SimpleUI::pwaPopupButtonClicked(const PopupButtons& button) {
     switch (button) {
     case OK:
     BROWSER_LOGD("[%s:%d] pwaPopup OK !", __PRETTY_FUNCTION__, __LINE__);
-    m_webEngine->setPWAData();
+    m_webEngine->AddToHomescreen();
     m_storageService->getPWAStorage().addPWAItem(uri, 1, 0);
         break;
     case CANCEL:
index 6023fc81ce91c7fced3eea3a0994456c6fe5c402..aa105e5d277f9664cdb0a9351d2b283d086923fb 100755 (executable)
@@ -29,6 +29,11 @@ WebEngineMin::WebEngineMin() :
     m_downloadControl(std::make_shared<DownloadControl>()),
     m_policyCounter(0)
 {
+    m_pwaHandler.reset(new PWAHandler);
+    m_pwaHandler->installPWA.connect(
+        [this](const std::string& s, const std::string& p, const std::string& sn) { return *installPWA(s, p, sn); });
+    m_pwaHandler->storePWAShortcut.connect(
+        [this](const unsigned& id, const std::string& shortcut) { storePWAShortcut(id, shortcut); });
 }
 
 WebEngineMin::~WebEngineMin()
@@ -121,6 +126,8 @@ void WebEngineMin::init(Evas_Object* guiParent)
 #if PWE_SHUB
     evas_object_smart_callback_add(m_ewkView, "request,certificate,confirm", __requestCertificationConfirm, this);
 #endif
+    m_pwaHandler->ConnectWebView(m_ewkView);
+
     auto permissions = *getPermissionsMap();
     Eina_List* permList = nullptr;
     for (const auto& it : permissions) {
index beb88e977ec3bb0d16ead2db6b719f23371bbb0b..9d8b9d759f4b1845cf8c53b36151d7338fc0ae27 100755 (executable)
 #include <boost/noncopyable.hpp>
 #include <Evas.h>
 #include <EWebKit_internal.h>
+#include <memory>
 
 #include "AbstractWebEngine/AbstractWebEngine.h"
 #include "DownloadControl/DownloadControl.h"
+#include "PWAHandler.h"
 #include "service_macros.h"
 
 namespace tizen_browser {
@@ -85,7 +87,7 @@ public:
 #if !DUMMY_BUTTON
     Evas_Object* getWidget() override { }
 #endif
-    void setPWAData() override { }
+    void AddToHomescreen() override { }
     void setUserAgent(const std::string&) override { }
     void languageChanged() override { }
     void stopLoading() override { }
@@ -132,6 +134,7 @@ private:
     Evas_Object* m_ewkView;
     Ewk_Context* m_ewkContext;
     std::string m_loadingURL;
+    std::unique_ptr<PWAHandler> m_pwaHandler;
     std::shared_ptr<DownloadControl> m_downloadControl;
 #if PWE_SHUB
     std::map<CertificateConfirmationPtr, Ewk_Certificate_Policy_Decision *> m_confirmationCertificatenMap;
index a437f0492c8e017366f2245e5e97c6e5ed0b1e8e..64493935a8afeb77b5386630ce3010efd01b71b7 100755 (executable)
@@ -195,9 +195,9 @@ void WebEngineService::connectSignals(std::shared_ptr<WebView> webView)
         [this](const int& r, const int& g, const int& b, const int& a){
             this->changeUIColor(r, g, b, a);
     });
-    webView->installPWA.connect(
+    webView->GetPWAHandler()->installPWA.connect(
         [this](const std::string& str, const std::string& id, const std::string& sn) { return *installPWA(str, id, sn); });
-    webView->storePWAShortcut.connect(
+    webView->GetPWAHandler()->storePWAShortcut.connect(
         [this](const unsigned& id, const std::string& shortcut){this->storePWAShortcut(id, shortcut);});
     webView->pushSignal.connect(
         [this](const char* sender, const char* push_data) {
@@ -244,8 +244,8 @@ void WebEngineService::disconnectSignals(std::shared_ptr<WebView> webView)
     webView->findOnPage.disconnect(boost::bind(&WebEngineService::_findOnPage, this, _1));
     webView->searchInNewTab.disconnect_all_slots();
     webView->changeUIColor.disconnect_all_slots();
-    webView->installPWA.disconnect_all_slots();
-    webView->storePWAShortcut.disconnect_all_slots();
+    webView->GetPWAHandler()->installPWA.disconnect_all_slots();
+    webView->GetPWAHandler()->storePWAShortcut.disconnect_all_slots();
     webView->storePermission.disconnect_all_slots();
     webView->getPermissionId.disconnect_all_slots();
     webView->updatePermissionState.disconnect_all_slots();
@@ -289,13 +289,9 @@ std::string WebEngineService::getURI() const
         return std::string("");
 }
 
-void WebEngineService::setPWAData()
+void WebEngineService::AddToHomescreen()
 {
-    m_currentWebView->addManifestTypeToHandle(ManifestType::PWA_MANIFEST);
-    if (!m_currentWebView->isManifestReady())
-        m_currentWebView->requestManifest();
-    else
-        m_currentWebView->handleManifest();
+    m_currentWebView->requestManifest();
 }
 
 bool WebEngineService::isLoadError() const
index 4bf7f310dd44411a524804ea8741cef5c6d0145b..78bb28d814fb12fdbe9fcab204591a09d016facd 100755 (executable)
@@ -63,7 +63,7 @@ public:
     void init(Evas_Object* guiParent);
     void setURI(const std::string &);
     std::string getURI(void) const;
-    void setPWAData();
+    void AddToHomescreen();
     std::string getTitle(void) const;
     TabOrigin getOrigin(void) const;
     std::string getUserAgent(void) const;
index 5a720970ee9317c0cc12b36d6e9bde198113f499..ccb47f4530108b456a3ea29f5e44b4ca3d8c8f33 100755 (executable)
@@ -82,10 +82,6 @@ namespace basic_webengine {
 namespace webengine_service {
 
 const std::string WebView::COOKIES_PATH = "cookies";
-std::string WebView::s_pwaData = "";
-std::string WebView::s_name = "";
-std::string WebView::s_icon = "";
-const std::string WebView::DOWNLOAD_PATH = app_get_shared_data_path();
 
 struct SnapshotItemData {
     WebView* web_view;
@@ -106,26 +102,12 @@ WebView::WebView(Evas_Object * obj, TabId tabId, const std::string& title, bool
     , m_suspended(false)
     , m_private(incognitoMode)
     , m_fullscreen(false)
-    , m_manifestData()
-    , m_manifestReady(false)
     , m_downloadControl(nullptr)
     , m_policyCounter(0)
     , m_imeState(false)
     , m_themeColor()
 {
-    m_manifestData.orientation_type = static_cast<Ewk_View_Orientation_Type>(0);
-    m_manifestData.web_display_mode = static_cast<Ewk_View_Web_Display_Mode>(0);
-    m_manifestData.theme_color.colorExist = 0;
-    m_manifestData.theme_color.r = 0;
-    m_manifestData.theme_color.g = 0;
-    m_manifestData.theme_color.b = 0;
-    m_manifestData.theme_color.a = 0;
-    m_manifestData.background_color.colorExist = 0;
-    m_manifestData.background_color.r = 0;
-    m_manifestData.background_color.g = 0;
-    m_manifestData.background_color.b = 0;
-    m_manifestData.background_color.a = 0;
-    m_manifestData.icons_count = 0;
+    m_pwaHandler.reset(new PWAHandler());
 }
 
 WebView::~WebView()
@@ -199,7 +181,7 @@ void WebView::init(bool desktopMode, TabOrigin origin)
         BROWSER_LOGD("[%s:%d] Set permissions", __PRETTY_FUNCTION__, __LINE__);
         ewk_notification_cached_permissions_set(permList);
     }
-
+    m_pwaHandler->ConnectWebView(m_ewkView);
     resume();
 }
 
@@ -307,9 +289,6 @@ void WebView::registerCallbacks()
     evas_object_smart_callback_add(m_ewkView, "notification,permission,reply", __notification_reply_cb, this);
 
     ewk_view_did_change_theme_color_callback_set(m_ewkView, __theme_color_changed, this);
-#if PWE_SHUB
-    ewk_view_app_installation_request_callback_set(m_ewkView, __install_pwa_request_cb, this);
-#endif
 }
 
 void WebView::unregisterCallbacks()
@@ -390,161 +369,7 @@ std::string WebView::getURI(void)
 void WebView::requestManifest(void)
 {
     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
-    ewk_view_request_manifest(m_ewkView, __setManifestData, this);
-}
-
-void WebView::handleManifest()
-{
-    BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
-    for (const auto &type : m_manifestVector) {
-        switch (type) {
-            case ManifestType::QUICKACCESS_MANIFEST:
-                BROWSER_LOGD("Quickaccess manifest - not implemented");
-                break;
-            case ManifestType::THEME_MANIFEST:
-                BROWSER_LOGD("Quickaccess manifest - not implemented");
-                break;
-            case ManifestType::PWA_MANIFEST:
-                setPWAData();
-                break;
-            default:
-                BROWSER_LOGD("Bad manifest type");
-                break;
-        }
-    }
-    m_manifestVector.clear();
-}
-
-void WebView::setPWAData(const std::string& serviceWorkerURL)
-{
-    BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
-    s_name = m_manifestData.name;
-
-    CURL *curl = curl_easy_init();
-    char* text;
-    if (!curl) {
-        BROWSER_LOGE("[%s:%d] CURL not initialized", __PRETTY_FUNCTION__, __LINE__);
-        return;
-    }
-
-    std::string str_icon_src = m_manifestData.icons.begin()->src;
-    s_icon = DOWNLOAD_PATH + boost::uuids::to_string(boost::uuids::random_generator()());
-    request_file_download(m_manifestData.icons.begin()->src, s_icon, __download_result_cb, nullptr);
-
-    if (m_manifestData.m_push_id.empty())
-        BROWSER_LOGW("[%s:%d] unknown Push ID value!", __PRETTY_FUNCTION__, __LINE__);
-
-    auto id = installPWA(m_manifestData.name, m_manifestData.m_push_id, m_manifestData.short_name);
-    if (!id) {
-        BROWSER_LOGE("[%s:%d] unknown installPWA value!", __PRETTY_FUNCTION__, __LINE__);
-        curl_easy_cleanup(curl);
-        return;
-    }
-
-    std::string retVal("multi-instance-shortcut://tizen.org/shortcut/multi-instance?");
-    retVal += "id=" + m_manifestData.short_name + std::to_string(*id)
-        + "&icon=" + std::string(text = curl_easy_escape(curl, s_icon.c_str(), s_icon.length()));
-    curl_free(text);
-    retVal += "&name=" + s_name
-        + "&uri=" + std::string(text = curl_easy_escape(curl, m_manifestData.start_url.c_str(),
-            m_manifestData.start_url.length()));
-    curl_free(text);
-    retVal += "&pwa_shortName=" + m_manifestData.short_name
-        + "&pwa_name=" + m_manifestData.name
-        + "&pwa_uri=" + std::string(text = curl_easy_escape(curl, m_manifestData.start_url.c_str(),
-            m_manifestData.start_url.length()));
-    curl_free(text);
-    retVal += "&pwa_orientation=" + std::to_string(static_cast<int>(m_manifestData.orientation_type))
-        + "&pwa_displayMode=" + std::to_string(static_cast<int>(m_manifestData.web_display_mode))
-        + "&pwa_themeColor=" + std::to_string(m_manifestData.theme_color.colorExist)
-        + "&pwa_theme_r=" + std::to_string(m_manifestData.theme_color.r)
-        + "&pwa_theme_g=" + std::to_string(m_manifestData.theme_color.g)
-        + "&pwa_theme_b=" + std::to_string(m_manifestData.theme_color.b)
-        + "&pwa_theme_a=" + std::to_string(m_manifestData.theme_color.a)
-        + "&pwa_backgroundColor=" + std::to_string(m_manifestData.background_color.colorExist)
-        + "&pwa_bg_r=" + std::to_string(m_manifestData.background_color.r)
-        + "&pwa_bg_g=" + std::to_string(m_manifestData.background_color.g)
-        + "&pwa_bg_b=" + std::to_string(m_manifestData.background_color.b)
-        + "&pwa_bg_a=" + std::to_string(m_manifestData.background_color.a)
-        + "&pwa_icon_count=" + std::to_string(m_manifestData.icons_count)
-        + "&pwa_icon_src=" + std::string(text = curl_easy_escape(curl, s_icon.c_str(), s_icon.length()));
-#if PWE_SHUB
-    if (!serviceWorkerURL.empty())
-        retVal += "&pwa_serviceWorkerUri=" + serviceWorkerURL;
-#endif
-    curl_free(text);
-    curl_easy_cleanup(curl);
-
-    BROWSER_LOGD("[%s:%d] retVal : %s", __PRETTY_FUNCTION__, __LINE__, retVal.c_str());
-    storePWAShortcut(*id, retVal);
-    s_pwaData = retVal;
-}
-
-void WebView::makeShortcut(const std::string& name, const std::string& pwaData, const std::string& icon)
-{
-    if (shortcut_add_to_home(name.c_str(), LAUNCH_BY_URI, pwaData.c_str(),
-            icon.c_str(), 0, result_cb, nullptr) != SHORTCUT_ERROR_NONE)
-        BROWSER_LOGE("[%s:%d] Fail to add to homescreen", __PRETTY_FUNCTION__, __LINE__);
-    else
-        BROWSER_LOGE("[%s:%d] Success to add to homescreen", __PRETTY_FUNCTION__, __LINE__);
-}
-
-int WebView::result_cb(int ret, void *data) {
-    if (data) {
-        BROWSER_LOGD("[%s:%d] ret : %d, data : %s", __PRETTY_FUNCTION__, __LINE__, ret, data);
-    } else {
-        BROWSER_LOGW("[%s] result_cb_data = nullptr", __PRETTY_FUNCTION__);
-    }
-    return 0;
-}
-
-void WebView::request_file_download(const std::string& uri, const std::string& file_path, download_finish_callback cb, void *data)
-{
-    BROWSER_LOGD("[%s:%d]", __PRETTY_FUNCTION__, __LINE__);
-    BROWSER_LOGD("uri = [%s], file_path = [%s]", uri.c_str(), file_path.c_str());
-
-    SoupSession *soup_session = nullptr;
-    SoupMessage *soup_msg = nullptr;
-    char *s_filePath = strdup(file_path.c_str());
-
-    soup_session = soup_session_async_new();
-    g_object_set(soup_session, SOUP_SESSION_TIMEOUT, 15, nullptr);
-
-    soup_msg = soup_message_new("GET", uri.c_str());
-    download_request *request = new(std::nothrow) download_request(s_filePath, cb, data);
-    soup_session_queue_message(soup_session, soup_msg, __file_download_finished_cb, static_cast<void*>(request));
-
-    g_object_unref(soup_session);
-    free(s_filePath);
-}
-
-void WebView::__file_download_finished_cb(SoupSession *session, SoupMessage *msg, gpointer data)
-{
-    BROWSER_LOGD("[%s:%d] session : %s", __PRETTY_FUNCTION__, __LINE__, session);
-
-    if (data) {
-        download_request *request = static_cast<download_request*>(data);
-        SoupBuffer *body = soup_message_body_flatten(msg->response_body);
-        int fd = 0;
-        if (body->data && (body->length > 0) && ((fd = open(request->file_path.c_str(), O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) >= 0)) {
-            unsigned int write_len = write(fd, body->data, body->length);
-            close(fd);
-            if (write_len == body->length)
-                request->cb(request->file_path.c_str(), request->data);
-            else
-                unlink(request->file_path.c_str());
-        }
-        g_object_unref(msg);
-        soup_buffer_free(body);
-        delete request;
-    }
-    makeShortcut(s_name, s_pwaData, s_icon);
-}
-
-void WebView::__download_result_cb(const std::string& file_path, void *data)
-{
-    BROWSER_LOGD("[%s:%d] file_path = [%s], data = [%s]", file_path.c_str(), data);
-    BROWSER_LOGD("[%s:%d] complete !", __PRETTY_FUNCTION__, __LINE__);
+    ewk_view_request_manifest(m_ewkView, OnDidGetManifestCb, this);
 }
 
 std::string WebView::getTitle(void)
@@ -776,65 +601,25 @@ void WebView::__closeWindowRequest(void *data, Evas_Object *, void *)
     m_webEngine->closeTab(self->getTabId());
 }
 
-void WebView::__setManifestData(Evas_Object *view, Ewk_View_Request_Manifest *manifest, void *data)
+void WebView::OnDidGetManifestCb(Evas_Object *view, Ewk_View_Request_Manifest *manifest, void *data)
 {
     BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
-
-    if (view && data) {
-        WebView *self = reinterpret_cast<WebView *>(data);
-
-        if (manifest) {
-            const char *tmp;
-            self->m_manifestData.m_push_id = ((tmp = ewk_manifest_push_sender_id_get(manifest)) ? tmp : "");
-            self->m_manifestData.short_name = ((tmp = ewk_manifest_short_name_get(manifest)) ? tmp : "");
-            self->m_manifestData.name = ((tmp = ewk_manifest_name_get(manifest)) ? tmp : "");
-            self->m_manifestData.start_url = ((tmp = ewk_manifest_start_url_get(manifest)) ? tmp : "");
-            self->m_manifestData.orientation_type = ewk_manifest_orientation_type_get(manifest);
-            self->m_manifestData.web_display_mode = ewk_manifest_web_display_mode_get(manifest);
-            self->m_manifestData.theme_color.colorExist = ewk_manifest_theme_color_get(
-                manifest,
-                &self->m_manifestData.theme_color.r,
-                &self->m_manifestData.theme_color.g,
-                &self->m_manifestData.theme_color.b,
-                &self->m_manifestData.theme_color.a);
-            self->m_manifestData.background_color.colorExist = ewk_manifest_background_color_get(
-                manifest,
-                &self->m_manifestData.background_color.r,
-                &self->m_manifestData.background_color.g,
-                &self->m_manifestData.background_color.b,
-                &self->m_manifestData.background_color.a);
-
-            self->m_manifestData.icons_count = ewk_manifest_icons_count_get(manifest);
-            self->m_manifestData.icons.clear();
-            for (size_t iconNumber = 0; iconNumber < self->m_manifestData.icons_count; iconNumber++) {
-                ManifestData::_icon icon;
-                icon.src = ((tmp = ewk_manifest_icons_src_get(manifest, iconNumber)) ? tmp : "");
-                icon.type = ((tmp = ewk_manifest_icons_type_get(manifest, iconNumber)) ? tmp : "");
-                icon.sizes_count = ewk_manifest_icons_sizes_count_get(manifest, iconNumber);
-                for (size_t sizeNumber = 0; sizeNumber < icon.sizes_count; sizeNumber++) {
-                    ManifestData::_icon::_size size;
-                    size.width = ewk_manifest_icons_width_get(manifest, iconNumber, sizeNumber);
-                    size.height = ewk_manifest_icons_height_get(manifest, iconNumber, sizeNumber);
-                    icon.sizes.push_back(size);
-                }
-                self->m_manifestData.icons.push_back(icon);
-            }
-
-            if (!self->m_manifestData.name.empty() && !self->m_manifestData.start_url.empty()) {
-                self->m_manifestReady = true;
-                self->handleManifest();
-            } else {
-                BROWSER_LOGW("No Name and url in manifest!");
-            }
-
-        } else {
-            BROWSER_LOGW("No manifest for webview!");
-            std::string uri = self->getURI();
-             shortcut_add_to_home(self->m_title.c_str(), LAUNCH_BY_URI, uri.c_str(), nullptr, 0, result_cb, nullptr);
-        }
-    } else {
+    auto self = static_cast<WebView*>(data);
+    if (!view || !data) {
         BROWSER_LOGW("No View or data!");
+        return;
     }
+
+    if (!manifest) {
+        BROWSER_LOGW("No manifest for webview!");
+        std::string uri = self->getURI();
+        shortcut_add_to_home(self->m_title.c_str(), LAUNCH_BY_URI, uri.c_str(),
+                             nullptr, 0, PWAHandler::OnDidMakeShortcutCb, nullptr);
+        return;
+    }
+
+    ManifestData manifest_data = self->m_pwaHandler->GetManifestData(manifest);
+    self->m_pwaHandler->TriggerPWAInstallation(manifest_data);
 }
 
 void WebView::__loadStarted(void * data, Evas_Object * /* obj */, void * /* event_info */)
@@ -934,7 +719,6 @@ void WebView::__urlChanged(void * data, Evas_Object * /* obj */, void * /* event
     WebView * self = reinterpret_cast<WebView *>(data);
     BROWSER_LOGD("URL changed for tab: %s", self->getTabId().toString().c_str());
     self->uriChanged(self->getURI());
-    self->m_manifestReady = false;
 }
 
 void WebView::__backForwardListChanged(void * data, Evas_Object * /* obj */, void * /* event_info */)
@@ -1761,20 +1545,6 @@ void WebView::__policy_navigation_decide_cb(void *data, Evas_Object * /*obj*/, v
     ewk_policy_decision_use(policy_decision);
 }
 
-#if PWE_SHUB
-void WebView::__install_pwa_request_cb(Evas_Object* ewk_view, Ewk_App_Installation_Request* request, void* user_data)
-{
-    BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__);
-    auto webView = static_cast<WebView*>(user_data);
-    Ewk_View_Request_Manifest* manifest = ewk_app_installation_request_manifest_get(request);
-    webView->__setManifestData(ewk_view, manifest, user_data);
-    const char* tmp = ewk_app_installation_request_service_worker_url_get(request);
-    std::string serviceWorkerURL = (tmp) ? tmp : "";
-    // Trigger installation
-    webView->setPWAData(serviceWorkerURL);
-}
-#endif
-
 } /* namespace webengine_service */
 } /* end of basic_webengine */
 } /* end of tizen_browser */
index 459c297330b713e26cdcb20b491494f0f8ccff01..f1d967816d4cb65d1c3839c5704026b51a2fbafc 100755 (executable)
@@ -18,6 +18,7 @@
 #define WEBVIEW_H_
 
 #include <boost/signals2/signal.hpp>
+#include <memory>
 #include <string>
 #include <vector>
 #include <Evas.h>
@@ -29,6 +30,7 @@
 #include "AbstractWebEngine/WebConfirmation.h"
 #include "AbstractWebEngine.h"
 #include "GeneralTools.h"
+#include "PWAHandler.h"
 
 #include <app_control.h>
 #include <app.h>
@@ -66,50 +68,12 @@ namespace tools {
 class BrowserImage;
 }
 
-enum class ManifestType {
-    PWA_MANIFEST,
-    QUICKACCESS_MANIFEST,
-    THEME_MANIFEST
-};
-
-struct ManifestData {
-    ManifestData() = default;
-    std::string short_name;
-    std::string name;
-    std::string start_url;
-    Ewk_View_Orientation_Type orientation_type;
-    Ewk_View_Web_Display_Mode web_display_mode;
-    struct _color {
-        _color() = default;
-        unsigned colorExist;
-        uint8_t r, g, b, a;
-    } theme_color, background_color;
-    size_t icons_count;
-    struct _icon {
-        _icon() = default;
-        std::string src;
-        std::string type;
-        size_t sizes_count;
-        struct _size {
-            _size() = default;
-            int width;
-            int height;
-        };
-        std::vector<_size> sizes;
-    };
-    std::vector<_icon> icons;
-    std::string m_push_id;
-};
-
 namespace basic_webengine {
 
 class TabOrigin;
 
 namespace webengine_service {
 
-using download_finish_callback = void (*)(const std::string& file_path, void *data);
-using ManifestTypesVector = std::vector<ManifestType>;
-
 class WebView
     : public tizen_browser::interfaces::AbstractRotatable
 {
@@ -144,33 +108,6 @@ public:
     bool isLoadError() const;
 
     void requestManifest(void);
-    bool isManifestReady() { return m_manifestReady; }
-    void handleManifest();
-    void addManifestTypeToHandle(const ManifestType &type) { m_manifestVector.push_back(type); }
-
-    void setPWAData(const std::string& serviceWorkerURL = "");
-
-    void request_file_download(const std::string& uri, const std::string& file_path, download_finish_callback cb, void *data);
-
-    struct download_request
-    {
-    public:
-        download_request(char* file_path_ = nullptr, download_finish_callback cb_ = nullptr, void* data_ = nullptr)
-            : file_path(file_path_)
-            , cb(cb_)
-            , data(data_)
-        {}
-
-        ~download_request() {}
-
-        std::string file_path;
-        download_finish_callback cb;
-        void *data;
-
-    private:
-        download_request& operator=(const download_request&);
-        download_request(const download_request&);
-    };
 
     std::map<std::string, std::vector<std::string> > parse_uri(const char *uriToParse);
 
@@ -180,6 +117,8 @@ public:
 #endif
     void confirmationResult(WebConfirmationPtr);
 
+    PWAHandler* GetPWAHandler() { return m_pwaHandler.get(); }
+
     std::shared_ptr<tizen_browser::tools::BrowserImage> captureSnapshot(int width, int height, bool async,
             tizen_browser::tools::SnapshotType snapshot_type);
 
@@ -353,8 +292,6 @@ public:
 
     boost::signals2::signal<void(int,int,int,int)> changeUIColor;
 
-    boost::signals2::signal<unsigned(const std::string&, const std::string&, const std::string&)> installPWA;
-    boost::signals2::signal<void(const unsigned&,const std::string&)> storePWAShortcut;
     boost::signals2::signal<std::string(const char*, const char* )> pushSignal;
     boost::signals2::signal<unsigned(const std::string&, const bool&)> storePermission;
     boost::signals2::signal<unsigned(const std::string&)> getPermissionId;
@@ -372,12 +309,8 @@ private:
 
     static void __newWindowRequest(void * data, Evas_Object *, void *out);
     static void __closeWindowRequest(void * data, Evas_Object *, void *);
-    static void __setManifestData(Evas_Object* view, Ewk_View_Request_Manifest* manifest, void *data);
+    static void OnDidGetManifestCb(Evas_Object* view, Ewk_View_Request_Manifest* manifest, void *data);
 
-    static int result_cb(int ret, void *data);
-    static void makeShortcut(const std::string& name, const std::string& pwaData, const std::string& icon);
-    static void __file_download_finished_cb(SoupSession *session, SoupMessage *msg, gpointer data);
-    static void __download_result_cb(const std::string& file_path, void *data);
     static void _push_cb(const char *sender_id, const char *, void *data);
 
     context_menu_type _get_menu_type(Ewk_Context_Menu *menu);
@@ -442,10 +375,6 @@ private:
     // Screenshot capture
     static void __screenshotCaptured(Evas_Object* image, void* user_data);
 
-#if PWE_SHUB
-    static void __install_pwa_request_cb(Evas_Object* /*ewk_view*/, Ewk_App_Installation_Request* request, void* user_data);
-#endif
-
     Evas_Object * m_parent;
     TabId m_tabId;
     Evas_Object * m_ewkView;
@@ -466,17 +395,10 @@ private:
     TabOrigin m_origin;
 
     std::map<CertificateConfirmationPtr, Ewk_Certificate_Policy_Decision *> m_confirmationCertificatenMap;
-    ManifestData m_manifestData;
-    bool m_manifestReady;
-    ManifestTypesVector m_manifestVector;
 
     static const std::string COOKIES_PATH;
-    static std::string s_pwaData;
-    static std::string s_name;
-    static std::string s_start_url;
-    static std::string s_icon;
-    static const std::string DOWNLOAD_PATH;
 
+    std::unique_ptr<PWAHandler> m_pwaHandler;
     DownloadControl* m_downloadControl;
     int m_policyCounter;
     bool m_imeState;