2 * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 import { wrt } from '../../browser/wrt';
20 import { WebApplication } from '../web_application';
21 import { WebApplicationDelegate } from '../../common/web_application_delegate';
23 export class WebApplicationDelegateTV extends WebApplicationDelegate {
24 backgroundExecutionLaunchMode: boolean = false;
25 backgroundExecutionMetaData: string = 'false';
26 inspectorSrc: string = '';
27 isAlwaysReload: boolean = false;
28 preloadStatus: string = 'none';
29 runningStatus: string = 'none';
30 launchMode: string = 'none';
31 needDispatchTizenVisibilityChange: boolean = false;
32 tv: any = (wrt.tv as NativeWRTjs.TVExtension);
34 constructor(webApplication: WebApplication) {
35 super(webApplication);
38 initialize(options: RuntimeOption) {
39 this.launchMode = options.launchMode;
40 if (options.launchMode == 'backgroundAtStartup') {
41 console.log('backgroundAtStartup');
42 this.preloadStatus = 'preload';
44 this.preloadStatus = 'none';
46 if (options.launchMode == 'backgroundExecution') {
47 console.log('launch mode is backgroundExecution');
48 this.backgroundExecutionLaunchMode = true;
50 this.backgroundExecutionLaunchMode = false;
52 this.isAlwaysReload = this.tv.isAlwaysReload();
53 this.webApplication.multitaskingSupport = this.tv.getMultitaskingSupport();
54 this.webApplication.defaultBackgroundColor = '#0000';
55 this.webApplication.defaultTransparent = true;
56 this.backgroundExecutionMetaData = this.tv.getMetadata('http://samsung.com/tv/metadata/background.execution.support');
58 this.initEventListener();
62 wrt.on('app-status-changed', (event: any, status: string) => {
63 console.log(`runningStatus: ${status}, ${this.webApplication.loadFinished}`);
64 this.runningStatus = status;
65 if (this.runningStatus === 'DialogClose' && this.inspectorSrc) {
66 console.log(`runningStatus is DialogClose, src is ${this.inspectorSrc}`);
67 this.webApplication.mainWindow.loadURL(this.inspectorSrc);
68 this.inspectorSrc = '';
69 this.needDispatchTizenVisibilityChange = true;
70 } else if (this.runningStatus == 'behind' && this.webApplication.loadFinished) {
71 // TODO : Need to care this situation and decide to pass the addon event emitter to suspend()
72 this.webApplication.suspend();
78 if (this.inspectorSrc) {
79 this.showInspectorGuide();
81 this.onDidFinishLoad = () => { };
82 this.suspendByStatus();
85 if (this.needDispatchTizenVisibilityChange)
86 this.sendTizenVisibilityEvent(this.webApplication.mainWindow.isVisible());
89 private sendTizenVisibilityEvent = (visibility: boolean) => {
90 console.log(`sendTizenVisibilityEvent call`);
91 this.needDispatchTizenVisibilityChange = false;
92 const kTizenvisibilityEventScript = `(function(){
93 var __event = document.createEvent("CustomEvent");
94 __event.initCustomEvent('tizenvisibilitychange', true, true, {visible: ${visibility} | 0});
95 document.dispatchEvent(__event);
96 for (var i=0; i < window.frames.length; i++)
97 window.frames[i].document.dispatchEvent(__event);
99 let webContents = this.webApplication.mainWindow.webContents;
100 wrt.executeJS(webContents, kTizenvisibilityEventScript);
103 private showInspectorGuide() {
104 console.log('WebApplication : showInspectorGuide');
105 this.showInspectorGuide = () => { }; // call once
106 const message = `${this.webApplication.debugPort.toString()}
107 Fast RWI is used, [about:blank] is loaded fist instead of
108 [${this.inspectorSrc}]
109 Click OK button will start the real loading.
111 Please connect to RWI in PC before click OK button.
112 Then you can get network log from the initial loading.
113 Please click Record button in Timeline panel in PC before click OK button,
114 Then you can get profile log from the initial loading.`;
115 let webContents = this.webApplication.mainWindow.webContents;
116 this.tv.showDialog(webContents, message);
117 if (this.preloadStatus !== 'none') {
119 this.tv.cancelDialogs(webContents);
124 private needSuspend() {
125 return this.launchMode !== 'runningAsBackground' &&
126 (this.preloadStatus === 'preload' || this.runningStatus === 'behind');
129 private suspendByStatus() {
130 if (this.needSuspend()) {
131 console.log('WebApplication : suspendByStatus');
132 console.log(`preloadStatus: ${this.preloadStatus}, runningStatus: ${this.runningStatus}`);
134 this.webApplication.suspend();
135 if (this.preloadStatus === 'preload')
136 this.runningStatus = 'preload';
137 this.tv.notifyAppStatus(this.runningStatus);
141 backgroundExecutableLaunchMode() {
142 return this.backgroundExecutionLaunchMode;
146 if (this.preloadStatus === 'preload' ||
147 this.launchMode === 'runningAsBackground') {
148 console.log(`preloadStatus is ${this.preloadStatus} or ${this.launchMode}, show is skipped`);
155 if (this.launchMode === 'runningAsForeground' ||
156 this.launchMode === 'runningAsBackground') {
157 console.log('WebApplication : view_suspend & multitasking feature is skipped!');
164 this.inspectorSrc = '';
165 this.tv.cancelDialogs(this.webApplication.mainWindow.webContents);
168 clearSurface(webContents: any) {
169 this.tv.clearSurface(webContents);
173 console.log('clearcache with low-memory');
174 this.webApplication.windowList.forEach((window) => {
175 //clear webframe cache
176 this.tv.clearWebCache(window.webContents);
177 window.webContents.session.clearCache().then(() => {
178 console.log('clear session Cache complete');
183 needInpectorGuide() {
184 let inspectorEnabledByVconf = this.tv.needUseInspector();
185 if (inspectorEnabledByVconf && !this.backgroundExecutionLaunchMode) {
186 this.inspectorSrc = this.webApplication.contentSrc;
187 this.webApplication.contentSrc = 'about:blank';
193 needReload(src: string) {
194 if (this.isAlwaysReload) {
198 let originalUrl = this.webApplication.mainWindow.webContents.getURL();
199 console.log(`appcontrol src = ${src}, original url = ${originalUrl}`);
200 if (src && originalUrl) {
201 let appcontrolUrl = (new URL(src)).href;
202 let oldUrl = (new URL(originalUrl)).href;
203 console.log(`appcontrolUrl = ${appcontrolUrl}, oldUrl = ${oldUrl}`);
205 // Below case it must be distinguishable for known cases
206 // from 'file:///index.htmlx' to 'file:///index.html'
207 if (appcontrolUrl !== oldUrl.substr(0, appcontrolUrl.length))
219 handleAppControlEvent(appControl: any) {
220 this.launchMode = appControl.getData('http://samsung.com/appcontrol/data/launch_mode');
221 this.preloadStatus = 'none';
223 if (this.launchMode === 'runningAsBackground') {
224 this.webApplication.suspended = false;
225 this.webApplication.windowList.forEach((window) => window.setEnabled(true));
226 this.webApplication.windowList[this.webApplication.windowList.length - 1].hide();
227 this.webApplication.sendAppControlEvent();
229 } else if (this.launchMode === 'runningAsForeground') {
230 this.webApplication.resume();
231 this.webApplication.sendAppControlEvent();
234 if (!this.webApplication.mainWindow.isVisible())
235 this.webApplication.show();
237 let skipReload = appControl.getData('SkipReload');
238 if (skipReload == 'Yes') {
239 console.log('skipping reload');
240 // TODO : Need to care this situation and decide to pass the addon event emitter to resume()
241 this.webApplication.resume();
246 if ('true' === this.backgroundExecutionMetaData) {
247 console.log(`handle AppControl background exectution app to show`);
248 this.webApplication.mainWindow.show();
253 handleProxyInfo(authInfo: any, callback: any) {
254 if (!authInfo.isProxy)
259 let vconfProxy = this.tv.getProxy();
261 let proxyInfo = new URL(vconfProxy);
262 usrname = proxyInfo.username;
263 passwd = proxyInfo.password;
265 if (usrname && passwd) {
266 callback(usrname, passwd);
268 console.log('Login, but usrname and passwd is empty!!!');
278 focus(webContents: any) {
279 this.tv.focus(webContents);