• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Notification from '@ohos.notificationManager'
16import NotificationManager from '@ohos.notificationManager'
17import WantAgent from '@ohos.app.ability.wantAgent';
18import { HiLog, sharedPreferencesUtils } from '../../../../../../common';
19import notificationSubscribe from '@ohos.notificationSubscribe';
20import call from '@ohos.telephony.call';
21import { NotificationSubscriber } from 'notification/notificationSubscriber';
22
23const TAG = 'MissedCallNotifier';
24
25const BUNDLE_NAME: string = 'com.ohos.contacts';
26const ABILITY_NAME: string = 'com.ohos.contacts.MainAbility';
27const GROUP_NAME: string = 'MissedCall'
28const KEY_MISSED_BADGE_NUM = 'missed_badge_number'
29const KEY_ID = 'unread_call_notification_id'
30const KEY_DISPLAY_NAME = 'unread_call_notification_displayName'
31const KEY_COUNT = 'unread_call_notification_count'
32const KEY_CREATE_TIME = 'unread_call_notification_create_time'
33const KEY_RING_DURATION = 'unread_call_notification_ring_duration'
34const actionBtnMaps =
35  {
36    'notification.event.dialBack': $r('app.string.dial_back'),
37    'notification.event.message': $r('app.string.message'),
38  };
39
40export class MissedCallNotifyData {
41  id?: number;
42  displayName?: string;
43  readonly phoneNumber: string;
44  count?: number;
45  createTime?: number;
46  ringDuration?: number;
47}
48
49export class MissedCallNotifier {
50  private label: string;
51  private context: Context;
52  private static sInstance: MissedCallNotifier = undefined;
53  private missedBadgeNumber: number = -1;
54  private UnReadMissedCallData: MissedCallNotifyData;
55
56  /**
57   * getInstance for MissedCallNotifier
58   */
59  public static getInstance() {
60    if (!MissedCallNotifier.sInstance || MissedCallNotifier.sInstance == undefined) {
61      MissedCallNotifier.sInstance = new MissedCallNotifier();
62    }
63    return MissedCallNotifier.sInstance;
64  }
65
66  /**
67   * init
68   *
69   * @param ctx context needed init
70   */
71  public init(ctx: Context) {
72    this.context = ctx;
73    if (!this.label) {
74      this.label = this.getContext()?.resourceManager.getStringSync($r('app.string.missed_call'));
75    }
76    sharedPreferencesUtils.init(this.getContext());
77  }
78
79  /**
80   * update Missed Call Notification
81   *
82   * @param missedData missedCallData - missed call data for notification
83   */
84  public async updateMissedCallNotifications(missedData: Map<string, MissedCallNotifyData>) {
85    let notifyData = await this.getMissedCallNotifyDatas();
86    HiLog.i(TAG, `updateMissedCallNotifications notifyData:${notifyData.length} missedData: ${missedData.size}`)
87    let badgeNumber: number = 0;
88    if (notifyData.length > 0) {
89      for (let notify of notifyData) {
90        let key: string = notify.displayName;
91        if (missedData.has(key)) {
92          let missed = missedData.get(key)
93          missedData.delete(key)
94          if (missed.id != notify.id) {
95            notify.createTime = missed.createTime;
96            notify.ringDuration = missed.ringDuration;
97            notify.count += missed.count;
98            this.sendNotification(notify);
99          }
100        }
101        badgeNumber += notify.count;
102      }
103    }
104    for (let notify of missedData.values()) {
105      await this.sendNotification(notify);
106      badgeNumber += notify.count;
107    }
108    if (badgeNumber > 0) {
109      this.setMissedBadgeNumber(badgeNumber);
110    }
111  }
112
113  /**
114   * cancel Missed Call Notification
115   */
116  public cancelAllNotification() {
117    HiLog.i(TAG, 'cancelNotification,cancel all')
118    this.setMissedBadgeNumber(0);
119    NotificationManager.cancelGroup(GROUP_NAME).catch(error => {
120      HiLog.e(TAG, `cancelNotification,err ${JSON.stringify(error)}}`)
121    });
122  }
123
124  /**
125   * get Missed Call BadgeNumber
126   */
127  public async getMissedBadgeNumber() {
128    if (this.missedBadgeNumber == -1) {
129      this.missedBadgeNumber = <number> await sharedPreferencesUtils.getFromPreferences(KEY_MISSED_BADGE_NUM, -1);
130    }
131    return this.missedBadgeNumber;
132  }
133
134  /**
135   * cancel Missed Call Notification By NotificationId
136   *
137   * @param id Notification Id
138   */
139  public async cancelNotificationById(id: number, count: number) {
140    HiLog.i(TAG, 'cancelNotificationById:' + id)
141    NotificationManager.cancel(id, this.label).catch(error => {
142      HiLog.e(TAG, `cancelNotificationById,err ${JSON.stringify(error)}}`)
143    });
144    let badgeNumber = await this.getMissedBadgeNumber();
145    badgeNumber -= count;
146    if (badgeNumber >= 0) {
147      this.setMissedBadgeNumber(badgeNumber);
148    }
149  }
150
151  private constructor() {
152  }
153
154  private getContext() {
155    if (this.context && this.context != undefined) {
156      return this.context;
157    }
158    return globalThis.context;
159  }
160
161  private async getMissedCallNotifyDatas() {
162    HiLog.i(TAG, `getMissedCallNotifyDatas in`)
163    let result: Array<MissedCallNotifyData> = [];
164    const notifications: Array<NotificationManager.NotificationRequest> =
165      await NotificationManager.getAllActiveNotifications()
166    for (let notify of notifications) {
167      if (notify.groupName == GROUP_NAME && notify.extraInfo) {
168        result.push(<MissedCallNotifyData> notify.extraInfo);
169      }
170    }
171    HiLog.i(TAG, `getMissedCallNotifyDatas result: ${result.length}`)
172    return result;
173  }
174
175  private async sendNotification(missedCallData: MissedCallNotifyData) {
176    const {id, displayName, count, createTime, ringDuration} = missedCallData;
177    sharedPreferencesUtils.saveToPreferences(KEY_ID, id);
178    sharedPreferencesUtils.saveToPreferences(KEY_DISPLAY_NAME, displayName);
179    sharedPreferencesUtils.saveToPreferences(KEY_COUNT, count);
180    sharedPreferencesUtils.saveToPreferences(KEY_CREATE_TIME, createTime);
181    sharedPreferencesUtils.saveToPreferences(KEY_RING_DURATION, ringDuration)
182    HiLog.i(TAG, `sendNotification in id:${id}, count:${count}, createTime:${createTime}`)
183    let str_text = this.getContext()?.resourceManager.getStringSync($r('app.string.contacts_ring_times')) +
184    ringDuration + this.getContext()?.resourceManager.getStringSync($r('app.string.contacts_time_sec'));
185    if (ringDuration === 0) {
186      str_text = $r('app.string.missed_call')
187    }
188    const notificationRequest: NotificationManager.NotificationRequest = {
189      content: {
190        contentType: Notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
191        normal: {
192          title: count > 1 ? `${displayName} (${count})` : displayName,
193          text: str_text,
194          additionalText: missedCallData.phoneNumber
195        },
196      },
197      id: id,
198      label: this.label,
199      groupName: GROUP_NAME,
200      slotType: Notification.SlotType.SOCIAL_COMMUNICATION,
201      deliveryTime: new Date().getTime(),
202      extraInfo: missedCallData
203    }
204
205    let wantAgentObj = await this.getWantAgent(missedCallData, 'notification.event.click');
206    notificationRequest.wantAgent = wantAgentObj;
207    notificationRequest.actionButtons = [];
208    for (const key of Object.keys(actionBtnMaps)) {
209      const wantAgent = await this.getWantAgent(missedCallData, key);
210      const title = this.getContext()?.resourceManager.getStringSync(actionBtnMaps[key]);
211      notificationRequest.actionButtons.push({
212        title: title,
213        wantAgent: wantAgent
214      });
215    }
216    notificationRequest.removalWantAgent = await this.createWantAgentForCommonEvent(missedCallData, 'notification.event.cancel');
217    NotificationManager.publish(notificationRequest).then(() => {
218      HiLog.i(TAG, '===>publish promise success req.id : ' + notificationRequest.id);
219    }).catch((err) => {
220      HiLog.e(TAG, '===>publish promise failed because ' + JSON.stringify(err));
221    });
222    HiLog.i(TAG, 'sendNotification end')
223  }
224
225  /**
226   * send Unread Call  Notification
227   */
228  public async sendUnreadCallNotification(map: Map<string, string>) {
229    let id: number = <number> await sharedPreferencesUtils.getFromPreferences(KEY_ID, -1);
230    let displayName: string = <string> await  sharedPreferencesUtils.getFromPreferences(KEY_DISPLAY_NAME, '');
231    let count: number = <number> await  sharedPreferencesUtils.getFromPreferences(KEY_COUNT, -1);
232    let createTime: number = <number> await  sharedPreferencesUtils.getFromPreferences(KEY_CREATE_TIME, -1);
233    let ringDuration: number = <number> await  sharedPreferencesUtils.getFromPreferences(KEY_RING_DURATION, -1);
234    let missCallData = map.get('missedPhoneJson')
235    const parameters = JSON.parse(JSON.stringify(missCallData));
236    for (let i = 0; i < parameters.phoneNumberList.length; i++) {
237      const missedPhoneNumber = parameters.phoneNumberList[i]
238      const missedNum = parameters.countList[i]
239      if (i === (parameters.phoneNumberList.length -1)) {
240        this.UnReadMissedCallData = {
241          phoneNumber: missedPhoneNumber,
242          displayName: missedPhoneNumber,
243          id: i,
244          createTime: createTime,
245          count: count,
246          ringDuration: ringDuration
247        }
248      } else {
249        this.UnReadMissedCallData = {
250          phoneNumber: missedPhoneNumber,
251          displayName: missedPhoneNumber,
252          id: i,
253          createTime: createTime,
254          count: count,
255          ringDuration: 0
256        }
257      }
258      this.sendNotification(this.UnReadMissedCallData);
259    }
260  }
261
262  private setMissedBadgeNumber(newBadgeNum: number) {
263    HiLog.i(TAG, 'setMissedBadgeNumber :' + newBadgeNum);
264    this.missedBadgeNumber = newBadgeNum;
265    NotificationManager.setBadgeNumber(newBadgeNum);
266    sharedPreferencesUtils.saveToPreferences(KEY_MISSED_BADGE_NUM, newBadgeNum);
267  }
268
269  /**
270   * create wantAgent for common event
271   *
272   * @param mAction
273   * @return return the created WantAgent object.
274   */
275  private async createWantAgentForCommonEvent(missedCallData, action?: string) {
276    return await WantAgent.getWantAgent({
277      wants: [{ action: 'contact.event.CANCEL_MISSED', parameters: {
278        action: action,
279        missedCallData: missedCallData
280      }, }],
281      actionType: WantAgent.OperationType.SEND_COMMON_EVENT,
282      requestCode: 0
283    })
284  }
285
286  private getWantAgent(missedCallData: MissedCallNotifyData, action: string) {
287    let data: any = {}
288    data.action = action,
289    data.missedCallData = missedCallData
290    if (action == 'notification.event.dialBack') {
291      HiLog.i(TAG, 'getWantAgent add page_flag_edit_before_calling')
292      return this.createWantAgentForCommonEvent(missedCallData, action);
293    }
294    return WantAgent.getWantAgent({
295      wants: [{
296                deviceId: '',
297                bundleName: BUNDLE_NAME,
298                abilityName: ABILITY_NAME,
299                uri: '',
300                type: 'phone',
301                parameters: data,
302                entities: []
303              }],
304      requestCode: 0,
305      actionType: WantAgent.OperationType.START_ABILITY,
306      wantAgentFlags: [WantAgent.WantAgentFlags.ONE_TIME_FLAG]
307    });
308  }
309}