From 64527f72f0990d9a5f3b7bc6bd4dc4355b27046f Mon Sep 17 00:00:00 2001 From: "surya.kumar7" Date: Wed, 15 May 2019 22:39:09 +0530 Subject: [PATCH 01/16] Refactor termination sequence 1. Termination logic has been altered to navigate toward one sink for different termination requests 2. UI/Watch app loop cycle is destroyed before electron app's quit is called Linked to: https://review.tizen.org/gerrit/205432 Change-Id: I471cf5896e7045a395ebe4a85fcb97962444721b Signed-off-by: surya.kumar7 --- wrt_app/src/runtime.js | 16 +++++++++++----- wrt_app/src/web_application.js | 15 +++++++++++---- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/wrt_app/src/runtime.js b/wrt_app/src/runtime.js index cafec8f..33596ba 100755 --- a/wrt_app/src/runtime.js +++ b/wrt_app/src/runtime.js @@ -37,6 +37,7 @@ class Runtime { }); app.on('before-quit', function(event) { console.log('before-quit'); + wrt.exit(); }); app.on('will-quit', function(event) { console.log('will-quit'); @@ -45,7 +46,6 @@ class Runtime { }); app.on('quit', function(event) { console.log('quit'); - wrt.exit(); }); app.on('browser-window-blur', function() { console.log('browser-window-blur'); @@ -65,7 +65,9 @@ class Runtime { }); app.on('window-all-closed', function(event) { console.log('window-all-closed'); - app.quit(); + // For Tizen Apps, quit will be called from web_application.js + if (!_this.webApplication) + app.quit(); }); app.on('will-finish-launching', function(event) { console.log('will-finish-launching'); @@ -152,15 +154,19 @@ class Runtime { }); wrt.on('suspend', function() { console.log('suspend'); - _this.webApplication.suspend(); + if (_this.webApplication) + _this.webApplication.suspend(); }); wrt.on('resume', function() { console.log('resume'); - _this.webApplication.resume(); + if (_this.webApplication) + _this.webApplication.resume(); }); wrt.on('terminate', function() { console.log('terminate'); - _this.webApplication.terminate(); + if (_this.webApplication) + _this.webApplication.terminate(); + else app.quit(); }); } onLanguageChanged() {} diff --git a/wrt_app/src/web_application.js b/wrt_app/src/web_application.js index 81e3b4d..fd9b5e4 100755 --- a/wrt_app/src/web_application.js +++ b/wrt_app/src/web_application.js @@ -53,14 +53,16 @@ class WebApplication { console.log(`window closed : #${self.windowList.length}`); let index = self.windowList.indexOf(window); self.windowList.splice(index, 1); - if (!self.isTerminating && index === self.windowList.length && self.windowList.length > 0) + if (!self.windowList.length) + self.terminate(); + else if (index === self.windowList.length) self.windowList[self.windowList.length - 1].show(); }); }); app.on('web-contents-created', function(event, webContents) { webContents.on('crashed', function() { console.error('webContents crashed'); - app.exit(100); + self.terminate(); }); webContents.session.setPermissionRequestHandler(function(webContents, permission, callback) { console.log(`handlePermissionRequests for ${permission}`); @@ -225,7 +227,7 @@ class WebApplication { let windows = BrowserWindow.getAllWindows(); if (!this.multitaskingSupport) { console.log('multitasking is not supported; quitting app') - app.quit(); + this.terminate(); } else if (!this.backgroundSupport) { windows.forEach((window) => window.setEnabled(false)); } @@ -245,7 +247,12 @@ class WebApplication { this.windowList[this.windowList.length - 1].show(); } terminate() { - this.isTerminating = true; + console.log('WebApplication : terminate'); + if (!this.isTerminating) { + console.log('terminating app'); + this.isTerminating = true; + app.quit(); + } else console.log('termination is already in progress'); } sendAppControlEvent() { const kAppControlEventScript = -- 2.7.4 From bccffdbaeced449640d95ed3f35b43bf5fe41b55 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Tue, 21 May 2019 14:15:54 +0900 Subject: [PATCH 02/16] Hide splash screen when load completed Crosswalk hide the splash screen 'load,complete' callback when if the option is ready_when=complete, thus 'did-finish-load' is proper time for 'complete' Change-Id: Icafac00ad2af2f88b9789faeaeb796002ef11df4 --- wrt_app/src/web_application.js | 1 + 1 file changed, 1 insertion(+) diff --git a/wrt_app/src/web_application.js b/wrt_app/src/web_application.js index fd9b5e4..16ab876 100755 --- a/wrt_app/src/web_application.js +++ b/wrt_app/src/web_application.js @@ -209,6 +209,7 @@ class WebApplication { }); this.mainWindow.webContents.on('did-finish-load', function() { console.log(`webContents did-finish-load preloadState: ${self.preloadState}`); + wrt.hideSplashScreen(2); if (wrt.isIMEWebApp()) self.activateIMEWebHelperClient(); if (self.preloadState === 'readyToShow' || self.preloadState === 'preload') { -- 2.7.4 From 7a237700720fea45b8c6d864579bfbee0e17368c Mon Sep 17 00:00:00 2001 From: "hyunduk.kim" Date: Wed, 22 May 2019 21:38:38 -0700 Subject: [PATCH 03/16] Removing duplicated code for 'will-finish-launching' Duplicated code for 'will-finish-launching' has been removed Change-Id: I4b9c1503184ccc02d79a9e17c5d1dfae5dc3566a Signed-off-by: hyunduk.kim --- wrt_app/src/runtime.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/wrt_app/src/runtime.js b/wrt_app/src/runtime.js index 33596ba..8fcdcf1 100755 --- a/wrt_app/src/runtime.js +++ b/wrt_app/src/runtime.js @@ -32,9 +32,6 @@ class Runtime { this.debug_mode = false; var _this = this; - app.on('will-finish-launching', function() { - console.log('will-finish-launching'); - }); app.on('before-quit', function(event) { console.log('before-quit'); wrt.exit(); -- 2.7.4 From 515f5b8bb70a422e4684c64a66c3645f74840f6c Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Fri, 31 May 2019 11:18:16 +0900 Subject: [PATCH 04/16] Suspend the app if app has gone behind When an app's visibility is changed as background even the app had not been get foreground event, this app should be suspended to avoid running in background mode. If the app has backgroundSupport mode, when suspeding, it will be skipped. This feature only can work with TV profile due to "wrt.getAppState" This patch is depend on https://review.tizen.org/gerrit/204707 Change-Id: I3c05f4c4f61b23c5b510e3ec058d60253a94e8a7 --- wrt_app/src/web_application.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/wrt_app/src/web_application.js b/wrt_app/src/web_application.js index 16ab876..3f242e9 100755 --- a/wrt_app/src/web_application.js +++ b/wrt_app/src/web_application.js @@ -41,6 +41,8 @@ class WebApplication { this.accessiblePath = wrt.getAccessiblePath(); this.isTerminating = false; this.suspended = true; + this.loadFinished = false; + this.runningStatus = 'none'; let self = this; app.on('browser-window-created', function(event, window) { @@ -157,6 +159,13 @@ class WebApplication { self.pendingCallbacks.delete(id); } }); + wrt.on('app-status-changed', function(event, status) { + console.log(`runningStatus: ${status}, ${self.loadFinished}`); + self.runningStatus = status; + if (self.loadFinished && self.runningStatus == 'behind') { + self.suspend(); + } + }); } getBrowserWindowOption(options) { return { @@ -206,15 +215,18 @@ class WebApplication { }); this.mainWindow.webContents.on('did-start-loading', function() { console.log('webContents did-start-loading'); + self.loadFinished = false; }); this.mainWindow.webContents.on('did-finish-load', function() { - console.log(`webContents did-finish-load preloadState: ${self.preloadState}`); + console.log(`webContents did-finish-load preloadState: ${self.preloadState}, status: ${self.runningStatus}`); + self.loadFinished = true; wrt.hideSplashScreen(2); if (wrt.isIMEWebApp()) self.activateIMEWebHelperClient(); - if (self.preloadState === 'readyToShow' || self.preloadState === 'preload') { + if (self.preloadState === 'readyToShow' || self.preloadState === 'preload' || self.runningStatus === 'behind') { self.suspend(); - wrt.notifyAppStatus('preload'); + if (self.runningStatus !== 'behind') + wrt.notifyAppStatus('preload'); } }); } -- 2.7.4 From 4e0f074e615384015f15b17ac0dad5fe4deecdd7 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Wed, 8 May 2019 16:17:52 +0900 Subject: [PATCH 05/16] [VD]Always reloading if force.loadDefaultURI is true When eden_resume by preview selecting and if wrt.isAlwaysReload() is true, the app has to be reloaded Change-Id: I23bd91cff8ff8eab018659118b2a1685c203a2c7 --- wrt_app/src/runtime.js | 2 +- wrt_app/src/web_application.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/wrt_app/src/runtime.js b/wrt_app/src/runtime.js index 8fcdcf1..a00c759 100755 --- a/wrt_app/src/runtime.js +++ b/wrt_app/src/runtime.js @@ -122,7 +122,7 @@ class Runtime { return; } - let reload = loadInfo.getReload(); + let reload = loadInfo.getReload() || _this.webApplication.isAlwaysReload; if (!reload) { if (src != _this.webApplication.mainWindow.getURL()) reload = true; diff --git a/wrt_app/src/web_application.js b/wrt_app/src/web_application.js index 3f242e9..ad29498 100755 --- a/wrt_app/src/web_application.js +++ b/wrt_app/src/web_application.js @@ -39,6 +39,7 @@ class WebApplication { this.preloadState = 'none'; } this.accessiblePath = wrt.getAccessiblePath(); + this.isAlwaysReload = wrt.isAlwaysReload(); this.isTerminating = false; this.suspended = true; this.loadFinished = false; -- 2.7.4 From 15dca7383c7a1b5901e1ac19ef5eee9111eca8ff Mon Sep 17 00:00:00 2001 From: Aron Kim Date: Mon, 27 May 2019 20:14:13 +0900 Subject: [PATCH 06/16] Revert "Refactor termination sequence" This reverts commit 64527f72f0990d9a5f3b7bc6bd4dc4355b27046f. This is an additional patch due to the ContextMenu implementation. This patch is not required when the ContextMenu is refactored. Linked to: https://review.tizen.org/gerrit/#/c/platform/framework/web/chromium-efl/+/207875/ Change-Id: I923fafed04f3979f6d8d4a09ac383eab00685517 Signed-off-by: Aron Kim --- wrt_app/src/runtime.js | 16 +++++----------- wrt_app/src/web_application.js | 15 ++++----------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/wrt_app/src/runtime.js b/wrt_app/src/runtime.js index 8fcdcf1..ebc0037 100755 --- a/wrt_app/src/runtime.js +++ b/wrt_app/src/runtime.js @@ -34,7 +34,6 @@ class Runtime { var _this = this; app.on('before-quit', function(event) { console.log('before-quit'); - wrt.exit(); }); app.on('will-quit', function(event) { console.log('will-quit'); @@ -43,6 +42,7 @@ class Runtime { }); app.on('quit', function(event) { console.log('quit'); + wrt.exit(); }); app.on('browser-window-blur', function() { console.log('browser-window-blur'); @@ -62,9 +62,7 @@ class Runtime { }); app.on('window-all-closed', function(event) { console.log('window-all-closed'); - // For Tizen Apps, quit will be called from web_application.js - if (!_this.webApplication) - app.quit(); + app.quit(); }); app.on('will-finish-launching', function(event) { console.log('will-finish-launching'); @@ -151,19 +149,15 @@ class Runtime { }); wrt.on('suspend', function() { console.log('suspend'); - if (_this.webApplication) - _this.webApplication.suspend(); + _this.webApplication.suspend(); }); wrt.on('resume', function() { console.log('resume'); - if (_this.webApplication) - _this.webApplication.resume(); + _this.webApplication.resume(); }); wrt.on('terminate', function() { console.log('terminate'); - if (_this.webApplication) - _this.webApplication.terminate(); - else app.quit(); + _this.webApplication.terminate(); }); } onLanguageChanged() {} diff --git a/wrt_app/src/web_application.js b/wrt_app/src/web_application.js index 3f242e9..d578788 100755 --- a/wrt_app/src/web_application.js +++ b/wrt_app/src/web_application.js @@ -55,16 +55,14 @@ class WebApplication { console.log(`window closed : #${self.windowList.length}`); let index = self.windowList.indexOf(window); self.windowList.splice(index, 1); - if (!self.windowList.length) - self.terminate(); - else if (index === self.windowList.length) + if (!self.isTerminating && index === self.windowList.length && self.windowList.length > 0) self.windowList[self.windowList.length - 1].show(); }); }); app.on('web-contents-created', function(event, webContents) { webContents.on('crashed', function() { console.error('webContents crashed'); - self.terminate(); + app.exit(100); }); webContents.session.setPermissionRequestHandler(function(webContents, permission, callback) { console.log(`handlePermissionRequests for ${permission}`); @@ -240,7 +238,7 @@ class WebApplication { let windows = BrowserWindow.getAllWindows(); if (!this.multitaskingSupport) { console.log('multitasking is not supported; quitting app') - this.terminate(); + app.quit(); } else if (!this.backgroundSupport) { windows.forEach((window) => window.setEnabled(false)); } @@ -260,12 +258,7 @@ class WebApplication { this.windowList[this.windowList.length - 1].show(); } terminate() { - console.log('WebApplication : terminate'); - if (!this.isTerminating) { - console.log('terminating app'); - this.isTerminating = true; - app.quit(); - } else console.log('termination is already in progress'); + this.isTerminating = true; } sendAppControlEvent() { const kAppControlEventScript = -- 2.7.4 From 7f55675fb5c0b5b9f285ce901d7021ba79b6ed6f Mon Sep 17 00:00:00 2001 From: SangYong Park Date: Tue, 11 Jun 2019 17:10:54 +0900 Subject: [PATCH 07/16] Change termination timing for non multitasking app e-manual app calls launchAppControl in visibilitychange event handler. but, wrtjs terminate app as soon as app status is suspend. so, add termination delay for visibilitychange event handling. Change-Id: Ie2bd615e44643bbb74410d9c4fab2c85b6fe9ce4 Signed-off-by: SangYong Park --- wrt_app/src/web_application.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/wrt_app/src/web_application.js b/wrt_app/src/web_application.js index d578788..78ef215 100755 --- a/wrt_app/src/web_application.js +++ b/wrt_app/src/web_application.js @@ -237,8 +237,11 @@ class WebApplication { } let windows = BrowserWindow.getAllWindows(); if (!this.multitaskingSupport) { - console.log('multitasking is not supported; quitting app') - app.quit(); + // FIXME : terminate app after visibilitychange event handling + setTimeout(() => { + console.log('multitasking is not supported; quitting app') + app.quit(); + }, 1000); } else if (!this.backgroundSupport) { windows.forEach((window) => window.setEnabled(false)); } -- 2.7.4 From 4be11d29c158cd884c943dc55fed19b31359b02d Mon Sep 17 00:00:00 2001 From: "hyunduk.kim" Date: Fri, 21 Jun 2019 00:54:49 -0700 Subject: [PATCH 08/16] Change names related to addon properly It changes : - 'extension_manager' to 'addon_manager' - IPC messages' names related to addon - instance name of addon in runtime - variables' names related to addon Change-Id: Ifc56a4c6457a1ab9a3e78b30432c77407761a0e3 Signed-off-by: hyunduk.kim --- .../src/{extension_manager.js => addon_manager.js} | 222 ++++++++++----------- wrt_app/src/ipc_message.js | 10 +- wrt_app/src/main.js | 2 +- wrt_app/src/runtime.js | 36 ++-- 4 files changed, 135 insertions(+), 135 deletions(-) rename wrt_app/src/{extension_manager.js => addon_manager.js} (52%) mode change 100755 => 100644 diff --git a/wrt_app/src/extension_manager.js b/wrt_app/src/addon_manager.js old mode 100755 new mode 100644 similarity index 52% rename from wrt_app/src/extension_manager.js rename to wrt_app/src/addon_manager.js index 3488428..7c7c449 --- a/wrt_app/src/extension_manager.js +++ b/wrt_app/src/addon_manager.js @@ -18,46 +18,46 @@ const fs = require('fs'); const path = require('path'); -const EXT_PATH = +const ADN_PATH = path.join(require('os').homedir(), 'data/electron/runtime_addon'); const MANIFEST_FILE = 'manifest.json'; const PRELOAD_JS_FILE = 'preload.js'; -const EXTENSIONS_DB_FILE = 'extensions_db.json'; +const ADDONS_DB_FILE = 'addons_db.json'; const T_CRX = 'CRX'; const T_WRT = 'WRT'; const T_API = 'API'; const {BrowserWindow} = require('electron'); -class ExtensionManager { +class AddonManager { constructor() { - this.extensions_list_ = null; - this.extensions_ = null; - this.extensions_API_ = null; + this.addons_list_ = null; + this.addons_ = null; + this.addons_API_ = null; } printAPIs() { console.log('==========printAPIs=========='); - for (var namespace in this.extensions_API_) { + for (var namespace in this.addons_API_) { console.log('namespace: ' + namespace); - for (var entry_symbol in this.extensions_API_[namespace]) { - console.log('extensions_API[' + namespace + '][' + entry_symbol + '] = ' + this.extensions_API_[namespace][entry_symbol]); + for (var entry_symbol in this.addons_API_[namespace]) { + console.log('addons_API[' + namespace + '][' + entry_symbol + '] = ' + this.addons_API_[namespace][entry_symbol]); } } } - loadExtensionsListFromPath() { - var extensions_list = [], + loadAddonsListFromPath() { + var addons_list = [], filenames; try { - filenames = fs.readdirSync(EXT_PATH); + filenames = fs.readdirSync(ADN_PATH); } catch (e) { - console.error('LoadExtensionsListFromPath - fs.readdirSync error : ' + e); + console.error('LoadAddonsListFromPath - fs.readdirSync error : ' + e); return false; } if (filenames) { for (var i in filenames) { var filename = filenames[i], - filepath = path.join(EXT_PATH, filename), + filepath = path.join(ADN_PATH, filename), stats = fs.statSync(filepath); if (stats.isDirectory()) { @@ -67,48 +67,48 @@ class ExtensionManager { try { manifest_obj = JSON.parse(fs.readFileSync(manifest_path)); } catch (e) { - console.error('LoadExtensionsListFromPath - error : ' + e); + console.error('LoadAddonsListFromPath - error : ' + e); continue; } - var extension = new Object(); + var addon = new Object(); - extension.name = manifest_obj.name; - extension.path = filepath; + addon.name = manifest_obj.name; + addon.path = filepath; if (manifest_obj.type) { - extension.type = manifest_obj.type; + addon.type = manifest_obj.type; } else { - extension.type = 'WRT'; + addon.type = 'WRT'; } - extension.activate = true; // activate by default - extensions_list.push(extension); + addon.activate = true; // activate by default + addons_list.push(addon); } } } - this.extensions_list_ = extensions_list; - console.log('LoadExtensionsListFromPath ; ' + JSON.stringify(this.extensions_list_)); + this.addons_list_ = addons_list; + console.log('LoadAddonsListFromPath ; ' + JSON.stringify(this.addons_list_)); return true; } loadJsonDB(db_path) { if (!db_path) { - db_path = path.join(EXT_PATH, EXTENSIONS_DB_FILE); + db_path = path.join(ADN_PATH, ADDONS_DB_FILE); } - var extensions_list; + var addons_list; try { - extensions_list = JSON.parse(fs.readFileSync(db_path)); + addons_list = JSON.parse(fs.readFileSync(db_path)); } catch (e) { console.error('LoadJsonDB - open error : ' + e); return false; - // For DEBUG purpose (load extensions from PATH, not via INSTALLER) - //return this.loadExtensionsListFromExtPath(); + // For DEBUG purpose (load addons from PATH, not via INSTALLER) + //return this.loadAddonsListFromAdnPath(); } - this.extensions_list_ = extensions_list; + this.addons_list_ = addons_list; return true; } saveJsonDB(db_path) { if (!db_path) { - db_path = path.join(EXT_PATH, EXTENSIONS_DB_FILE); + db_path = path.join(ADN_PATH, ADDONS_DB_FILE); } var fd; try { @@ -117,14 +117,14 @@ class ExtensionManager { console.error('SaveJsonDB - open error : ' + e); return false; } - fs.writeSync(fd, JSON.stringify(this.extensions_list_)); + fs.writeSync(fd, JSON.stringify(this.addons_list_)); fs.closeSync(fd); return true; } generateJsFromAPIs(js_path) { if (!js_path) { - js_path = path.join(EXT_PATH, PRELOAD_JS_FILE); + js_path = path.join(ADN_PATH, PRELOAD_JS_FILE); } console.log('preload.js : ' + js_path); var fd; @@ -135,18 +135,18 @@ class ExtensionManager { return false; } // Introduction Comments & preset - var comments = '// Auto-generated code by extensions_installer\n// Generated from “entry_points” field in package.json\n// var = ;\n'; - var preset = '\nvar EXTENSIONS_PATH = process.env.WAS_EXTENSIONS_PATH;\n'; + var comments = '// Auto-generated code by addons_installer\n// Generated from “entry_points” field in package.json\n// var = ;\n'; + var preset = '\nvar ADDONS_PATH = process.env.WAS_EXTENSIONS_PATH;\n'; fs.writeSync(fd, comments + preset); // namespace - for (var namespace in this.extensions_API_) { + for (var namespace in this.addons_API_) { if (namespace != '_default_') { fs.writeSync(fd, '\n//namespace\n'); fs.writeSync(fd, 'var ' + namespace + ' = new Object();\n'); // namespace.entry_points fs.writeSync(fd, '\n//namespace.entry_points\n'); - for (var entry_symbol in this.extensions_API_[namespace]) { - fs.writeSync(fd, namespace + '.' + entry_symbol + ' = require("' + this.extensions_API_[namespace][entry_symbol] + '");\n'); + for (var entry_symbol in this.addons_API_[namespace]) { + fs.writeSync(fd, namespace + '.' + entry_symbol + ' = require("' + this.addons_API_[namespace][entry_symbol] + '");\n'); } // attach to root fs.writeSync(fd, '\n//attach to window\n'); @@ -155,8 +155,8 @@ class ExtensionManager { // entry_points and attach to root fs.writeSync(fd, '\n//default namespace - entry_points and attach to window\n'); /*eslint no-redeclare: 1*/ - for (var entry_symbol in this.extensions_API_[namespace]) { - fs.writeSync(fd, 'window.' + entry_symbol + ' = require("' + this.extensions_API_[namespace][entry_symbol] + '");\n'); + for (var entry_symbol in this.addons_API_[namespace]) { + fs.writeSync(fd, 'window.' + entry_symbol + ' = require("' + this.addons_API_[namespace][entry_symbol] + '");\n'); } } } @@ -165,42 +165,42 @@ class ExtensionManager { } build() { - // 0. load extensions_list_ from JSON DB + // 0. load addons_list_ from JSON DB this.loadJsonDB(); - var extensions = []; - var extensions_API = []; - // 1. load extensions from extension_list_ - if (this.extensions_list_) { - for (var i in this.extensions_list_) { - var extension = this.extensions_list_[i]; - if (extension.activate == false) { + var addons = []; + var addons_API = []; + // 1. load addons from addon_list_ + if (this.addons_list_) { + for (var i in this.addons_list_) { + var addon = this.addons_list_[i]; + if (addon.activate == false) { continue; } try { - var manifest_obj, manifest_path = path.join(extension.path, MANIFEST_FILE); + var manifest_obj, manifest_path = path.join(addon.path, MANIFEST_FILE); manifest_obj = JSON.parse(fs.readFileSync(manifest_path)); console.log('manifest_obj : ' + JSON.stringify(manifest_obj)); if (manifest_obj.type && manifest_obj.type.toUpperCase() === 'INSTALLER') { - // do nothing for installer extension - console.log('ExtensionManager.build ' + manifest_obj.name + ' is for installer - SKIP'); + // do nothing for installer addon + console.log('AddonManager.build ' + manifest_obj.name + ' is for installer - SKIP'); continue; } else if (manifest_obj.type && manifest_obj.type.toUpperCase() === 'API') { var namespace = manifest_obj.namespace; if (!namespace) { namespace = '_default_'; } - if (!extensions_API[namespace]) { - extensions_API[namespace] = []; + if (!addons_API[namespace]) { + addons_API[namespace] = []; } for (var entry_it in manifest_obj.entry_points) { for (var entry_symbol in manifest_obj.entry_points[entry_it]) { var module_path = manifest_obj.entry_points[entry_it][entry_symbol]; - if (extensions_API[namespace][entry_symbol]) { - console.log('extensions_API[' + namespace + '][' + entry_symbol + '] already registered :' + extensions_API[namespace][entry_symbol]); + if (addons_API[namespace][entry_symbol]) { + console.log('extensions_API[' + namespace + '][' + entry_symbol + '] already registered :' + addons_API[namespace][entry_symbol]); continue; } - extensions_API[namespace][entry_symbol] = path.join(extension.path, module_path); - console.log('extensions_API[' + namespace + '][' + entry_symbol + '] registered :' + extensions_API[namespace][entry_symbol]); + addons_API[namespace][entry_symbol] = path.join(addon.path, module_path); + console.log('addons_API[' + namespace + '][' + entry_symbol + '] registered :' + addons_API[namespace][entry_symbol]); } } } else { @@ -210,62 +210,62 @@ class ExtensionManager { } else { type = T_CRX; } - if (!extensions[type]) { - extensions[type] = []; + if (!addons[type]) { + addons[type] = []; } - if (extensions[type][manifest_obj.name]) { - console.log('extensions[' + type + '][' + manifest_obj.name + '] already registered : ' + extensions[type][manifest_obj.name]); + if (addons[type][manifest_obj.name]) { + console.log('addons[' + type + '][' + manifest_obj.name + '] already registered : ' + addons[type][manifest_obj.name]); continue; } if (manifest_obj.main) { - extensions[type][manifest_obj.name] = path.join(extension.path, manifest_obj.main); + addons[type][manifest_obj.name] = path.join(addon.path, manifest_obj.main); } else { - extensions[type][manifest_obj.name] = extension.path; + addons[type][manifest_obj.name] = addon.path; } } - console.log('extensions[' + type + '][' + manifest_obj.name + '] = ' + extensions[type][manifest_obj.name] + ' registered'); + console.log('addons[' + type + '][' + manifest_obj.name + '] = ' + addons[type][manifest_obj.name] + ' registered'); } catch (e) { - console.error('ExtensionManager.build error - ' + e); + console.error('AddonManager.build error - ' + e); } } } - if (this.extensions_ != null) { - delete this.extensions_; - this.extensions_ = null; + if (this.addons_ != null) { + delete this.addons_; + this.addons_ = null; } - if (this.extensions_API_ != null) { - delete this.extensions_API_; - this.extensions_API_ = null; + if (this.addons_API_ != null) { + delete this.addons_API_; + this.addons_API_ = null; } - this.extensions_ = extensions; - this.extensions_API_ = extensions_API; - return this.extensions_; + this.addons_ = addons; + this.addons_API_ = addons_API; + return this.addons_; } activate(event_emitter, name) { - if (!this.extensions_) { + if (!this.addons_) { return; } - var extension, extension_path = null; - if (this.extensions_[T_WRT] !== undefined && this.extensions_[T_WRT][name] !== undefined) { - extension_path = this.extensions_[T_WRT][name]; - console.log('activate: ' + extension_path + ' name:' + name); + var addon, addon_path = null; + if (this.addons_[T_WRT] !== undefined && this.addons_[T_WRT][name] !== undefined) { + addon_path = this.addons_[T_WRT][name]; + console.log('activate: ' + addon_path + ' name:' + name); try { - extension = require(extension_path); + addon = require(addon_path); } catch (e) { console.error('activate - error on require() : ' + e); return; } - if (extension && extension.activate) { - extension.activate(event_emitter); + if (addon && addon.activate) { + addon.activate(event_emitter); } - else console.log('extension.activate not defined!'); - } else if (this.extensions_[T_CRX] !== undefined && this.extensions_[T_CRX][name] !== undefined) { - extension_path = this.extensions_[T_CRX][name]; - console.log('activate 2: ' + extension_path + ' name:' + name); + else console.log('addon.activate not defined!'); + } else if (this.addons_[T_CRX] !== undefined && this.addons_[T_CRX][name] !== undefined) { + addon_path = this.addons_[T_CRX][name]; + console.log('activate 2: ' + addon_path + ' name:' + name); try { - console.log('BrowserWindow.addExtension: ' + extension_path); - BrowserWindow.addExtension(extension_path); + console.log('BrowserWindow.addExtension: ' + addon_path); + BrowserWindow.addExtension(addon_path); } catch (e) { console.error('activate - error on addExtension() : ' + e); } @@ -274,31 +274,31 @@ class ExtensionManager { } deactivate(event_emitter, name) { - if (!this.extensions_) { + if (!this.addons_) { return; } console.log('deactivate: name:' + name); - var extension, extension_path = null; - if (this.extensions_[T_WRT] !== undefined && this.extensions_[T_WRT][name] !== undefined) { + var addon, addon_path = null; + if (this.addons_[T_WRT] !== undefined && this.addons_[T_WRT][name] !== undefined) { try { - extension_path = this.extensions_[T_WRT][name]; + addon_path = this.addons_[T_WRT][name]; } catch (e) { console.error('deactivate - error : ' + e); return; } - console.log('deactivate: path:' + extension_path); + console.log('deactivate: path:' + addon_path); try { - extension = require(extension_path); + addon = require(addon_path); } catch (e) { console.error('deactivate - error on require() : ' + e); } - if (extension && extension.deactivate) { - extension.deactivate(event_emitter); + if (addon && addon.deactivate) { + addon.deactivate(event_emitter); } else { - console.log('extension.deactivate not defined!'); + console.log('addon.deactivate not defined!'); } - } else if (this.extensions_[T_CRX] !== undefined && this.extensions_[T_CRX][name] !== undefined) { - extension_path = this.extensions_[T_CRX][name]; + } else if (this.addons_[T_CRX] !== undefined && this.addons_[T_CRX][name] !== undefined) { + addon_path = this.addons_[T_CRX][name]; try { BrowserWindow.removeExtension(name); } catch (e) { @@ -308,33 +308,33 @@ class ExtensionManager { } activateAll(event_emitter) { - if (!this.extensions_) { - console.log('activateAll - extensions not built'); + if (!this.addons_) { + console.log('activateAll - addons not built'); return; } - for (var name in this.extensions_[T_WRT]) { + for (var name in this.addons_[T_WRT]) { this.activate(event_emitter, name); } - for (var name in this.extensions_[T_CRX]) { + for (var name in this.addons_[T_CRX]) { this.activate(event_emitter, name); } } deactivateAll(event_emitter) { - if (!this.extensions_) { - console.log('deactivateAll - extensions not built'); + if (!this.addons_) { + console.log('deactivateAll - addons not built'); return; } - for (var name in this.extensions_[T_WRT]) { + for (var name in this.addons_[T_WRT]) { this.deactivate(event_emitter, name); } - for (var name in this.extensions_[T_CRX]) { + for (var name in this.addons_[T_CRX]) { this.deactivate(event_emitter, name); } } isAddonAvailable() { - return Object.keys(this.extensions_).length != 0; + return Object.keys(this.addons_).length != 0; } static getManifestFile() { @@ -345,9 +345,9 @@ class ExtensionManager { return PRELOAD_JS_FILE; } - static getExtensionsPath() { - return EXT_PATH; + static getAddonsPath() { + return ADN_PATH; } } -module.exports = ExtensionManager; +module.exports = AddonManager; diff --git a/wrt_app/src/ipc_message.js b/wrt_app/src/ipc_message.js index 10509db..01f620c 100755 --- a/wrt_app/src/ipc_message.js +++ b/wrt_app/src/ipc_message.js @@ -17,10 +17,10 @@ 'use strict'; module.exports = Object.freeze({ - EXTENSIONS: { - INSTALLED: 'ipc:extensions:installed', - UNINSTALLED: 'ipc:extensions:uninstalled', - ACTIVATE: 'ipc:extensions:activate', - DEACTIVATE: 'ipc:extensions:deactivate' + ADDONS: { + INSTALLED: 'ipc:addons:installed', + UNINSTALLED: 'ipc:addons:uninstalled', + ACTIVATE: 'ipc:addons:activate', + DEACTIVATE: 'ipc:addons:deactivate' } }); diff --git a/wrt_app/src/main.js b/wrt_app/src/main.js index a6ae967..aa07326 100755 --- a/wrt_app/src/main.js +++ b/wrt_app/src/main.js @@ -25,5 +25,5 @@ process.on('uncaughtException', function (error) { new (require('./runtime'))({ devMode: false, - noExtensions: false + noAddons: false }); diff --git a/wrt_app/src/runtime.js b/wrt_app/src/runtime.js index ebc0037..fd1b8fd 100755 --- a/wrt_app/src/runtime.js +++ b/wrt_app/src/runtime.js @@ -17,7 +17,7 @@ 'use strict'; const wrt = require('../browser/wrt'); // Load first for log -const ExtensionManager = require('./extension_manager'); +const AddonManager = require('./addon_manager'); const {app, ipcMain} = require('electron'); const IPC_MESSAGE = require('./ipc_message'); const WAS_EVENT = require('./was_event'); @@ -27,7 +27,7 @@ class Runtime { constructor(options) { this.webApplication = null; this.handleIpcMessages(); - this.extensionManager = null; + this.addonManager = null; this.isLaunched = false; this.debug_mode = false; @@ -37,7 +37,7 @@ class Runtime { }); app.on('will-quit', function(event) { console.log('will-quit'); - _this.extensionManager.deactivateAll(app); + _this.addonManager.deactivateAll(app); _this.killAllProcesses(); }); app.on('quit', function(event) { @@ -53,7 +53,7 @@ class Runtime { app.on('browser-window-created', function() { console.log('browser-window-created'); if (!_this.isLaunched) { - _this.extensionManager.activateAll(app); + _this.addonManager.activateAll(app); _this.isLaunched = true; } }); @@ -69,9 +69,9 @@ class Runtime { }); app.once('ready', function(event) { console.log('ready'); - _this.extensionManager = new ExtensionManager(); - if (!options.noExtensions) { - _this.extensionManager.build(); + _this.addonManager = new AddonManager(); + if (!options.noAddons) { + _this.addonManager.build(); } wrt.importCertificate(''); }); @@ -97,8 +97,8 @@ class Runtime { console.log('Tizen Web App launch'); if (!_this.webApplication) { console.log('Creating WebApplication'); - options.isAddonAvailable = !options.noExtensions && - _this.extensionManager.isAddonAvailable(); + options.isAddonAvailable = !options.noAddons && + _this.addonManager.isAddonAvailable(); options.launchMode = appControl.getData('http://samsung.com/appcontrol/data/launch_mode'); _this.webApplication = new WebApplication(options); _this.webApplication.mainWindow.loadURL(src); @@ -165,22 +165,22 @@ class Runtime { killAllProcesses() {} handleIpcMessages() { var _this = this; - ipcMain.on(IPC_MESSAGE.EXTENSIONS.INSTALLED, (sender, name) => { + ipcMain.on(IPC_MESSAGE.ADDONS.INSTALLED, (sender, name) => { console.log('handleIpcMessages: INSTALLED ' + name); - _this.extensionManager.build(); - return _this.extensionManager.activate(app, name); + _this.addonManager.build(); + return _this.addonManager.activate(app, name); }); - ipcMain.on(IPC_MESSAGE.EXTENSIONS.UNINSTALLED, (sender, name) => { + ipcMain.on(IPC_MESSAGE.ADDONS.UNINSTALLED, (sender, name) => { console.log('handleIpcMessages: UNINSTALLED ' + name); - return _this.extensionManager.deactivate(app, name); + return _this.addonManager.deactivate(app, name); }); - ipcMain.on(IPC_MESSAGE.EXTENSIONS.ACTIVATE, (sender, name) => { + ipcMain.on(IPC_MESSAGE.ADDONS.ACTIVATE, (sender, name) => { console.log('handleIpcMessages: ACTIVATE ' + name); - return _this.extensionManager.activate(app, name); + return _this.addonManager.activate(app, name); }); - ipcMain.on(IPC_MESSAGE.EXTENSIONS.DEACTIVATE, (sender, name) => { + ipcMain.on(IPC_MESSAGE.ADDONS.DEACTIVATE, (sender, name) => { console.log('handleIpcMessages: DEACTIVATE ' + name); - return _this.extensionManager.deactivate(app, name); + return _this.addonManager.deactivate(app, name); }); } launchInspector(appControl) { -- 2.7.4 From c0ff46b5e4bbbe0d926dc6e4ddacb57729f86d22 Mon Sep 17 00:00:00 2001 From: liwei Date: Thu, 13 Jun 2019 16:43:09 +0800 Subject: [PATCH 09/16] [VD] Support RWI feature 1. When set vconf "db/rwi/inspected_appid" to appid or __AUL_DEBUG__ is 1, RWI feature will be started. (i.e. vconftool set -t string db/rwi/inspected_appid "zLNL5kc4kl.emanual" -f -g 5000 aul_test launch zLNL5kc4kl.emanual __AUL_DEBUG__ 1) 2. Support popup to show port number when appid is set to vconf. Native side link: https://review.tizen.org/gerrit/#/c/platform/framework/web/chromium-efl/+/207831/ Change-Id: Id7d640b1fd690cce9695fe4c552be7fbe7ed5c90 Signed-off-by: liwei --- wrt_app/src/runtime.js | 18 +++++++++++++++--- wrt_app/src/web_application.js | 6 ++++++ 2 files changed, 21 insertions(+), 3 deletions(-) mode change 100755 => 100644 wrt_app/src/runtime.js mode change 100755 => 100644 wrt_app/src/web_application.js diff --git a/wrt_app/src/runtime.js b/wrt_app/src/runtime.js old mode 100755 new mode 100644 index 8fcdcf1..d7daa36 --- a/wrt_app/src/runtime.js +++ b/wrt_app/src/runtime.js @@ -30,6 +30,7 @@ class Runtime { this.extensionManager = null; this.isLaunched = false; this.debug_mode = false; + this.need_inspector = false; var _this = this; app.on('before-quit', function(event) { @@ -143,8 +144,8 @@ class Runtime { // FIX ME : It must be supplemented to set a specific path wrt.setCookiePath(); - // AUL public key - To support debug argument - if (!_this.debug_mode && appControl.getData('__AUL_DEBUG__') == "1") { + // AUL public key/Vconf - To support inspector + if (!_this.debug_mode && _this.checkInspectorCondition(appControl)) { _this.debug_mode = true; _this.launchInspector(appControl); } @@ -189,8 +190,19 @@ class Runtime { return _this.extensionManager.deactivate(app, name); }); } + checkInspectorCondition(appControl) { + var _this = this; + let bundle_debug = (appControl.getData('__AUL_DEBUG__') === "1"); + _this.need_inspector = wrt.needUseInspector(); + return (bundle_debug || _this.need_inspector); + } launchInspector(appControl) { - var data = { "port" : [ wrt.getDebuggingPort().toString() ] }; + var _this = this; + var portnum = wrt.getDebuggingPort(); + var data = { "port" : [ portnum.toString() ] }; + if(_this.need_inspector) { + _this.webApplication.debugport = portnum; + } appControl.reply(data); } } diff --git a/wrt_app/src/web_application.js b/wrt_app/src/web_application.js old mode 100755 new mode 100644 index 3f242e9..2c35351 --- a/wrt_app/src/web_application.js +++ b/wrt_app/src/web_application.js @@ -32,6 +32,7 @@ class WebApplication { this.firstRendered = false; this.backgroundSupport = wrt.getBackgroundSupport(); this.multitaskingSupport = wrt.getMultitaskingSupport(); + this.debugport = 0; if (options.launchMode == 'backgroundAtStartup') { console.log('backgroundAtStartup'); this.preloadState = 'preload'; @@ -228,6 +229,11 @@ class WebApplication { if (self.runningStatus !== 'behind') wrt.notifyAppStatus('preload'); } + if((self.debugport) && (wrt.getPlatformType() === "product_tv")) { + const kDebugPopupScript = "alert('port number :" + self.debugport +"')"; + wrt.executeJS(self.mainWindow.webContents, kDebugPopupScript); + self.debugport = 0; + } }); } suspend() { -- 2.7.4 From d779408cd99ce0f09a98bac963862767a793f40d Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Wed, 19 Jun 2019 17:22:52 +0900 Subject: [PATCH 10/16] Set default backgroundColor 1) Set background color as follows - TV: black - Others : white 2) transparent is not truely working, becuase there is no proper implementation of native side. If needs, NativeWindowEfl class will support this Related patch for this: https://review.tizen.org/gerrit/208174/ Change-Id: Id028bb05d98be8be221784ab20892da8ba71ec88 Signed-off-by: DongHyun Song --- wrt_app/src/web_application.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) mode change 100644 => 100755 wrt_app/src/web_application.js diff --git a/wrt_app/src/web_application.js b/wrt_app/src/web_application.js old mode 100644 new mode 100755 index 69f45a8..b6729c4 --- a/wrt_app/src/web_application.js +++ b/wrt_app/src/web_application.js @@ -45,6 +45,9 @@ class WebApplication { this.suspended = true; this.loadFinished = false; this.runningStatus = 'none'; + this.isTVProfile = (wrt.getPlatformType() === "product_tv"); + this.defaultBackgroundColor = (this.isTVProfile ? '#000' : '#FFF'); + this.defaultTransparent = (this.isTVProfile ? true : false); let self = this; app.on('browser-window-created', function(event, window) { @@ -170,6 +173,8 @@ class WebApplication { getBrowserWindowOption(options) { return { fullscreen: false, + backgroundColor: this.defaultBackgroundColor, + transparent: this.defaultTransparent, show: false, webPreferences: { nodeIntegration: options.isAddonAvailable, @@ -191,7 +196,7 @@ class WebApplication { }); } let self = this; - if (!(wrt.getPlatformType() === "product_tv")) { + if (!self.isTVProfile) { self.showTimer = setTimeout(() => { if (!self.suspended) { console.log('FrameRendered not obtained from engine. To show window, timer fired'); @@ -228,7 +233,7 @@ class WebApplication { if (self.runningStatus !== 'behind') wrt.notifyAppStatus('preload'); } - if((self.debugport) && (wrt.getPlatformType() === "product_tv")) { + if(self.debugport && self.isTVProfile) { const kDebugPopupScript = "alert('port number :" + self.debugport +"')"; wrt.executeJS(self.mainWindow.webContents, kDebugPopupScript); self.debugport = 0; -- 2.7.4 From bd73f9e3d01751fe2debee75d58bf44925095ef0 Mon Sep 17 00:00:00 2001 From: SangYong Park Date: Wed, 26 Jun 2019 19:14:38 +0900 Subject: [PATCH 11/16] Add WRTWindow and WRTWebContents It is customized module of BrowserWindow and WebContents. related to https://review.tizen.org/gerrit/#/c/platform/framework/web/chromium-efl/+/208618/ Change-Id: I336c171e384316373e9cbb404efa7da4fb29e8a2 Signed-off-by: SangYong Park --- wrt_app/browser/wrt_web_contents.js | 34 +++++++++++++++++++++++++ wrt_app/browser/wrt_window.js | 49 +++++++++++++++++++++++++++++++++++++ wrt_app/src/web_application.js | 19 ++++++++------ 3 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 wrt_app/browser/wrt_web_contents.js create mode 100644 wrt_app/browser/wrt_window.js diff --git a/wrt_app/browser/wrt_web_contents.js b/wrt_app/browser/wrt_web_contents.js new file mode 100644 index 0000000..994cca2 --- /dev/null +++ b/wrt_app/browser/wrt_web_contents.js @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const binding = process.binding('wrt_web_contents') +const { WRTWebContents } = binding +const { WebContents: AtomWebContents } = process.atomBinding('web_contents') + +const parent = AtomWebContents.prototype +AtomWebContents.prototype = WRTWebContents.prototype + +Object.setPrototypeOf(WRTWebContents.prototype, parent) + +WRTWebContents.prototype._init = function () { + parent._init.call(this) +} + +module.exports = { + create (options = {}) { + return binding.create(options) + } +} diff --git a/wrt_app/browser/wrt_window.js b/wrt_app/browser/wrt_window.js new file mode 100644 index 0000000..b4eb6c5 --- /dev/null +++ b/wrt_app/browser/wrt_window.js @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const { WRTWindow } = process.binding('wrt_window') +const { BrowserWindow, TopLevelWindow } = require('electron') +const WRTWebContents = require('../browser/wrt_web_contents'); + +Object.setPrototypeOf(WRTWindow.prototype, BrowserWindow.prototype) + +WRTWindow.prototype._init = function () { + BrowserWindow.prototype._init.call(this) + this.setup() + let self = this + this.webContents.on('new-window', (event, url, frameName, disposition, options) => { + event.preventDefault() + let parentOptions = self.browserWindowOptions || {} + parentOptions.webContents = options.webContents || WRTWebContents() + const win = new WRTWindow(parentOptions) + event.newGuest = win + }) +} + +const isWindow = (win) => { + return win && win.constructor.name === 'WRTWindow' +} + +WRTWindow.fromId = (id) => { + const win = TopLevelWindow.fromId(id) + return isWindow(win) ? win : null +} + +WRTWindow.getAllWindows = () => { + return TopLevelWindow.getAllWindows().filter(isWindow) +} + +module.exports = WRTWindow diff --git a/wrt_app/src/web_application.js b/wrt_app/src/web_application.js index 78ef215..ec85403 100755 --- a/wrt_app/src/web_application.js +++ b/wrt_app/src/web_application.js @@ -16,9 +16,11 @@ 'use strict'; -const {BrowserWindow, app, protocol} = require('electron'); +const { app, protocol } = require('electron'); const WAS_EVENT = require('./was_event'); const wrt = require('../browser/wrt'); +const WRTWebContents = require('../browser/wrt_web_contents'); +const WRTWindow = require('../browser/wrt_window'); class WebApplication { constructor(options) { @@ -165,7 +167,7 @@ class WebApplication { } }); } - getBrowserWindowOption(options) { + getWindowOption(options) { return { fullscreen: false, show: false, @@ -173,6 +175,7 @@ class WebApplication { nodeIntegration: options.isAddonAvailable, nodeIntegrationInWorker: false }, + webContents: WRTWebContents.create(), 'web-preferences': { 'direct-write': true, 'subpixel-font-scaling': false, @@ -181,8 +184,8 @@ class WebApplication { }; } createMainWindow(options) { - let winopt = this.getBrowserWindowOption(options); - this.mainWindow = new BrowserWindow(winopt); + let winopt = this.getWindowOption(options); + this.mainWindow = new WRTWindow(winopt); if (options.devMode) { this.mainWindow.webContents.openDevTools({ detached: true @@ -235,7 +238,7 @@ class WebApplication { console.log('App has been terminated; return'); return; } - let windows = BrowserWindow.getAllWindows(); + let windows = WRTWindow.getAllWindows(); if (!this.multitaskingSupport) { // FIXME : terminate app after visibilitychange event handling setTimeout(() => { @@ -254,7 +257,7 @@ class WebApplication { console.log('WebApplication : resume firstRendered is false'); return; } - BrowserWindow.getAllWindows().forEach((window) => { + WRTWindow.getAllWindows().forEach((window) => { if (!this.backgroundSupport) window.setEnabled(true); }); @@ -284,12 +287,12 @@ class WebApplication { console.log('WebApplication : show'); this.preloadState = 'none'; if (!this.mainWindow.isVisible()) { - console.log('show browserWindow'); + console.log('show window'); this.mainWindow.show(); } } closeWindows() { - BrowserWindow.getAllWindows().forEach((window) => { + WRTWindow.getAllWindows().forEach((window) => { if (window != this.mainWindow) window.destroy(); }); -- 2.7.4 From 60e67fd0666d6d539f49583545b5e6e943fab7bd Mon Sep 17 00:00:00 2001 From: "hyunduk.kim" Date: Sun, 30 Jun 2019 22:18:21 -0700 Subject: [PATCH 12/16] Initial code to handle lifecycles and events in addons This provides the invocation of predefined methods for lifecycles and events - prelanuch : invoking prelaunch() in an addon when app-control is emitted - suspend : invoking suspend() in an addon when suspend is emitted - resume : invoking resume() in an addon when resume is emitted - quit : invoking quit() in an addon when before-quit is emitted - arrowup : invoking arrowup() in an addon when arrowup is pressed - arrowdown : invoking arrowdown() in an addon when arrowdown is pressed It's only an initial code and focused on the logic to call each method. Change-Id: I04c5976dd88fabb2ccdfcf96e0d444ed296acbe4 Signed-off-by: hyunduk.kim --- wrt_app/src/addon_manager.js | 49 ++++++++++++++++++++++++ wrt_app/src/runtime.js | 50 ++++++++++++++++++++++++- wrt_app/src/web_application.js | 85 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 180 insertions(+), 4 deletions(-) diff --git a/wrt_app/src/addon_manager.js b/wrt_app/src/addon_manager.js index 7c7c449..d3efeca 100644 --- a/wrt_app/src/addon_manager.js +++ b/wrt_app/src/addon_manager.js @@ -33,6 +33,12 @@ class AddonManager { this.addons_list_ = null; this.addons_ = null; this.addons_API_ = null; + this.prelaunch_path = null; + this.resume_path = null; + this.suspend_path = null; + this.quit_path = null; + this.arrowup_path = null; + this.arrowdown_path = null; } printAPIs() { @@ -164,6 +170,44 @@ class AddonManager { return true; } + registerLifecycles(lifecycles, path) { + if (!lifecycles) { + console.log('lifecycle is not declared'); + return; + } + if (lifecycles.prelaunch) { + this.prelaunch_path = path; + console.log('prelaunch operation path :' + this.prelaunch_path); + } + if (lifecycles.resume) { + this.resume_path = path; + console.log('resume override path :' + this.resume_path); + } + if (lifecycles.suspend) { + this.suspend_path = path; + console.log('suspend override path :' + this.suspend_path); + } + if (lifecycles.quit) { + this.quit_path = path; + console.log('quit operation path :' + this.quit_path); + } + } + + registerEvents(events, path) { + if (!events) { + console.log('event is not declared'); + return; + } + if (events.arrowup) { + this.arrowup_path = path; + console.log('arrowup operation path :' + this.arrowup_path); + } + if (events.arrowdown) { + this.arrowdown_path = path; + console.log('arrowdown operation path :' + this.arrowdown_path); + } + } + build() { // 0. load addons_list_ from JSON DB this.loadJsonDB(); @@ -223,6 +267,11 @@ class AddonManager { addons[type][manifest_obj.name] = addon.path; } } + + let addon_path = path.join(addon.path, manifest_obj.name) + '.js'; + this.registerLifecycles(manifest_obj.lifecycle, addon_path); + this.registerEvents(manifest_obj.event, addon_path); + console.log('addons[' + type + '][' + manifest_obj.name + '] = ' + addons[type][manifest_obj.name] + ' registered'); } catch (e) { console.error('AddonManager.build error - ' + e); diff --git a/wrt_app/src/runtime.js b/wrt_app/src/runtime.js index 02af0d8..36e0eb1 100644 --- a/wrt_app/src/runtime.js +++ b/wrt_app/src/runtime.js @@ -31,10 +31,23 @@ class Runtime { this.isLaunched = false; this.debug_mode = false; this.need_inspector = false; + this.webContents = null; + this.allowQuit = false; var _this = this; app.on('before-quit', function(event) { console.log('before-quit'); + if (!wrt.isElectronApp()) { + if (_this.addonManager.quit_path && !_this.allowQuit) { + event.preventDefault(); + let timeout = _this.webApplication.quit(_this.addonManager.quit_path); + _this.allowQuit = true; + if (timeout >= 0) + setTimeout(function() { + app.quit(); + }, timeout, null); + } + } }); app.on('will-quit', function(event) { console.log('will-quit'); @@ -68,6 +81,15 @@ class Runtime { app.on('will-finish-launching', function(event) { console.log('will-finish-launching'); }); + app.on('web-contents-created', function(event, webContents) { + console.log('web-contents-created'); + _this.webContents = webContents; + _this.webContents.on('before-input-event', function(event, input) { + if (_this.isLaunched && _this.webApplication) { + _this.handleKeyEvents(input.key); + } + }); + }); app.once('ready', function(event) { console.log('ready'); _this.addonManager = new AddonManager(); @@ -103,6 +125,7 @@ class Runtime { options.launchMode = appControl.getData('http://samsung.com/appcontrol/data/launch_mode'); _this.webApplication = new WebApplication(options); _this.webApplication.mainWindow.loadURL(src); + _this.webApplication.prelaunch(_this.addonManager.prelaunch_path, src); } else { console.log('Handling app-control event'); if (_this.webApplication.preloadState == 'readyToShow') { @@ -150,11 +173,11 @@ class Runtime { }); wrt.on('suspend', function() { console.log('suspend'); - _this.webApplication.suspend(); + _this.webApplication.suspend(_this.addonManager.suspend_path); }); wrt.on('resume', function() { console.log('resume'); - _this.webApplication.resume(); + _this.webApplication.resume(_this.addonManager.resume_path); }); wrt.on('terminate', function() { console.log('terminate'); @@ -199,5 +222,28 @@ class Runtime { } appControl.reply(data); } + handleKeyEvents(key) { + let path = null; + let _this = this; + + console.log(key + ' is pressed'); + switch(key) { + case "ArrowUp": + case "Up": + path = _this.addonManager.arrowup_path; + break; + case "ArrowDown": + case "Down": + path = _this.addonManager.arrowdown_path; + break; + default: + console.log('No handler for the key ' + key); + break; + } + console.log('Path for ' + key + ' : ' + path); + if (path) { + _this.webApplication.keyEvent(key, path); + } + } } module.exports = Runtime; diff --git a/wrt_app/src/web_application.js b/wrt_app/src/web_application.js index 77e9f63..0688643 100755 --- a/wrt_app/src/web_application.js +++ b/wrt_app/src/web_application.js @@ -243,8 +243,18 @@ class WebApplication { } }); } - suspend() { + suspend(path) { console.log('WebApplication : suspend'); + if (path != null) { + let addon = require(path); + console.log('addon for suspend is ' + path); + if (addon.suspend) { + console.log('addon for suspend is found'); + addon.suspend(this.mainWindow.id, path); + } else { + console.log('addon for suspend is NOT found'); + } + } this.suspended = true; if (this.isTerminating) { console.log('App has been terminated; return'); @@ -262,11 +272,21 @@ class WebApplication { } this.windowList[this.windowList.length - 1].hide(); } - resume() { + resume(path) { console.log('WebApplication : resume'); this.suspended = false; if (!this.firstRendered) { console.log('WebApplication : resume firstRendered is false'); + if (path != null) { + let addon = require(path); + console.log('addon for resume is ' + path); + if (addon.resume) { + console.log('addon for resume is found'); + addon.resume(this.mainWindow.id, path); + } else { + console.log('addon for resume is NOT found'); + } + } return; } WRTWindow.getAllWindows().forEach((window) => { @@ -278,6 +298,21 @@ class WebApplication { terminate() { this.isTerminating = true; } + quit(path) { + console.log('WebApplication : quit'); + let timeout = -1; + if (path != null) { + let addon = require(path); + console.log('addon for quit is ' + path); + if (addon.quit) { + console.log('addon for quit is found'); + timeout = addon.quit(this.mainWindow.id, path); + } else { + console.log('addon for quit is NOT found'); + } + } + return timeout; + } sendAppControlEvent() { const kAppControlEventScript = '(function(){' + @@ -309,5 +344,51 @@ class WebApplication { window.destroy(); }); } + keyEvent(key, path) { + console.log('WebApplication : keyEvent'); + if (!path) { + console.log('no path for event hook exists'); + return; + } + let addon = require(path); + console.log('event is hooked for ' + path); + switch(key) { + case "ArrowUp": + case "Up": + if (addon.arrowup) { + console.log('arrowup is found'); + addon.arrowup(this.mainWindow.id); + } else { + console.log('arrowup is NOT found'); + } + break; + case "ArrowDown": + case "Down": + if (addon.arrowdown) { + console.log('arrowdown is found'); + addon.arrowdown(this.mainWindow.id); + } else { + console.log('arrowdown is NOT found'); + } + break; + default: + console.log('No handler for ' + key); + break; + } + } + prelaunch(path, origURL) { + console.log('WebApplication : prelaunch'); + if (path != null) { + let addon = require(path); + console.log('addon for additional runtime is ' + path); + console.log('prelaunch : org URL : ' + origURL); + if (addon.prelaunch) { + console.log('prelaunch is found'); + addon.prelaunch(this.mainWindow.id, origURL); + } else { + console.log('prelaunch is NOT found'); + } + } + } } module.exports = WebApplication; -- 2.7.4 From 1b42b763369d1c303dd678da777852da0866d65b Mon Sep 17 00:00:00 2001 From: liwei Date: Thu, 4 Jul 2019 09:08:57 +0800 Subject: [PATCH 13/16] [VD] Flush Local Storage and Cookie when app exit 1. In current logic, data will be set to SQLite database every 30s, if app exit immediately after it's launched, the data will not be set to SQLite database, so we should flush SQLite database commit all pending operations before app terminate, it's same with local storage database. Bcz app can be killed by LMF, so suspend is proper timing. For eg. AIO(3201606009648)'s account is stored in Cookie, if app is exited immedatley, the account will not stored to Cookie, then when AIO launch again, account can not be signed atuomatically. 2. In WRTJS, EWebView class will not be used anymore, so this logic should be moved to WRTJS side. Refrence Patch: https://review.tizen.org/gerrit/#/c/platform/framework/web/chromium-efl/+/203302/ Native Patch: https://review.tizen.org/gerrit/#/c/platform/framework/web/chromium-efl/+/208872/ Change-Id: I63a21ef88d59876b2e43348f0e004ce3c8011c81 Signed-off-by: liwei --- wrt_app/src/web_application.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wrt_app/src/web_application.js b/wrt_app/src/web_application.js index 77e9f63..90aaaf6 100755 --- a/wrt_app/src/web_application.js +++ b/wrt_app/src/web_application.js @@ -251,6 +251,10 @@ class WebApplication { return; } let windows = WRTWindow.getAllWindows(); + if (this.isTVProfile) { + wrt.flushCookie(); + this.windowList.forEach((window) => window.webContents.session.flushStorageData()); + } if (!this.multitaskingSupport) { // FIXME : terminate app after visibilitychange event handling setTimeout(() => { -- 2.7.4 From b320d98de8e67b9fe1929df739c24fbea473d145 Mon Sep 17 00:00:00 2001 From: "ws29.jung" Date: Fri, 5 Jul 2019 17:38:39 +0900 Subject: [PATCH 14/16] Check WRTWindow.setup to launch App Currently same wrtjs is used in m63 and m69 Chromium-efl but supported methods from each library are different. The WRTWindow.setup() method is only provided by m69 and to launch Webapp on latest m63 Chromium-efl, the method need to be checked whether it is accessible. Change-Id: I44800e3f7209b86954cf3f65c118458173e34750 Signed-off-by: ws29.jung --- wrt_app/browser/wrt_window.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wrt_app/browser/wrt_window.js b/wrt_app/browser/wrt_window.js index b4eb6c5..d2cd792 100644 --- a/wrt_app/browser/wrt_window.js +++ b/wrt_app/browser/wrt_window.js @@ -22,7 +22,8 @@ Object.setPrototypeOf(WRTWindow.prototype, BrowserWindow.prototype) WRTWindow.prototype._init = function () { BrowserWindow.prototype._init.call(this) - this.setup() + if (typeof this.setup === 'function') + this.setup() let self = this this.webContents.on('new-window', (event, url, frameName, disposition, options) => { event.preventDefault() -- 2.7.4 From f638eb86e7d404cab9d3dd3f2f130e2cf15d9e98 Mon Sep 17 00:00:00 2001 From: SangYong Park Date: Wed, 3 Jul 2019 18:32:50 +0900 Subject: [PATCH 15/16] Remove unnecessary event handling during termination Add code for preventing unnecessary event handling. and remove unusing code. Change-Id: I48ea7e9f6b36fe0eb0c19fb49a4ec4a10363e795 Signed-off-by: SangYong Park --- wrt_app/src/runtime.js | 13 ++++--------- wrt_app/src/web_application.js | 25 ++++++++++--------------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/wrt_app/src/runtime.js b/wrt_app/src/runtime.js index 36e0eb1..ac408d2 100644 --- a/wrt_app/src/runtime.js +++ b/wrt_app/src/runtime.js @@ -48,11 +48,12 @@ class Runtime { }, timeout, null); } } + _this.webApplication.finalize(); + _this.webApplication = null; }); app.on('will-quit', function(event) { console.log('will-quit'); _this.addonManager.deactivateAll(app); - _this.killAllProcesses(); }); app.on('quit', function(event) { console.log('quit'); @@ -173,20 +174,14 @@ class Runtime { }); wrt.on('suspend', function() { console.log('suspend'); - _this.webApplication.suspend(_this.addonManager.suspend_path); + if (_this.webApplication) + _this.webApplication.suspend(_this.addonManager.suspend_path); }); wrt.on('resume', function() { console.log('resume'); _this.webApplication.resume(_this.addonManager.resume_path); }); - wrt.on('terminate', function() { - console.log('terminate'); - _this.webApplication.terminate(); - }); } - onLanguageChanged() {} - onLowMemory() {} - killAllProcesses() {} handleIpcMessages() { var _this = this; ipcMain.on(IPC_MESSAGE.ADDONS.INSTALLED, (sender, name) => { diff --git a/wrt_app/src/web_application.js b/wrt_app/src/web_application.js index 3b0f964..65aa1da 100755 --- a/wrt_app/src/web_application.js +++ b/wrt_app/src/web_application.js @@ -43,7 +43,6 @@ class WebApplication { } this.accessiblePath = wrt.getAccessiblePath(); this.isAlwaysReload = wrt.isAlwaysReload(); - this.isTerminating = false; this.suspended = true; this.loadFinished = false; this.runningStatus = 'none'; @@ -62,7 +61,7 @@ class WebApplication { console.log(`window closed : #${self.windowList.length}`); let index = self.windowList.indexOf(window); self.windowList.splice(index, 1); - if (!self.isTerminating && index === self.windowList.length && self.windowList.length > 0) + if (index === self.windowList.length && self.windowList.length > 0) self.windowList[self.windowList.length - 1].show(); }); }); @@ -256,11 +255,6 @@ class WebApplication { } } this.suspended = true; - if (this.isTerminating) { - console.log('App has been terminated; return'); - return; - } - let windows = WRTWindow.getAllWindows(); if (this.isTVProfile) { wrt.flushCookie(); this.windowList.forEach((window) => window.webContents.session.flushStorageData()); @@ -272,7 +266,7 @@ class WebApplication { app.quit(); }, 1000); } else if (!this.backgroundSupport) { - windows.forEach((window) => window.setEnabled(false)); + this.windowList.forEach((window) => window.setEnabled(false)); } this.windowList[this.windowList.length - 1].hide(); } @@ -293,14 +287,15 @@ class WebApplication { } return; } - WRTWindow.getAllWindows().forEach((window) => { - if (!this.backgroundSupport) - window.setEnabled(true); - }); + if (!this.backgroundSupport) { + this.windowList.forEach((window) => window.setEnabled(true)); + } this.windowList[this.windowList.length - 1].show(); } - terminate() { - this.isTerminating = true; + finalize() { + this.windowList.forEach((window) => { + window.removeAllListeners(); + }); } quit(path) { console.log('WebApplication : quit'); @@ -343,7 +338,7 @@ class WebApplication { } } closeWindows() { - WRTWindow.getAllWindows().forEach((window) => { + this.windowList.forEach((window) => { if (window != this.mainWindow) window.destroy(); }); -- 2.7.4 From f61728e88626b9e85cb651732ac543f076f8ebfc Mon Sep 17 00:00:00 2001 From: "ws29.jung" Date: Thu, 11 Jul 2019 17:57:46 +0900 Subject: [PATCH 16/16] Fix error when suspend/resume on m63 fromId and getAllWindows Methods which are in WRTWindow class were executing binded function from TopLevelWindow class. However, TopLevelWindow class does not exist in m63. Instead of TopLevelWindow, BrowserWindow class in m63 has same functions and in m69, it is a child class of TopLevelWindow. Methods from TopLevelWindow is now subsituted to methods from BrowserWindow. Change-Id: I88607d1ded40d2daae9d74ea6e45f65272cf609d Signed-off-by: ws29.jung --- wrt_app/browser/wrt_window.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrt_app/browser/wrt_window.js b/wrt_app/browser/wrt_window.js index d2cd792..e3a5977 100644 --- a/wrt_app/browser/wrt_window.js +++ b/wrt_app/browser/wrt_window.js @@ -39,12 +39,12 @@ const isWindow = (win) => { } WRTWindow.fromId = (id) => { - const win = TopLevelWindow.fromId(id) + const win = BrowserWindow.fromId(id) return isWindow(win) ? win : null } WRTWindow.getAllWindows = () => { - return TopLevelWindow.getAllWindows().filter(isWindow) + return BrowserWindow.getAllWindows().filter(isWindow) } module.exports = WRTWindow -- 2.7.4