[VD] Segregates WebApplicationDelegateTV for TV profile 28/255828/14
authorDongHyun Song <dh81.song@samsung.com>
Wed, 24 Mar 2021 05:59:51 +0000 (14:59 +0900)
committerDongHyun Song <dh81.song@samsung.com>
Tue, 30 Mar 2021 05:28:48 +0000 (14:28 +0900)
WebApplicationDelegateTV will implements TV profile feature via
inherited from WebApplicationDelegate base class.

This patch will improve code readability of WebApplication class.

Change-Id: Ic785f47fc19ad69a93701744eab2a50e6175d7be
Signed-off-by: DongHyun Song <dh81.song@samsung.com>
wrt_app/common/web_application_delegate.ts [new file with mode: 0644]
wrt_app/src/runtime.ts
wrt_app/src/tv/web_application_tv.ts [new file with mode: 0644]
wrt_app/src/web_application.ts

diff --git a/wrt_app/common/web_application_delegate.ts b/wrt_app/common/web_application_delegate.ts
new file mode 100644 (file)
index 0000000..fcc4872
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021 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.
+ */
+
+'use strict';
+
+import { WebApplication } from '../src/web_application';
+
+export class WebApplicationDelegate {
+  webApplication: WebApplication;
+  constructor(webApplication: WebApplication) {
+    this.webApplication = webApplication;
+  }
+  initialize(options: RuntimeOption) { }
+  backgroundExecutable() { return false; }
+  beforeQuit() { }
+  clearCache() { }
+  clearSuface(webContents: any) { }
+  handleAppControlEvent(appControl: any) { return true; }
+  handleProxyInfo(authInfo: any, callback: any) { return false; }
+  needInpectorGuide() { return false; }
+  needReload(src: string) {
+    let originalUrl = this.webApplication.mainWindow.webContents.getURL();
+    if (src !== originalUrl) {
+      return true;
+    }
+    return false;
+  }
+  needShowTimer() { return true; }
+  isPreloading() { return false; }
+  onDidFinishLoad() { }
+  profileName() { return 'common' }
+  show() { }
+}
index 925a2e5..bd3bd01 100644 (file)
@@ -98,7 +98,7 @@ class Runtime {
 
     wrt.on('low-memory', () => {
       console.log('low-memory');
-      this.webApplication?.lowMemory();
+      this.webApplication?.clearCache();
     });
 
     wrt.on('message', (event: any, type: string, params: string[]) => {
diff --git a/wrt_app/src/tv/web_application_tv.ts b/wrt_app/src/tv/web_application_tv.ts
new file mode 100644 (file)
index 0000000..83e4b88
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2021 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.
+ */
+
+'use strict';
+
+import { protocol } from 'electron';
+import { wrt } from '../../browser/wrt';
+import { WebApplication } from '../web_application';
+import { WebApplicationDelegate } from '../../common/web_application_delegate';
+
+export class WebApplicationDelegateTV extends WebApplicationDelegate {
+  accessiblePath?: string[];
+  backgroundExecution: boolean = false;
+  inspectorSrc: string = '';
+  isAlwaysReload: boolean = false;
+  preloadStatus: string = 'none';
+  runningStatus: string = 'none';
+  tv: any = (wrt.tv as NativeWRTjs.TVExtension);
+
+  constructor(webApplication: WebApplication) {
+    super(webApplication);
+  }
+
+  initialize(options: RuntimeOption) {
+    if (options.launchMode == 'backgroundAtStartup') {
+      console.log('backgroundAtStartup');
+      this.preloadStatus = 'preload';
+    } else {
+      this.preloadStatus = 'none';
+    }
+    if (options.launchMode == 'backgroundExecution') {
+      console.log('backgroundExecution');
+      this.backgroundExecution = true;
+    } else {
+      this.backgroundExecution = false;
+    }
+    this.isAlwaysReload = this.tv.isAlwaysReload();
+    this.accessiblePath = this.tv.getAccessiblePath();
+
+    this.webApplication.multitaskingSupport = this.tv.getMultitaskingSupport();
+    this.webApplication.defaultBackgroundColor = '#0000';
+    this.webApplication.defaultTransparent = true;
+
+    this.initAccessiblePath();
+    this.initEventListener();
+  }
+
+  private initAccessiblePath() {
+    if (this.accessiblePath) {
+      console.log(`accessiblePath: ${this.accessiblePath}`);
+      protocol.interceptFileProtocol('file', (request: any, callback: any) => {
+        if (request.url) {
+          let parsed_info = new URL(request.url);
+          let access_path = parsed_info.host + decodeURI(parsed_info.pathname);
+          console.log(`check path: : ${access_path}`);
+          for (let path of (this.accessiblePath as string[])) {
+            if (access_path.startsWith(path)) {
+              callback(access_path);
+              return;
+            }
+          }
+          if (access_path.indexOf("/shared/res/") > -1) {
+            callback(access_path);
+            return;
+          }
+          else {
+            console.log(`invalid accesspath: ${access_path}`);
+            (callback as any)(403);
+          }
+        } else {
+          console.log('request url is empty');
+          (callback as any)(403);
+        }
+      }, (error: Error) => {
+        console.log(error);
+      });
+    }
+  }
+
+  initEventListener() {
+    wrt.on('app-status-changed', (event: any, status: string) => {
+      console.log(`runningStatus: ${status}, ${this.webApplication.loadFinished}`);
+      this.runningStatus = status;
+      if (this.runningStatus === 'DialogClose' && this.inspectorSrc) {
+        console.log(`runningStatus is DialogClose, src is ${this.inspectorSrc}`);
+        this.webApplication.mainWindow.loadURL(this.inspectorSrc);
+        this.inspectorSrc = '';
+      } else if (this.runningStatus == 'behind' && this.webApplication.loadFinished) {
+        // TODO : Need to care this situation and decide to pass the addon event emitter to suspend()
+        this.webApplication.suspend();
+      }
+    });
+  }
+
+  onDidFinishLoad() {
+    if (this.inspectorSrc)
+      this.showInspectorGuide();
+    else
+      this.suspendByStatus();
+  }
+
+  private showInspectorGuide() {
+    console.log('WebApplication : showInspectorGuide');
+    this.showInspectorGuide = () => { }; // call once
+    const message = `${this.webApplication.debugPort.toString()}
+Fast RWI is used, [about:blank] is loaded fist instead of
+[${this.inspectorSrc}]
+Click OK button will start the real loading.
+Notes:
+Please connect to RWI in PC before click OK button.
+Then you can get network log from the initial loading.
+Please click Record button in Timeline panel in PC before click OK button,
+Then you can get profile log from the initial loading.`;
+    let webContents = this.webApplication.mainWindow.webContents;
+    this.tv.showDialog(webContents, message);
+    if (this.preloadStatus !== 'none') {
+      setTimeout(() => {
+        this.tv.cancelDialogs(webContents);
+      }, 5000);
+    }
+  }
+
+  private suspendByStatus() {
+    if (this.preloadStatus === 'preload' ||
+      this.runningStatus === 'behind') {
+      console.log('WebApplication : suspendByStatus');
+      console.log(`preloadStatus: ${this.preloadStatus}, runningStatus: ${this.runningStatus}`);
+      // TODO : Need to care this situation and decide to pass the addon event emitter to suspend()
+      this.webApplication.suspend();
+      if (this.preloadStatus === 'preload')
+        this.runningStatus = 'preload';
+      this.tv.notifyAppStatus(this.runningStatus);
+    }
+  }
+
+  private handlePreloadState(launchMode: string) {
+    if (this.preloadStatus === 'preload') {
+      this.show();
+    } else {
+      if (launchMode != 'backgroundAtStartup')
+        this.preloadStatus = 'none';
+    }
+  }
+
+  backgroundExecutable() {
+    return this.backgroundExecution;
+  }
+
+  isPreloading() {
+    if (this.preloadStatus == 'preload') {
+      console.log('preloading show is skipped!');
+      return true;
+    }
+    return false;
+  }
+
+  show() {
+    this.preloadStatus = 'none';
+  }
+
+  beforeQuit() {
+    this.inspectorSrc = '';
+    this.tv.cancelDialogs(this.webApplication.mainWindow.webContents);
+  }
+
+  clearSurface(webContents: any) {
+    this.tv.clearSurface(webContents);
+  }
+
+  clearCache() {
+    console.log('clearcache with low-memory');
+    this.webApplication.windowList.forEach((window) => {
+      //clear webframe cache
+      this.tv.clearWebCache(window.webContents);
+      window.webContents.session.clearCache(function() {
+        console.log('clear session Cache complete');
+      })
+    });
+  }
+
+  needInpectorGuide() {
+    let inspectorEnabledByVconf = this.tv.needUseInspector();
+    if (inspectorEnabledByVconf && !this.backgroundExecution) {
+      this.inspectorSrc = this.webApplication.contentSrc;
+      this.webApplication.contentSrc = 'about:blank';
+      return true;
+    }
+    return false;
+  }
+
+  needReload(src: string) {
+    if (this.isAlwaysReload) {
+      return true;
+    }
+    let reload = false;
+    let originalUrl = this.webApplication.mainWindow.webContents.getURL();
+    console.log(`appcontrol src = ${src}, original url = ${originalUrl}`);
+    if (src && originalUrl) {
+      let appcontrolUrl = (new URL(src)).href;
+      let oldUrl = (new URL(originalUrl)).href;
+      console.log(`appcontrolUrl = ${appcontrolUrl}, oldUrl = ${oldUrl}`);
+      // FIXME(dh81.song)
+      // Below case it must be distinguishable for known cases
+      //   from 'file:///index.htmlx' to 'file:///index.html'
+      if (appcontrolUrl !== oldUrl.substr(0, appcontrolUrl.length))
+        reload = true;
+    } else {
+      reload = true;
+    }
+    return reload;
+  }
+
+  needShowTimer() {
+    return false;
+  }
+
+  handleAppControlEvent(appControl: any) {
+    let launchMode = appControl.getData('http://samsung.com/appcontrol/data/launch_mode');
+    this.handlePreloadState(launchMode);
+
+    let skipReload = appControl.getData('SkipReload');
+    if (skipReload == 'Yes') {
+      console.log('skipping reload');
+      // TODO : Need to care this situation and decide to pass the addon event emitter to resume()
+      this.webApplication.resume();
+      return false;
+    }
+    return true;
+  }
+
+  handleProxyInfo(authInfo: any, callback: any) {
+    if (!authInfo.isProxy)
+      return false;
+
+    let usrname = '';
+    let passwd = '';
+    let vconfProxy = this.tv.getProxy();
+    if (vconfProxy) {
+      let proxyInfo = new URL(vconfProxy);
+      usrname = proxyInfo.username;
+      passwd = proxyInfo.password;
+    }
+    if (usrname && passwd) {
+      callback(usrname, passwd);
+    } else {
+      console.log('Login, but usrname and passwd is empty!!!');
+      callback('', '');
+    }
+    return true;
+  }
+
+  profileName() {
+    return 'TV';
+  }
+}
index 7fa658e..f2e3d1a 100644 (file)
 
 'use strict';
 
-import { app, protocol } from 'electron';
+import { app } from 'electron';
 import { wrt } from '../browser/wrt';
 import * as WRTWebContents from '../browser/wrt_web_contents';
 import { WRTWindow } from '../browser/wrt_window';
 import { addonManager } from './addon_manager';
+import { WebApplicationDelegate } from '../common/web_application_delegate';
+import { WebApplicationDelegateTV } from './tv/web_application_tv';
 
 export class WebApplication {
-  accessiblePath?: string[];
-  backgroundExecution: boolean;
-  defaultBackgroundColor: string;
-  defaultTransparent: boolean;
-  isAlwaysReload: boolean;
+  defaultBackgroundColor: string = (wrt.getPlatformType() === "product_wearable") ? '#000' : '#FFF';
+  defaultTransparent: boolean = false;
   mainWindow: Electron.BrowserWindow;
-  multitaskingSupport: boolean;
+  multitaskingSupport: boolean = true;
   notificationPermissionMap?: Map<Electron.WebContents, boolean>;
-  preloadStatus: string;
   showTimer?: NodeJS.Timeout;
 
-  backgroundSupport = wrt.getBackgroundSupport();
-  debugPort = 0;
-  firstRendered = false;
-  contentSrc = '';
-  inspectorSrc = '';
-  loadFinished = false;
+  backgroundSupport: boolean = wrt.getBackgroundSupport();
+  debugPort: number = 0;
+  firstRendered: boolean = false;
+  contentSrc: string = '';
+  loadFinished: boolean = false;
   pendingCallbacks: Map<number, any> = new Map();
-  pendingID = 0;
-  runningStatus = 'none';
-  suspended = false;
+  pendingID: number = 0;
+  suspended: boolean = false;
   windowList: Electron.BrowserWindow[] = [];
-  inQuit = false;
+  inQuit: boolean = false;
+  profileDelegate: WebApplicationDelegate;
 
   constructor(options: RuntimeOption) {
-    if (options.launchMode == 'backgroundAtStartup') {
-      console.log('backgroundAtStartup');
-      this.preloadStatus = 'preload';
-    } else {
-      this.preloadStatus = 'none';
-    }
-    if (options.launchMode == 'backgroundExecution') {
-      console.log('backgroundExecution');
-      this.backgroundExecution = true;
+    if (wrt.tv) {
+      this.profileDelegate = new WebApplicationDelegateTV(this);
+      this.profileDelegate.initialize(options);
     } else {
-      this.backgroundExecution = false;
+      this.profileDelegate = new WebApplicationDelegate(this);
     }
-    this.accessiblePath = wrt.tv?.getAccessiblePath();
-    this.isAlwaysReload = (wrt.tv ? wrt.tv.isAlwaysReload() : false);
-    this.multitaskingSupport = (wrt.tv ? wrt.tv.getMultitaskingSupport() : true);
-    this.defaultBackgroundColor = (wrt.tv ? '#0000' :
-        ((wrt.getPlatformType() === "product_wearable") ? '#000' : '#FFF'));
-    this.defaultTransparent = (wrt.tv ? true : false);
-
     this.setupEventListener(options);
-
     this.mainWindow = new WRTWindow(this.getWindowOption(options));
     this.initDisplayDelay();
     this.setupMainWindowEventListener();
@@ -148,22 +131,7 @@ export class WebApplication {
     app.on('login', (event: any, webContents: any, request: any, authInfo: any, callback: any) => {
       console.log(`Login info is required, isproxy: ${authInfo.isProxy}`);
       event.preventDefault();
-      let usrname = '';
-      let passwd = '';
-      if (wrt.tv && authInfo.isProxy) {
-        let vconfProxy = wrt.tv.getProxy();
-        if (vconfProxy) {
-          let proxyInfo = new URL(vconfProxy);
-          usrname = proxyInfo.username;
-          passwd = proxyInfo.password;
-        }
-        if (usrname && passwd) {
-          callback(usrname, passwd);
-        } else {
-          console.log('Login, but usrname and passwd is empty!!!');
-          callback('', '');
-        }
-      } else {
+      if (!this.profileDelegate.handleProxyInfo(authInfo, callback)) {
         const id = ++this.pendingID;
         console.log(`Raising a login info request with id: ${id}`);
         this.pendingCallbacks.set(id, callback);
@@ -171,36 +139,6 @@ export class WebApplication {
       }
     });
 
-    if (this.accessiblePath) {
-      console.log(`accessiblePath: ${this.accessiblePath}`);
-      protocol.interceptFileProtocol('file', (request: any, callback: any) => {
-        if (request.url) {
-          let parsed_info = new URL(request.url);
-          let access_path = parsed_info.host + decodeURI(parsed_info.pathname);
-          console.log(`check path: : ${access_path}`);
-          for (let path of (this.accessiblePath as string[])) {
-            if (access_path.startsWith(path)) {
-              callback(access_path);
-              return;
-            }
-          }
-          if (access_path.indexOf("/shared/res/") > -1) {
-            callback(access_path);
-            return;
-          }
-          else {
-            console.log(`invalid accesspath: ${access_path}`);
-            (callback as any)(403);
-          }
-        } else {
-          console.log('request url is empty');
-          (callback as any)(403);
-        }
-      }, (error: Error) => {
-        console.log(error);
-      });
-    }
-
     wrt.on('permission-response', (event: any, id: number, result: boolean) => {
       console.log(`permission-response for ${id} is ${result}`);
       let callback = this.pendingCallbacks.get(id);
@@ -222,21 +160,6 @@ export class WebApplication {
         this.pendingCallbacks.delete(id);
       }
     });
-
-    wrt.on('app-status-changed', (event: any, status: string) => {
-      console.log(`runningStatus: ${status}, ${this.loadFinished}`);
-      if (!wrt.tv)
-        return;
-      this.runningStatus = status;
-      if (this.runningStatus === 'DialogClose' && this.inspectorSrc) {
-        console.log(`runningStatus is DialogClose, src is ${this.inspectorSrc}`);
-        this.mainWindow.loadURL(this.inspectorSrc);
-        this.inspectorSrc = '';
-      } else if (this.runningStatus == 'behind' && this.loadFinished) {
-        // TODO : Need to care this situation and decide to pass the addon event emitter to suspend()
-        this.suspend();
-      }
-    });
   }
 
   private getWindowOption(options: RuntimeOption): NativeWRTjs.WRTWindowConstructorOptions {
@@ -261,11 +184,8 @@ export class WebApplication {
         clearTimeout(this.showTimer);
       wrt.hideSplashScreen(0);
       this.firstRendered = true;
-      if (this.preloadStatus == 'preload') {
-        this.preloadStatus = 'readyToShow';
-        console.log('preloading show is skipped!');
+      if (this.profileDelegate.isPreloading())
         return;
-      }
       this.show();
     });
 
@@ -281,11 +201,8 @@ export class WebApplication {
       addonManager.emit('contentDidFinishLoad', this.mainWindow.id);
       if (wrt.isIMEWebApp()) {
         this.activateIMEWebHelperClient();
-      } else if (wrt.tv) {
-        if (this.inspectorSrc)
-          this.showInspectorGuide();
-        else
-          this.suspendByStatus();
+      } else {
+        this.profileDelegate.onDidFinishLoad();
       }
     });
   }
@@ -300,8 +217,11 @@ export class WebApplication {
   }
 
   private initDisplayDelay() {
-    let splashShown = this.preloadStatus !== 'preload' && wrt.showSplashScreen();
-    if (splashShown || wrt.tv)
+    if (this.profileDelegate.isPreloading())
+      return;
+
+    let splashShown = wrt.showSplashScreen();
+    if (splashShown || !this.profileDelegate.needShowTimer())
       return;
 
     this.showTimer = setTimeout(() => {
@@ -312,60 +232,18 @@ export class WebApplication {
     }, 2000);
   }
 
-  private backgroundRunnable(): boolean {
-    return this.backgroundSupport || this.backgroundExecution;
-  }
-
-  private suspendByStatus() {
-    if (this.preloadStatus === 'readyToShow' ||
-        this.preloadStatus === 'preload' ||
-        this.runningStatus === 'behind') {
-      console.log('WebApplication : suspendByStatus');
-      console.log(`preloadStatus: ${this.preloadStatus}, runningStatus: ${this.runningStatus}`);
-      // TODO : Need to care this situation and decide to pass the addon event emitter to suspend()
-      this.suspend();
-      if (this.runningStatus !== 'behind')
-        (wrt.tv as NativeWRTjs.TVExtension).notifyAppStatus('preload');
-    }
-  }
-
-  private showInspectorGuide() {
-    console.log('WebApplication : showInspectorGuide');
-    this.showInspectorGuide = () => {}; // call once
-    const message = `${this.debugPort.toString()}
-Fast RWI is used, [about:blank] is loaded fist instead of
-[${this.inspectorSrc}]
-Click OK button will start the real loading.
-Notes:
-Please connect to RWI in PC before click OK button.
-Then you can get network log from the initial loading.
-Please click Record button in Timeline panel in PC before click OK button,
-Then you can get profile log from the initial loading.`;
-    let tv = wrt.tv as NativeWRTjs.TVExtension;
-    tv.showDialog(this.mainWindow.webContents, message);
-
-    if (this.preloadStatus !== 'none') {
-      setTimeout(() => {
-        tv.cancelDialogs(this.mainWindow.webContents);
-      }, 5000);
-    }
+  private backgroundRunnable() {
+    return this.backgroundSupport || this.profileDelegate.backgroundExecutable();
   }
 
   handleAppControlEvent(appControl: any) {
-    let launchMode = appControl.getData('http://samsung.com/appcontrol/data/launch_mode');
-    this.handlePreloadState(launchMode);
-
-    let skipReload = appControl.getData('SkipReload');
-    if (skipReload == 'Yes') {
-      console.log('skipping reload');
-      // TODO : Need to care this situation and decide to pass the addon event emitter to resume()
-      this.resume();
+    if (!this.profileDelegate.handleAppControlEvent(appControl)) {
       return;
     }
 
     let loadInfo = appControl.getLoadInfo();
     let src = loadInfo.getSrc();
-    let reload = loadInfo.getReload() || this.needReload(src);
+    let reload = loadInfo.getReload() || this.profileDelegate.needReload(src);
     // handle http://tizen.org/appcontrol/operation/main operation specially.
     // only menu-screen app can send launch request with main operation.
     // in this case, web app should have to resume web app not reset.
@@ -379,13 +257,10 @@ Then you can get profile log from the initial loading.`;
 
   private launchInspectorIfNeeded(appControl: NativeWRTjs.AppControl) {
     console.log('launchInspectorIfNeeded');
-    let inspectorEnabledByVconf = wrt.tv ? wrt.tv.needUseInspector() : false;
-    if (inspectorEnabledByVconf && !this.backgroundExecution) {
-      this.inspectorSrc = this.contentSrc;
-      this.contentSrc = 'about:blank';
-    }
+    let needInpectorGuide = this.profileDelegate.needInpectorGuide();
     let hasAulDebug = (appControl.getData('__AUL_DEBUG__') === '1');
-    if (hasAulDebug || inspectorEnabledByVconf) {
+
+    if (hasAulDebug || needInpectorGuide) {
       let debugPort = wrt.startInspectorServer();
       let data = { "port": [debugPort.toString()] };
       this.debugPort = debugPort;
@@ -447,11 +322,8 @@ Then you can get profile log from the initial loading.`;
 
   beforeQuit() {
     console.log('WebApplication : beforeQuit');
+    this.profileDelegate.beforeQuit();
     addonManager.emit('lcQuit', this.mainWindow.id);
-    if (wrt.tv) {
-      this.inspectorSrc = '';
-      wrt.tv.cancelDialogs(this.mainWindow.webContents);
-    }
     if (this.debugPort) {
       console.log('stop inspector server');
       this.debugPort = 0;
@@ -460,32 +332,6 @@ Then you can get profile log from the initial loading.`;
     this.inQuit = true;
   }
 
-  private needReload(src: string) {
-    if (this.isAlwaysReload) {
-      return true;
-    }
-    let reload = false;
-    let originalUrl = this.mainWindow.webContents.getURL();
-    if (wrt.tv) {
-      console.log(`appcontrol src = ${src}, original url = ${originalUrl}`);
-      if (src && originalUrl) {
-        let appcontrolUrl = (new URL(src)).href;
-        let oldUrl = (new URL(originalUrl)).href;
-        console.log(`appcontrolUrl = ${appcontrolUrl}, oldUrl = ${oldUrl}`);
-        // FIXME(dh81.song)
-        // Below case it must be distinguishable for known cases
-        //   from 'file:///index.htmlx' to 'file:///index.html'
-        if (appcontrolUrl !== oldUrl.substr(0, appcontrolUrl.length))
-          reload = true;
-      } else {
-        reload = true;
-      }
-    } else if (src !== originalUrl) {
-      reload = true;
-    }
-    return reload;
-  }
-
   private handleAppControlReload(url: string) {
     console.log('WebApplication : handleAppControlReload');
     this.closeWindows();
@@ -493,15 +339,6 @@ Then you can get profile log from the initial loading.`;
     this.mainWindow.loadURL(url);
   }
 
-  private handlePreloadState(launchMode: string) {
-    if (this.preloadStatus == 'readyToShow') {
-      this.show();
-    } else {
-      if (launchMode != 'backgroundAtStartup')
-        this.preloadStatus = 'none';
-    }
-  }
-
   private flushData() {
     console.log('WebApplication : FlushData');
     this.windowList.forEach((window) => window.webContents.session.flushStorageData());
@@ -527,17 +364,17 @@ Then you can get profile log from the initial loading.`;
 
   show() {
     console.log('WebApplication : show');
-    this.preloadStatus = 'none';
-    if (this.backgroundExecution) {
+    if (this.profileDelegate.backgroundExecutable()) {
       console.log('skip showing while backgroundExecution mode');
     } else if (!this.mainWindow.isVisible()) {
       console.log('show window');
       this.mainWindow.show();
     }
+    this.profileDelegate.show();
   }
 
   private closeWindows() {
-    wrt.tv?.clearSurface(this.mainWindow.webContents);
+    this.profileDelegate.clearSuface(this.mainWindow.webContents);
     this.windowList.forEach((window) => {
       if (window != this.mainWindow)
         window.destroy();
@@ -566,17 +403,8 @@ Then you can get profile log from the initial loading.`;
     addonManager.emit('lcPrelaunch', this.mainWindow.id, url);
   }
 
-  lowMemory() {
-    console.log('WebApplication : lowMemory to clearcache');
-    if (!wrt.tv)
-      return;
-    this.windowList.forEach((window) => {
-      //clear webframe cache
-      (wrt.tv as NativeWRTjs.TVExtension).clearWebCache(window.webContents);
-      window.webContents.session.clearCache(function() {
-        console.log('clear session Cache complete');
-      })
-    });
+  clearCache() {
+    this.profileDelegate.clearCache();
   }
 
   ambientTick() {