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 */
15
16import util from '@ohos.util';
17import notificationManager from '@ohos.notificationManager';
18import inputEventClient from '@ohos.multimodalInput.inputEventClient';
19import WantAgent, { WantAgent as _WantAgent } from '@ohos.app.ability.wantAgent';
20import CommonEventManager from '@ohos.commonEventManager';
21import Base from '@ohos.base';
22import type context from '@ohos.app.ability.common';
23import image from '@ohos.multimedia.image';
24import GlobalContext from '../common/GlobalContext';
25
26const TAG: string = 'InjectNotice';
27const LABEL: string = 'inject notice';
28const EVENT_NAME: string = 'event_inject_close_notice';
29export const NOTICE_ID: number = 100;
30
31export enum InjectNoticeStatus {
32  DEFAULT = 0,
33  OPENING = 1,
34  SERVER_CLOSE = 2,
35  MAN_CLOSE = 3,
36};
37
38class InjectNoticeUtil {
39  status: InjectNoticeStatus = InjectNoticeStatus.DEFAULT;
40  isInit: boolean = false;
41  removalWantAgentObj: _WantAgent = null;
42  removalWantAgentInfo: WantAgent.WantAgentInfo = {
43    wants: [
44      {
45        action: EVENT_NAME,
46        parameters: {
47          noticeId: NOTICE_ID,
48          noticeLabel: LABEL,
49        },
50      }
51    ],
52    actionType: WantAgent.OperationType.SEND_COMMON_EVENT,
53    requestCode: 0,
54    actionFlags: [WantAgent.WantAgentFlags.CONSTANT_FLAG],
55  };
56  commonEventSubscriber: CommonEventManager.CommonEventSubscriber = null;
57  capsuleIcon: image.PixelMap | null = null;
58  constructor() {
59
60  }
61
62  async init(): Promise<void> {
63    console.info(TAG, `init begin`);
64    if (this.isInit) {
65      return;
66    }
67    this.initRemovalWantAgent();
68    this.createCommonEventSubscriber();
69    let systemLiveViewSubscriber: notificationManager.SystemLiveViewSubscriber = {
70      onResponse: this.onLiveNoticeResponseCallback,
71    };
72    console.info(TAG, 'subscribeSystemLiveView begin');
73    notificationManager.subscribeSystemLiveView(systemLiveViewSubscriber).then(() => {
74      console.info(TAG, 'subscribeSystemLiveView success');
75    }).catch((error: Base.BusinessError) => {
76      console.error(`subscribeSystemLiveView fail: ${JSON.stringify(error)}`);
77    });
78    console.info(TAG, 'initCapsuleIcon begin');
79    this.initCapsuleIcon();
80    console.info(TAG, 'init end');
81    this.isInit = true;
82  }
83
84  async cancelNotificationById(id: number): Promise<void> {
85    try {
86      await notificationManager.cancel(id, LABEL);
87      console.info(TAG, 'cancel notification success');
88    } catch (err) {
89      if (err) {
90        console.error(TAG, 'cancel notification err: ' + JSON.stringify(err));
91      }
92    }
93  }
94
95  sendNotice(): void {
96    console.debug(TAG, 'sendNotice begin==>');
97    console.debug(TAG, `removalWantAgentObj is ${this.removalWantAgentObj}`);
98    let applicationContext = (GlobalContext.getContext().getObject('appcontext')) as context.ApplicationContext;
99    let resourceManager = applicationContext.resourceManager;
100    let imagePixelMap = resourceManager.getDrawableDescriptor($r('app.media.icon_notice')).getPixelMap();
101    let capsuleColor = resourceManager.getColorSync($r('sys.color.ohos_id_color_warning'));
102    let title = resourceManager.getStringSync($r('app.string.notice_title'));
103    let text = resourceManager.getStringSync($r('app.string.notice_text'));
104    text = util.format(text, '');
105    let noticeText = resourceManager.getStringSync($r('app.string.notice_title'));
106    let cancelBnText = resourceManager.getStringSync($r('app.string.bn_notice_cancel'));
107    let cancelBnImage = resourceManager.getDrawableDescriptor($r('app.media.link_slash')).getPixelMap();
108    let notificationRequest: notificationManager.NotificationRequest = {
109      id: NOTICE_ID,
110      label: LABEL,
111      isOngoing: true,
112      isFloatingIcon: true,
113      smallIcon: imagePixelMap,
114      isUnremovable: false,
115      removalWantAgent: this.removalWantAgentObj,
116      notificationSlotType: notificationManager.SlotType.LIVE_VIEW,
117      content: {
118        notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_SYSTEM_LIVE_VIEW,
119        systemLiveView: {
120          title: title,
121          text: text,
122          typeCode: 1,
123          capsule: {
124            title: noticeText,
125            backgroundColor: String(capsuleColor),
126            icon: this.capsuleIcon!
127
128          },
129          button: {
130            names: [cancelBnText],
131            icons: [cancelBnImage],
132          },
133        },
134      },
135    };
136
137    console.debug(TAG, `publish content is ${JSON.stringify(notificationRequest)}`);
138    notificationManager.publish(notificationRequest, (err: Base.BusinessError) => {
139      if (err) {
140        console.error(TAG, TAG + `Failed to publish notification. Code is ${err.code}, message is ${err.message}`);
141        return;
142      }
143      console.info(TAG, 'succeeded in publishing notification.');
144    });
145  }
146
147  async initRemovalWantAgent(): Promise<void> {
148    console.info(TAG, 'initRemovalWantAgent begin');
149    if (this.removalWantAgentObj !== null) {
150      console.info(TAG, 'RemovalWantAgent has init');
151      return;
152    }
153    try {
154      await WantAgent.getWantAgent(this.removalWantAgentInfo).then((data) => {
155        this.removalWantAgentObj = data;
156        console.info(TAG, `initRemovalWantAgent getWantAgent ok`);
157      }).catch((err: Base.BusinessError) => {
158        console.error(TAG, `initRemovalWantAgent getWantAgent failed, code: ${JSON.stringify(err.code)}, message: ${JSON.stringify(err.message)}`);
159      });
160    } catch (error) {
161      let err = error as Base.BusinessError;
162      console.error(TAG, `initRemovalWantAgent getWantAgent catch failed, code: ${JSON.stringify(err.code)}, message: ${JSON.stringify(err.message)}`);
163    }
164    console.info(TAG, 'initRemovalWantAgent getWantAgent end');
165  }
166
167  async cancelAuthorization(): Promise<void> {
168    console.debug(TAG, 'cancelAuthorization begin===>');
169    try {
170      inputEventClient.permitInjection(false);
171    } catch (error) {
172      let err = error as Base.BusinessError;
173      console.error(TAG + `cancelAuthorization fail: ${JSON.stringify(err)}`);
174    }
175    console.debug(TAG, 'cancelAuthorization end===>');
176  }
177
178  createCommonEventSubscriber(): void {
179    console.debug(TAG, 'createCommonEventSubscriber begin===>');
180    if (this.commonEventSubscriber !== null) {
181      console.debug(TAG, `commonEventSubscriber has init`);
182      return;
183    }
184    let subscribeInfo: CommonEventManager.CommonEventSubscribeInfo = {
185      events: [EVENT_NAME],
186      publisherPermission: 'ohos.permission.INJECT_INPUT_EVENT',
187    };
188    CommonEventManager.createSubscriber(subscribeInfo).then((commonEventSubscriber: CommonEventManager.CommonEventSubscriber) => {
189      console.debug(TAG, 'createCommonEventSubscriber ok');
190      this.commonEventSubscriber = commonEventSubscriber;
191      this.subscribe();
192    }).catch((err: Base.BusinessError) => {
193      console.error(TAG, `createCommonEventSubscriber fail:${JSON.stringify(err)}}`);
194    });
195    console.debug(TAG, 'cancelAuthorization end');
196  }
197 
198  subscribe(): void {
199    console.debug(TAG, 'subscribe begin');
200    if (this.commonEventSubscriber === null) {
201      console.debug(TAG, 'subscribe commonEventSubscriber is null');
202      return;
203    }
204    CommonEventManager.subscribe(this.commonEventSubscriber, (err: Base.BusinessError,
205      data: CommonEventManager.CommonEventData) => {
206      if (err.code) {
207        console.error(TAG, `commonEventSubscribeCallBack err:${JSON.stringify(err)}`);
208        return;
209      }
210      console.error(TAG, `commonEventSubscribeCallBack data:${JSON.stringify(data)}`);
211      let code: number = data.code;
212      if (code !== 0) {
213        console.error(TAG, 'commonEventSubscribeCallBack !==0');
214        return;
215      }
216      if ('noticeId' in data.parameters) {
217        console.debug(TAG, `commonEventSubscribeCallBack data noticeId has value`);
218        if (data.parameters.noticeId === NOTICE_ID) {
219          console.debug(TAG, `commonEventSubscribeCallBack data event: ${data.event} close notice`);
220          injectNoticeUtil.cancelAuthorization();
221          injectNoticeUtil.cancelNotificationById(NOTICE_ID);
222          return;
223        }
224      }
225    });
226    console.debug(TAG, 'subscribe end');
227  }
228
229  onSystemLiveBttonsResponse(notificationId: number,
230    buttonOptions: notificationManager.ButtonOptions): void {
231      console.debug(TAG, 'onSystemLiveBttonsResponse:', JSON.stringify(buttonOptions), 'id:' + notificationId);
232  }
233
234  onLiveNoticeResponseCallback(notificationId: number, buttonOptions: notificationManager.ButtonOptions): void {
235    console.debug(TAG, 'onLiveNoticeResponseCallback enter');
236    if (buttonOptions == null) {
237      console.error(TAG, 'onLiveNoticeResponseCallback button callback: ' + 'buttonOptions is null');
238      return;
239    }
240    let clickButtonName = buttonOptions.buttonName;
241    let applicationContext = (GlobalContext.getContext().getObject('appcontext')) as context.ApplicationContext;
242    let resourceManager = applicationContext.resourceManager;
243    let locateButtonName = resourceManager.getStringSync($r('app.string.bn_notice_cancel'));
244    console.info(TAG, 'onLiveNoticeResponseCallback button callback: ' + clickButtonName + ', notificationId = ' + notificationId);
245    if (clickButtonName === locateButtonName) {
246      console.debug(TAG, `onLiveNoticeResponseCallback close notice`);
247      injectNoticeUtil.cancelAuthorization();
248      injectNoticeUtil.cancelNotificationById(NOTICE_ID);
249    }
250   }
251 
252   async initCapsuleIcon(): Promise<void> {
253    console.debug(TAG, `initCapsuleIcon begin`);
254    if (this.capsuleIcon != null) {
255      console.debug(TAG, `initCapsuleIcon has init`);
256      return;
257    }
258    let applicationContext = (GlobalContext.getContext().getObject('appcontext')) as context.ApplicationContext;
259    let resourceManager = applicationContext.resourceManager;
260    let defaultSize: image.Size = {
261      'height': 30,
262      'width': 30,
263    };
264    let svgData = resourceManager.getMediaContentSync($r('app.media.capsule_icon34'));
265    let opts: image.DecodingOptions = {
266      'index': 0,
267      'sampleSize': 1,
268      'rotate' :0,
269      'editable': true,
270      'desiredSize': defaultSize,
271      'desiredPixelFormat': 3,
272    };
273    let imageSource = image.createImageSource(svgData.buffer);
274    let svImage: image.PixelMap | null = null;
275    svImage = await imageSource.createPixelMap(opts);
276    this.capsuleIcon = svImage;
277    console.debug(TAG, `initCapsuleIcon end vaule: ${this.capsuleIcon}`);
278  }
279}
280
281export let injectNoticeUtil = new InjectNoticeUtil();