• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15import UIExtensionAbility from '@ohos.app.ability.UIExtensionAbility';
16import window from '@ohos.window';
17import { Log, PermissionDialogException, setAvoidArea } from '../common/utils/utils';
18import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession';
19import Want from '@ohos.app.ability.Want';
20import uiExtensionHost from '@ohos.uiExtensionHost';
21import display from '@ohos.display';
22import { BusinessError } from '@ohos.base';
23import Constants from '../common/utils/constant';
24import AbilityConstant from '@ohos.app.ability.AbilityConstant';
25import deviceInfo from '@ohos.deviceInfo';
26
27let terminating: boolean = false;
28let state: boolean = false;
29
30export default class PermissionStateSheetAbility extends UIExtensionAbility {
31  private subWindowForHost: window.Window | null = null;
32  private shouldChangeState: boolean = true;
33
34  onCreate(launchParam: AbilityConstant.LaunchParam): void {
35    Log.info('PermissionStateSheetAbility on create');
36    if (deviceInfo.deviceType === 'wearable') {
37      this.context.terminateSelf();
38      Log.info('PermissionStateSheetAbility terminateSelf');
39      return;
40    }
41  }
42
43  onSessionCreate(want: Want, session: UIExtensionContentSession): void {
44    Log.info('current state:' + state);
45    if (state == true) {
46      this.shouldChangeState = false;
47      Log.error('window state is already set');
48      PermissionDialogException(Constants.ERR_MODAL_ALREADY_EXIST, session);
49      this.context.terminateSelf();
50      return;
51    } else {
52      Log.info('set window state to true');
53      state = true;
54    }
55
56    let param: Record<string, Object> = {
57      'session': session, 'want': want
58    };
59
60    let storage: LocalStorage = new LocalStorage(param);
61    this.createSubWindow(session, storage).then(() => {
62      // if met error, do not load window,
63      // in case of nested error codes passed to applications
64      if (terminating) {
65        this.context.terminateSelf();
66        return;
67      }
68      this.loadContentAndSetColor(storage).then((result: boolean) => {
69        if (!result) {
70          return;
71        }
72        this.showWindow();
73      })
74    })
75  }
76
77  onSessionDestroy(): void {
78    Log.info('OnSessionDestroy start');
79    try {
80      Log.info('try to reshow non-secure windows.');
81      this.subWindowForHost?.hideNonSystemFloatingWindows(false);
82    } catch (error) {
83      Log.error('failed to reshowing the non-secure windows. Cause: ' + JSON.stringify(error));
84    }
85    try {
86      this.subWindowForHost?.off('windowEvent');
87    } catch (exception) {
88      Log.error('fail to call off window event: ' + JSON.stringify(exception));
89    }
90    this.subWindowForHost?.destroyWindow((err, data) => {
91      if (err && err.code !== 0) {
92        Log.info('destroy window:' + err.message + ' ' + JSON.stringify(data));
93      }
94    });
95    Log.info('destroy window end');
96  }
97
98  onForeground(): void {
99    Log.info('onForegorund');
100    this.subWindowForHost?.showWindow();
101  }
102
103  onBackground(): void {
104    Log.info('extension onBackground');
105    this.subWindowForHost?.hide();
106  }
107
108  onDestroy(): void | Promise<void> {
109    Log.info('onDestroy');
110    if (this.shouldChangeState == true) {
111      state = false;
112      Log.info('set window state to false');
113    }
114    this.subWindowForHost = null;
115  }
116
117  async loadContentAndSetColor(storage: LocalStorage): Promise<boolean> {
118    let promise: Promise<void> | undefined =
119      this.subWindowForHost?.loadContent('PermissionSheet/PermissionStateSheetDialog', storage);
120    if (promise) {
121      await promise.then(() => {
122        Log.info('Succeeded in loading the content');
123        try {
124          this.subWindowForHost?.setWindowBackgroundColor('#00000000');
125        } catch (error) {
126          Log.error(`setWindowBackgroundColor failed, error code ${JSON.stringify(error)}`);
127        }
128      }).catch((err: BusinessError) => {
129        Log.error('Failed to load the content. Cause:' + JSON.stringify(err));
130        return false;
131      })
132    }
133    return true;
134  }
135
136  async createSubWindow(session: UIExtensionContentSession, storage: LocalStorage): Promise<void> {
137    let extensionWinProxy: uiExtensionHost.UIExtensionHostWindowProxy = session?.getUIExtensionHostWindowProxy();
138    setAvoidArea(extensionWinProxy);
139    let subWindowOpts: window.SubWindowOptions = {
140      title: '', decorEnabled: false, isModal: true,
141    };
142    if (!extensionWinProxy) {
143      Log.error('extensionWinProxy is nullptr!');
144      return;
145    }
146    // try to create subwindow first
147    await extensionWinProxy.createSubWindowWithOptions('permissionSubWindowForHost' + Date(), subWindowOpts)
148      .then((subWindow: window.Window)=>{
149        this.subWindowForHost = subWindow;
150      }).catch((err: BusinessError) => {
151        Log.error('create sub window error:' + err.message + ' ' + err.code);
152      });
153    // if create subwindow fails, try create floating window
154    if (!this.subWindowForHost) {
155      Log.error('subwindow is null, failed to create subwindow, tray create float window');
156      await this.createFloatingWindow(session);
157      if (!this.subWindowForHost) {
158        terminating = true;
159        PermissionDialogException(Constants.ERR_MODAL_ALREADY_EXIST, session);
160        this.context.terminateSelf();
161        Log.error('floating is null, failed to create float window, terminate self');
162        return;
163      }
164    }
165    try {
166      let dis = display.getDefaultDisplaySync();
167      await this.subWindowForHost?.resize(dis.width, dis.height).catch((err: BusinessError) => {
168        Log.error('resize window error: ' + err.code + ' ' + err.message);
169      });
170    } catch (error) {
171      Log.error('getDefaultDisplaySync error: ' + error.code + ' ' + error.message);
172    }
173    this.subWindowForHost?.on('windowEvent', (eventType: window.WindowEventType) => {
174      Log.info('window event type is: ' + eventType);
175      storage.setOrCreate('permissionWindow', eventType);
176    })
177    Log.info('create and resize window success');
178    return;
179  }
180
181  async createFloatingWindow(session: UIExtensionContentSession): Promise<void> {
182    let config: window.Configuration = {
183      name: 'PermissionFloatWindow' + Date(),
184      windowType: window.WindowType.TYPE_FLOAT,
185      ctx: this.context
186    }
187    let promise: Promise<window.Window> | undefined = window.createWindow(config);
188    await promise.then((floatWindow: window.Window) => {
189      this.subWindowForHost = floatWindow;
190      session.loadContent('');
191      session.setWindowBackgroundColor('#00000000');
192    }).catch((err: BusinessError) => {
193      Log.error('create floating window error:' + err.message + ' ' + err.code);
194      // if modal already exist , return
195      if (err.code === Constants.CREATE_WINDOW_REPEATED) {
196        Log.error('try to create subwindow repeatedly');
197        terminating = true;
198        PermissionDialogException(Constants.ERR_MODAL_ALREADY_EXIST, session);
199        this.context.terminateSelf();
200      }
201    });
202    if (!this.subWindowForHost) {
203      Log.error('create floating fail');
204      return;
205    }
206    Log.info('create floating window success');
207  }
208
209  showWindow(): void {
210    this.subWindowForHost?.showWindow((err) => {
211      if (err && err.code !== 0) {
212        Log.error(`failed to showWindow for subWindow, ${JSON.stringify(err)}`);
213        return;
214      }
215      this.subWindowForHost?.hideNonSystemFloatingWindows(true);
216      Log.info('show window and set non floating success');
217    })
218  }
219}