1/*
2 * Copyright (c) 2022 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 ServiceExtensionAbility from '@ohos.app.ability.ServiceExtensionAbility';
16import common from '@ohos.app.ability.common';
17import window from '@ohos.window';
18import inputMethod from '@ohos.inputMethod';
19import commonEvent from '@ohos.commonEventManager';
20import Want from '@ohos.app.ability.Want';
21import { BusinessError } from '@ohos.base';
22
23let TAG: string = '[InputMethodChooseDialog]';
24let PACKAGE_ADDED: string = 'usual.event.PACKAGE_ADDED';
25let PACKAGE_REMOVED: string = 'usual.event.PACKAGE_REMOVED';
26let subscribeInfo: commonEvent.CommonEventSubscribeInfo = {
27  events: [PACKAGE_ADDED, PACKAGE_REMOVED]
28};
29
30interface DialogRect {
31  left: number;
32  top: number;
33  width: number;
34  height: number;
35}
36
37export default class ServiceExtAbility extends ServiceExtensionAbility {
38  private extensionWin: window.Window | undefined = undefined;
39  private mContext: common.ServiceExtensionContext | undefined = undefined;
40  private windowNum: number = 0;
41
42  onCreate(want: Want): void {
43    console.log(TAG, 'onCreate');
44    this.windowNum = 0;
45    this.mContext = this.context;
46  }
47
48  onRequest(want: Want, startId: number): void {
49    console.log(TAG, 'onRequest execute');
50    let dialogRect: DialogRect = {
51      left: 50,
52      top: 900,
53      width: 300,
54      height: 300,
55    };
56    let windowConfig: window.Configuration = {
57      name: 'inputmethod Dialog',
58      windowType: window.WindowType.TYPE_FLOAT,
59      ctx: this.mContext
60    };
61    this.getInputMethods().then(() => {
62      this.createWindow(windowConfig, dialogRect);
63    });
64
65    commonEvent.createSubscriber(subscribeInfo, (error: BusinessError, subcriber: commonEvent.CommonEventSubscriber) => {
66      commonEvent.subscribe(subcriber, (error: BusinessError, commonEventData: commonEvent.CommonEventData) => {
67        if (error) {
68          console.log(TAG + `commonEvent subscribe error, errorCode: ${error}`);
69          return;
70        }
71        console.log(TAG + 'commonEvent:' + JSON.stringify(commonEventData?.event));
72        if (commonEventData?.event === PACKAGE_ADDED || commonEventData?.event === PACKAGE_REMOVED) {
73          this.updateImeList();
74        }
75      });
76    });
77  }
78
79  onDestroy(): void {
80    console.log(TAG + 'ServiceExtAbility destroyed');
81    this.releaseContext();
82  }
83
84  private async createWindow(config: window.Configuration, rect: DialogRect): Promise<void> {
85    console.log(TAG + 'createWindow execute');
86    try {
87      if (this.windowNum > 0) {
88        this.updateImeList();
89        return;
90      }
91      try {
92        this.extensionWin = await window.createWindow(config);
93        console.info(TAG + 'Succeeded in creating the window. Data: ' + JSON.stringify(this.extensionWin));
94        this.extensionWin.on('windowEvent', async (data: window.WindowEventType) => {
95          console.log(TAG + 'windowEvent:' + JSON.stringify(data));
96          if (data === window.WindowEventType.WINDOW_INACTIVE) {
97            await this.releaseContext();
98          }
99        });
100        await this.extensionWin.moveWindowTo(rect.left, rect.top);
101        await this.extensionWin.resize(rect.width, rect.height);
102        await this.extensionWin.setUIContent('pages/index');
103        await this.extensionWin.showWindow();
104        this.windowNum++;
105        console.log(TAG + 'window create successfully');
106      } catch (exception) {
107        console.error('Failed to create the window. Cause: ' + JSON.stringify(exception));
108      }
109    } catch {
110      console.info(TAG + 'window create failed');
111    }
112  }
113
114  private async getInputMethods(): Promise<void> {
115    let inputMethodList: Array<inputMethod.InputMethodProperty> = [];
116    try {
117      let enableList = await inputMethod.getSetting().getInputMethods(true);
118      let disableList = await inputMethod.getSetting().getInputMethods(false);
119      inputMethodList = enableList.concat(disableList);
120      AppStorage.setOrCreate('inputMethodList', inputMethodList);
121    } catch {
122      console.log(TAG + 'getInputMethods failed');
123    }
124  }
125
126  private async updateImeList(): Promise<void> {
127    await this.getInputMethods().then(async () => {
128      if (this.extensionWin) {
129        await this.extensionWin.setUIContent('pages/index');
130        if (!this.extensionWin.isWindowShowing()) {
131          await this.extensionWin.showWindow();
132        }
133      }
134    });
135  }
136
137  public async releaseContext(): Promise<void> {
138    await this.extensionWin?.destroyWindow();
139    await this.mContext?.terminateSelf();
140  }
141};