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.wantAgent';
20import CommonEventManager from '@ohos.commonEvent';
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 InjectNoticeStaus {
32  DEFAULT = 0,
33  OPENING = 1,
34  SERVER_CLOSE = 2,
35  MAN_CLOSE = 3,
36};
37
38class InjectNoticeUtil {
39  status: InjectNoticeStaus = InjectNoticeStaus.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    operationType: WantAgent.OperationType.SEND_COMMON_EVENT,
53    requestCode: 0,
54    wantAgentFlags: [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      slotType: 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 (err: Base.BusinessError) {
161      console.error(TAG, `initRemovalWantAgent getWantAgent catch failed, code: ${JSON.stringify(err.code)}, message: ${JSON.stringify(err.message)}`);
162    }
163    console.info(TAG, 'initRemovalWantAgent getWantAgent end');
164  }
165
166  async cancelAuthorization(): Promise<void> {
167    console.debug(TAG, 'cancelAuthorization begin===>');
168    try {
169      inputEventClient.permitInjection(false);
170    } catch (err: Base.BusinessError) {
171      console.error(TAG + `cancelAuthorization fail: ${JSON.stringify(err)}`);
172    }
173    console.debug(TAG, 'cancelAuthorization end===>');
174  }
175
176  createCommonEventSubscriber(): void {
177    console.debug(TAG, 'createCommonEventSubscriber begin===>');
178    if (this.commonEventSubscriber !== null) {
179      console.debug(TAG, `commonEventSubscriber has init`);
180      return;
181    }
182    let subscribeInfo: CommonEventManager.CommonEventSubscribeInfo = {
183      events: [EVENT_NAME],
184      publisherPermission: 'ohos.permission.INJECT_INPUT_EVENT',
185    };
186    CommonEventManager.createSubscriber(subscribeInfo).then((commonEventSubscriber: CommonEventManager.CommonEventSubscriber) => {
187      console.debug(TAG, 'createCommonEventSubscriber ok');
188      this.commonEventSubscriber = commonEventSubscriber;
189      this.subscribe();
190    }).catch((err: Base.BusinessError) => {
191      console.error(TAG, `createCommonEventSubscriber fail:${JSON.stringify(err)}}`);
192    });
193    console.debug(TAG, 'cancelAuthorization end');
194  }
195
196  subscribe(): void {
197    console.debug(TAG, 'subscribe begin');
198    if (this.commonEventSubscriber === null) {
199      console.debug(TAG, 'subscribe commonEventSubscriber is null');
200      return;
201    }
202    CommonEventManager.subscribe(this.commonEventSubscriber, (err: Base.BusinessError,
203      data: CommonEventManager.CommonEventData) => {
204      if (err.code) {
205        console.error(TAG, `commonEventSubscribeCallBack err:${JSON.stringify(err)}`);
206        return;
207      }
208      console.error(TAG, `commonEventSubscribeCallBack data:${JSON.stringify(data)}`);
209      let code: number = data.code;
210      if (code !== 0) {
211        console.error(TAG, 'commonEventSubscribeCallBack !==0');
212        return;
213      }
214      if ('noticeId' in data.parameters) {
215        console.debug(TAG, `commonEventSubscribeCallBack data noticeId has value`);
216        if (data.parameters.noticeId === NOTICE_ID) {
217          console.debug(TAG, `commonEventSubscribeCallBack data event: ${data.event} close notice`);
218          injectNoticeUtil.cancelAuthorization();
219          injectNoticeUtil.cancelNotificationById(NOTICE_ID);
220          return;
221        }
222      }
223    });
224    console.debug(TAG, 'subscribe end');
225  }
226
227  onSystemLiveBttonsResponse(notificationId: number,
228    buttonOptions: notificationManager.ButtonOptions): void {
229      console.debug(TAG, 'onSystemLiveBttonsResponse:', JSON.stringify(buttonOptions), 'id:' + notificationId);
230  }
231
232  onLiveNoticeResponseCallback(notificationId: number, buttonOptions: notificationManager.ButtonOptions): void {
233    console.debug(TAG, 'onLiveNoticeResponseCallback enter');
234    if (buttonOptions == null) {
235      console.error(TAG, 'onLiveNoticeResponseCallback button callback: ' + 'buttonOptions is null');
236      return;
237    }
238    let clickButtonName = buttonOptions.buttonName;
239    let applicationContext = (GlobalContext.getContext().getObject('appcontext')) as context.ApplicationContext;
240    let resourceManager = applicationContext.resourceManager;
241    let locateButtonName = resourceManager.getStringSync($r('app.string.bn_notice_cancel'));
242    console.info(TAG, 'onLiveNoticeResponseCallback button callback: ' + clickButtonName + ', notificationId = ' + notificationId);
243    if (clickButtonName === locateButtonName) {
244      console.debug(TAG, `onLiveNoticeResponseCallback close notice`);
245      injectNoticeUtil.cancelAuthorization();
246      injectNoticeUtil.cancelNotificationById(NOTICE_ID);
247    }
248   }
249
250   async initCapsuleIcon(): Promise<void> {
251    console.debug(TAG, `initCapsuleIcon begin`);
252    if (this.capsuleIcon != null) {
253      console.debug(TAG, `initCapsuleIcon has init`);
254      return;
255    }
256    let applicationContext = (GlobalContext.getContext().getObject('appcontext')) as context.ApplicationContext;
257    let resourceManager = applicationContext.resourceManager;
258    let defaultSize: image.Size = {
259      'height': 30,
260      'width': 30,
261    };
262    let svgData = resourceManager.getMediaContentSync($r('app.media.capsule_icon34'));
263    let opts: image.DecodingOptions = {
264      'index': 0,
265      'sampleSize': 1,
266      'rotate' :0,
267      'editable': true,
268      'desiredSize': defaultSize,
269      'desiredPixelFormat': 3,
270    };
271    let imageSource = image.createImageSource(svgData.buffer);
272    let svImage: image.PixelMap | null = null;
273    svImage = await imageSource.createPixelMap(opts);
274    this.capsuleIcon = svImage;
275    console.debug(TAG, `initCapsuleIcon end vaule: ${this.capsuleIcon}`);
276  }
277}
278
279export let injectNoticeUtil = new InjectNoticeUtil();