bc07eb9e801e1eb200416068e931cb162a516a66
[platform/framework/web/wrtjs.git] / wrt_app / src / runtime.js
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 'use strict';
18
19 const wrt = require('../browser/wrt');  // Load first for log
20 const AddonManager = require('./addon_manager');
21 const {app, ipcMain} = require('electron');
22 const IPC_MESSAGE = require('./ipc_message');
23 const WAS_EVENT = require('./was_event');
24 const WebApplication = require('./web_application');
25
26 class Runtime {
27     constructor(options) {
28         this.webApplication = null;
29         this.handleIpcMessages();
30         this.addonManager = null;
31         this.isLaunched = false;
32         this.inspectorEnabledByVconf = false;
33         this.webContents = null;
34
35         var _this = this;
36         app.on('before-quit', function(event) {
37             console.log('before-quit');
38             if (!wrt.isElectronApp()) {
39                 _this.webApplication.quit(_this.addonManager.evt_emitter_);
40                 _this.webApplication.finalize();
41                 _this.webApplication = null;
42             }
43         });
44         app.on('will-quit', function(event) {
45             console.log('will-quit');
46             _this.addonManager.deactivateAll(app);
47         });
48         app.on('quit', function(event) {
49             console.log('quit');
50             wrt.exit();
51         });
52         app.on('browser-window-blur', function() {
53             console.log('browser-window-blur');
54         });
55         app.on('browser-window-focus', function() {
56             console.log('browser-window-focus');
57         });
58         app.on('browser-window-created', function() {
59             console.log('browser-window-created');
60             if (!_this.isLaunched) {
61                 _this.addonManager.activateAll(app);
62                 _this.isLaunched = true;
63             }
64         });
65         app.on('gpu-process-crashed', function() {
66             console.error('gpu-process-crashed');
67         });
68         app.on('window-all-closed', function(event) {
69             console.log('window-all-closed');
70             app.quit();
71         });
72         app.on('will-finish-launching', function(event) {
73             console.log('will-finish-launching');
74         });
75         app.on('web-contents-created', function(event, webContents) {
76             console.log('web-contents-created');
77             _this.webContents = webContents;
78             _this.webContents.on('before-input-event', function(event, input) {
79                 if (_this.isLaunched && _this.webApplication) {
80                     _this.handleKeyEvents(input.key);
81                 }
82             });
83         });
84         app.once('ready', function(event) {
85             console.log('ready');
86             _this.addonManager = new AddonManager();
87             if (!options.noAddons) {
88                 _this.addonManager.build();
89             }
90             wrt.importCertificate('');
91         });
92         wrt.on('app-control', function(event, appControl) {
93             console.log('app-control');
94             let loadInfo = appControl.getLoadInfo();
95             let src = loadInfo.getSrc();
96
97             if (wrt.isElectronApp()) {
98                 console.log('Electron App launch');
99                 const Module = require('module');
100                 Module.globalPaths.push(wrt.getAppPath());
101                 let filePath = src[7] === '/' ? src.substr(8) : src.substr(7); // strip "file://"
102                 let pkgJson = require(filePath);
103                 let pos = filePath.lastIndexOf('/');
104
105                 let mainJsPath = (pos !== -1 ? filePath.substr(0, pos + 1) : '') +
106                                  (pkgJson.main || 'index.js');
107                 console.log('loading path:', mainJsPath);
108                 Module._load(mainJsPath, Module, true);
109                 app.emit('ready');
110             } else {
111                 console.log('Tizen Web App launch');
112                 let launchMode = appControl.getData('http://samsung.com/appcontrol/data/launch_mode');
113                 if (!_this.webApplication) {
114                     console.log('Creating WebApplication');
115                     options.isAddonAvailable = !options.noAddons &&
116                             _this.addonManager.isAddonAvailable();
117                     options.launchMode = launchMode;
118                     _this.webApplication = new WebApplication(options);
119                     _this.inspectorEnabledByVconf = wrt.needUseInspector();
120                     if (_this.inspectorEnabledByVconf && launchMode != 'backgroundExecution') {
121                         _this.webApplication.inspectorSrc = src;
122                         src = "about:blank";
123                     }
124                     _this.webApplication.mainWindow.loadURL(src);
125                     _this.webApplication.prelaunch(_this.addonManager.evt_emitter_, src);
126                 } else {
127                     console.log('Handling app-control event');
128                     if (_this.webApplication.preloadStatus == 'readyToShow') {
129                         _this.webApplication.show();
130                     } else {
131                         if (launchMode != 'backgroundAtStartup') {
132                             _this.webApplication.preloadStatus = 'none';
133                         }
134                     }
135
136                     let skipReload = appControl.getData('SkipReload');
137                     if (skipReload == 'Yes') {
138                         console.log('skipping reload');
139                         // TODO : Need to care this situation and decide to pass the addon event emitter to resume()
140                         _this.webApplication.resume();
141                         return;
142                     }
143
144                     let reload = loadInfo.getReload() || _this.webApplication.isAlwaysReload;
145                     if (!reload) {
146                         if (src != _this.webApplication.mainWindow.getURL())
147                             reload = true;
148                     }
149                     // handle http://tizen.org/appcontrol/operation/main operation specially.
150                     // only menu-screen app can send launch request with main operation.
151                     // in this case, web app should have to resume web app not reset.
152                     if (reload && appControl.getOperation() == 'http://tizen.org/appcontrol/operation/main')
153                         reload = false;
154                     if (reload) {
155                         _this.webApplication.closeWindows();
156                         _this.webApplication.mainWindow.loadURL(src);
157                     } else {
158                         _this.webApplication.sendAppControlEvent();
159                     }
160                 }
161             }
162             _this.configureRuntime(appControl);
163         });
164         wrt.on('suspend', function() {
165             console.log('suspend');
166             if (_this.webApplication)
167                 _this.webApplication.suspend(_this.addonManager.evt_emitter_);
168         });
169         wrt.on('resume', function() {
170             console.log('resume');
171             if (_this.webApplication)
172                 _this.webApplication.resume(_this.addonManager.evt_emitter_);
173         });
174         wrt.on('low-memory', function() {
175             console.log('low-memory');
176             if (_this.webApplication)
177                 _this.webApplication.lowMemory();
178         });
179         wrt.on('wgt-installed', function(event, path) {
180             console.log('wgt-installed at ' + path);
181             if (AddonManager.isAddon(path)) {
182                 console.log('Addon is updated on DB');
183             }
184         });
185         wrt.on('addon-uninstalled', function(event, id) {
186             console.log('addon-unistalled named ' + id);
187         });
188         /* FIXME: will uncheck after chromium-efl released */
189         if (wrt.getPlatformType() !== "product_tv") {
190             wrt.getInstalledPkg();
191         }
192     }
193     handleIpcMessages() {
194         var _this = this;
195         ipcMain.on(IPC_MESSAGE.ADDONS.INSTALLED, (sender, name) => {
196             console.log('handleIpcMessages: INSTALLED ' + name);
197             _this.addonManager.build();
198             return _this.addonManager.activate(app, name);
199         });
200         ipcMain.on(IPC_MESSAGE.ADDONS.UNINSTALLED, (sender, name, pkg) => {
201             console.log('handleIpcMessages: UNINSTALLED ' + name);
202             _this.addonManager.deactivate(app, name);
203             /* FIXME: will uncheck after chromium-efl released */
204             if (wrt.getPlatformType() !== "product_tv") {
205                wrt.reqUninstallPkg(pkg);
206             }
207             return true;
208         });
209         ipcMain.on(IPC_MESSAGE.ADDONS.ACTIVATE, (sender, name) => {
210             console.log('handleIpcMessages: ACTIVATE ' + name);
211             return _this.addonManager.activate(app, name);
212         });
213         ipcMain.on(IPC_MESSAGE.ADDONS.DEACTIVATE, (sender, name) => {
214             console.log('handleIpcMessages: DEACTIVATE ' + name);
215             return _this.addonManager.deactivate(app, name);
216         });
217     }
218     checkInspectorCondition(appControl) {
219         let bundleDebug = (appControl.getData('__AUL_DEBUG__') === "1");
220         return (bundleDebug || this.inspectorEnabledByVconf);
221     }
222     launchInspector(appControl) {
223         var portnum = wrt.getDebuggingPort();
224         var data    = { "port" :  [ portnum.toString() ] };
225         if (this.webApplication)
226             this.webApplication.debugPort = portnum;
227         appControl.reply(data);
228     }
229     configureRuntime(appControl) {
230         this.configureRuntime = (param) => {}; // call once
231
232         // FIX ME : It must be supplemented to set a specific path
233         wrt.setCookiePath();
234
235         // AUL public key/Vconf - To support inspector
236         if (this.checkInspectorCondition(appControl)) {
237             this.launchInspector(appControl);
238         }
239     }
240     handleKeyEvents(key) {
241         let valid = false;
242         let _this = this;
243
244         console.log(key + ' is pressed');
245         switch(key) {
246             case "ArrowUp":
247             case "Up":
248             case "ArrowDown":
249             case "Down":
250                 valid = true;
251                 break;
252             default:
253                 console.log('No handler for the key ' + key);
254                 break;
255         }
256
257         if (valid) {
258             _this.webApplication.keyEvent(_this.addonManager.evt_emitter_, key);
259         }
260     }
261 }
262 module.exports = Runtime;