3717d434eee5a9d76d9c48e2e2558a45eec8ad13
[platform/framework/web/wrtjs.git] / wrt_app / src / runtime.ts
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 import { wrt } from '../browser/wrt';  // Load first for log
20 import { addonManager } from './addon_manager';
21 import { app } from 'electron';
22 import { WebApplication } from './web_application';
23
24 class Runtime {
25   webApplication?: WebApplication = undefined;
26   isLaunched = false;
27   inspectorEnabledByVconf = false;
28
29   constructor() {
30     app.on('before-quit', (event) => {
31       console.log('before-quit');
32       this.webApplication?.quit();
33     });
34     app.on('will-quit', (event) => {
35       console.log('will-quit');
36       addonManager.deactivateAll();
37     });
38     app.on('quit', (event) => {
39       console.log('quit');
40       if (this.webApplication) {
41         this.webApplication.finalize();
42         this.webApplication = undefined;
43       }
44     });
45     app.on('browser-window-created', () => {
46       console.log('browser-window-created');
47       if (!this.isLaunched) {
48         addonManager.activateAll();
49         this.isLaunched = true;
50       }
51     });
52     app.on('window-all-closed', () => {
53       console.log('window-all-closed');
54       app.quit();
55     });
56     app.on('web-contents-created', (event, webContents) => {
57       console.log('web-contents-created');
58       webContents.on('before-input-event', (event, input) => {
59         if (this.isLaunched && this.webApplication)
60           this.handleKeyEvents(input.key);
61       });
62     });
63     app.once('ready', (event) => {
64       console.log('ready');
65       let addonAvailable = addonManager.build();
66       console.log("addonBuild : " + addonAvailable);
67       if (addonAvailable) {
68         const XWalkExtension = require('../common/wrt_xwalk_extension');
69         XWalkExtension.initialize();
70         XWalkExtension.preventCleanup();
71       }
72       wrt.tv?.importCertificate('');
73     });
74     wrt.on('app-control', (event, appControl) => {
75       console.log('app-control');
76       let loadInfo = appControl.getLoadInfo();
77       let src = loadInfo.getSrc();
78
79       if (wrt.isElectronApp()) {
80         console.log('Electron App launch');
81         const Module = require('module');
82         Module.globalPaths.push(wrt.getAppPath());
83         let filePath = src[7] === '/' ? src.substr(8) : src.substr(7); // strip "file://"
84         let pkgJson = require(filePath);
85         let pos = filePath.lastIndexOf('/');
86
87         let mainJsPath = (pos !== -1 ? filePath.substr(0, pos + 1) : '') +
88                             (pkgJson.main || 'index.js');
89         console.log('loading path:', mainJsPath);
90         Module._load(mainJsPath, Module, true);
91         app.emit('ready');
92       } else {
93         console.log('Tizen Web App launch');
94         let launchMode = appControl.getData('http://samsung.com/appcontrol/data/launch_mode');
95         if (!this.webApplication) {
96           console.log('Creating WebApplication');
97           let options: RuntimeOption = {
98             isAddonAvailable: addonManager.isAddonAvailable(),
99             launchMode: launchMode
100           }
101           this.webApplication = new WebApplication(options);
102           if (wrt.tv) {
103             this.inspectorEnabledByVconf = wrt.tv.needUseInspector();
104             if (this.inspectorEnabledByVconf && launchMode != 'backgroundExecution') {
105               this.webApplication.inspectorSrc = src;
106               src = "about:blank";
107             }
108             let useDiskCache = appControl.getData('USE_DISKCACHE');
109             let halfWindowOption = appControl.getData('http://samsung.com/appcontrol/data/half_window_support');
110             wrt.tv.setDiskCache(useDiskCache);
111             wrt.tv.handleAppControlData(launchMode, halfWindowOption);
112           }
113           this.webApplication.mainWindow.loadURL(src);
114           this.webApplication.prelaunch(src);
115           if (wrt.da) {
116             this.webApplication.mainWindow.emit('ready-to-show');
117           }
118         } else {
119           console.log('Handling app-control event');
120           if (this.webApplication.preloadStatus == 'readyToShow') {
121             this.webApplication.show();
122           } else {
123             if (launchMode != 'backgroundAtStartup')
124               this.webApplication.preloadStatus = 'none';
125           }
126
127           let skipReload = appControl.getData('SkipReload');
128           if (skipReload == 'Yes') {
129             console.log('skipping reload');
130             // TODO : Need to care this situation and decide to pass the addon event emitter to resume()
131             this.webApplication.resume();
132             return;
133           }
134
135           let reload = loadInfo.getReload() || this.webApplication.isAlwaysReload;
136           if (!reload) {
137             let originalUrl = this.webApplication.mainWindow.webContents.getURL();
138             if (wrt.tv) {
139               console.log(`appcontrol src = ${src}, original url = ${originalUrl}`);
140               if (src && originalUrl) {
141                 let appcontrolUrl = (new URL(src)).href;
142                 let oldUrl = (new URL(originalUrl)).href;
143                 console.log(`appcontrolUrl = ${appcontrolUrl}, oldUrl = ${oldUrl}`);
144                 // FIXME(dh81.song)
145                 // Below case it must be distinguishable for known cases
146                 //   from 'file:///index.htmlx' to 'file:///index.html'
147                 if (appcontrolUrl !== oldUrl.substr(0, appcontrolUrl.length))
148                   reload = true;
149               } else {
150                 reload = true;
151               }
152             } else if (src !== originalUrl) {
153               reload = true;
154             }
155           }
156           // handle http://tizen.org/appcontrol/operation/main operation specially.
157           // only menu-screen app can send launch request with main operation.
158           // in this case, web app should have to resume web app not reset.
159           if (reload && appControl.getOperation() == 'http://tizen.org/appcontrol/operation/main')
160             reload = false;
161           if (reload)
162             this.webApplication.handleAppControlReload(src);
163           else
164             this.webApplication.sendAppControlEvent();
165         }
166       }
167       this.launchInspector(appControl);
168     });
169     wrt.on('suspend', () => {
170       console.log('suspend');
171       this.webApplication?.suspend();
172     });
173     wrt.on('resume', () => {
174       console.log('resume');
175       this.webApplication?.resume();
176     });
177     wrt.on('low-memory', () => {
178       console.log('low-memory');
179       this.webApplication?.lowMemory();
180     });
181     wrt.on('message', (event, type, params) => {
182       console.log('message type(' + type + ') params : ' + params);
183       const app_id = params[0];
184       if (type === 'startService') {
185         require('../common/service_manager').startService(app_id, params[1]);
186         event.preventDefault();
187       } else if (type === 'stopService') {
188         require('../common/service_manager').stopService(app_id);
189         event.preventDefault();
190       }
191     });
192     wrt.on('ambient-tick', () => {
193       this.webApplication?.ambientTick();
194     });
195     wrt.on('ambient-changed', (event, ambient_mode) => {
196       console.log('ambient-changed , ambient_mode:' + ambient_mode);
197       this.webApplication?.ambientChanged(ambient_mode);
198     });
199     wrt.on('addon-installed', (event, path) => {
200       console.log('addon-installed at ' + path);
201       addonManager.checkAddon(path);
202     });
203     wrt.on('addon-uninstalled', (event, id) => {
204       console.log('addon-unistalled named ' + id);
205     });
206     wrt.on('wgt-checking-done', (event) => {
207       console.log('wgt-checking-done');
208       addonManager.updateDB();
209     });
210
211     /* FIXME: will uncheck after chromium-efl released */
212     if (wrt.getPlatformType() !== "product_tv")
213       wrt.getInstalledPkg();
214   }
215
216   private launchInspector(appControl: NativeWRTjs.AppControl) {
217     this.launchInspector = (param) => {}; // call once
218     console.log('launchInspector');
219
220     // AUL public key/Vconf - To support inspector
221     if (this.checkInspectorCondition(appControl)) {
222       let debugPort = wrt.startInspectorServer();
223       let data = { "port" :  [ debugPort.toString() ] };
224       if (this.webApplication)
225         this.webApplication.debugPort = debugPort;
226       appControl.reply(data);
227     }
228   }
229
230   private checkInspectorCondition(appControl: NativeWRTjs.AppControl) {
231     let bundleDebug = (appControl.getData('__AUL_DEBUG__') === "1");
232     return (bundleDebug || this.inspectorEnabledByVconf);
233   }
234
235   private handleKeyEvents(key: string) {
236     let valid = false;
237     console.log(key + ' is pressed');
238     switch(key) {
239       case "ArrowUp":
240       case "Up":
241       case "ArrowDown":
242       case "Down":
243         valid = true;
244         break;
245       default:
246         console.log('No handler for the key ' + key);
247         break;
248     }
249     if (valid)
250       this.webApplication?.keyEvent(key);
251   }
252 }
253
254 new Runtime();