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