• 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 */
15
16import { HiLog } from '../../../../../../common/src/main/ets/util/HiLog';
17import { MissedCallNotifier, MissedCallNotifyData } from "./MissedCallNotifier"
18import { CallLogRepository } from '../repo/CallLogRepository';
19import { ContactRepository } from '../../../../../../feature/contact/src/main/ets/repo/ContactRepository';
20import { StringUtil } from '../../../../../../common/src/main/ets/util/StringUtil';
21import { CallLog } from '../entity/CallLog'
22import data_preferences from '@ohos.data.preferences';
23
24const TAG = "MissedCallService";
25const LAST_MISSED_ID: string = "Last_Missed_id"
26const PREFERENCE_NAME: string = "CONTACT_PREFERENCE";
27
28export class MissedCallService {
29  private static sInstance: MissedCallService = undefined;
30  private context: Context = undefined;
31  private onCallLogChanged = undefined;
32  private lastMissedId = -1;
33
34  /**
35   * getInstance for MissedCallService
36   */
37  public static getInstance() {
38    if (!MissedCallService.sInstance || MissedCallService.sInstance == undefined) {
39      MissedCallService.sInstance = new MissedCallService();
40    }
41    return MissedCallService.sInstance;
42  }
43
44  /**
45   * init
46   *
47   * @param ctx context needed init
48   */
49  public init(ctx: Context) {
50    this.context = ctx;
51    MissedCallNotifier.getInstance().init(ctx);
52    CallLogRepository.getInstance().init(ctx);
53    ContactRepository.getInstance().init(ctx);
54  }
55
56  /**
57   * updateAllMissedCallNotifications
58   */
59  public async updateAllMissedCallNotifications() {
60    HiLog.i(TAG, "updateMissedCallNotifications");
61    MissedCallNotifier.getInstance().cancelAllNotification();
62    this.sendMissedCallNotify();
63  }
64
65  /**
66   * updateMissedCallNotifications
67   */
68  public async updateMissedCallNotifications() {
69    if (this.lastMissedId == -1) {
70      this.lastMissedId = await this.getLastNotificationId();
71    }
72    this.registerDataChangeObserver();
73    HiLog.i(TAG, "updateMissedCallNotifications, lastMissedId:" + this.lastMissedId);
74    this.sendMissedCallNotify(this.lastMissedId);
75  }
76
77
78  /**
79   * cancelMissedNotificationAction
80   *
81   * @param data MissedCallNotifyData need cancel notify
82   */
83  public async cancelMissedNotificationAction(data: MissedCallNotifyData) {
84    HiLog.i(TAG, `cancelMissedNotificationAction, ${JSON.stringify(data)}`);
85    MissedCallNotifier.getInstance().cancelNotificationById(data.id, data.count);
86    CallLogRepository.getInstance().markMissedCallLogAsRead(data.phoneNumber);
87  }
88
89  /**
90   * cancelAllMissedNotificationAction
91   */
92  public async cancelAllMissedNotificationAction() {
93    let unreadMissed = await MissedCallNotifier.getInstance().getMissedBadgeNumber()
94    if (unreadMissed > 0) {
95      HiLog.i(TAG, `cancelAllMissedNotificationAction cancel all`);
96      MissedCallNotifier.getInstance().cancelAllNotification();
97      CallLogRepository.getInstance().markMissedCallLogAsRead();
98    }
99  }
100
101  private constructor() {
102  }
103
104  private getContext() {
105    if (this.context && this.context != undefined) {
106      return this.context;
107    }
108    return globalThis.context;
109  }
110
111  private registerDataChangeObserver() {
112    if (!this.onCallLogChanged || this.onCallLogChanged == undefined) {
113      this.onCallLogChanged = () => {
114        HiLog.i(TAG, "onCallLogChanged lastMissedId:" + this.lastMissedId);
115        this.sendMissedCallNotify(this.lastMissedId);
116        this.unRegisterDataChangeObserver();
117      }
118      HiLog.i(TAG, "registerDataChangeObserver");
119      CallLogRepository.getInstance().registerDataChangeObserver(this.onCallLogChanged);
120    }
121  }
122
123  private unRegisterDataChangeObserver() {
124    if (this.onCallLogChanged && this.onCallLogChanged != undefined) {
125      this.onCallLogChanged = undefined;
126      HiLog.i(TAG, "unRegisterDataChangeObserver");
127      CallLogRepository.getInstance().unRegisterDataChangeObserver(this.onCallLogChanged);
128    }
129  }
130
131  private async getLastNotificationId() {
132    let preferences = await data_preferences.getPreferences(this.getContext(), PREFERENCE_NAME);
133    return <number> await preferences.get(LAST_MISSED_ID, -1);
134  }
135
136  private setLastNotificationId(id: number, lastId?: number): boolean {
137    if (!lastId || this.lastMissedId < id) {
138      HiLog.i(TAG, `setLastNotificationId: ${id}`);
139      this.lastMissedId = id;
140      this.unRegisterDataChangeObserver();
141      data_preferences.getPreferences(this.getContext(), PREFERENCE_NAME, (err, preferences) => {
142        if (err) {
143          HiLog.e(TAG, JSON.stringify(err));
144        } else {
145          preferences.put(LAST_MISSED_ID, id);
146          preferences.flush();
147        }
148      });
149      return true;
150    }
151    return false;
152  }
153
154  private sendMissedCallNotify(lastId?: number) {
155    CallLogRepository.getInstance().findMissedCallLogUnread((data: CallLog[]) => {
156      HiLog.i(TAG, "sendMissedCallNotify, callLog unread count:" + data.length);
157      if (data.length <= 0 || !this.setLastNotificationId(data[0].id, lastId)) {
158        HiLog.i(TAG, "sendMissedCallNotify, No new CallLog.");
159        return;
160      }
161      let phoneNums = new Set();
162      for (let callLog of data) {
163        phoneNums.add(callLog.phoneNumber);
164      }
165      this.queryContactsName(Array.from(phoneNums), (numberMap) => {
166        let missedData: Map<string, MissedCallNotifyData> = new Map();
167        for (let callLog of data) {
168          let displayName = callLog.phoneNumber;
169          if (numberMap.has(callLog.phoneNumber)) {
170            displayName = numberMap.get(callLog.phoneNumber);
171          }
172          if (!missedData.has(displayName)) {
173            missedData.set(displayName, {
174              phoneNumber: callLog.phoneNumber,
175              displayName: displayName,
176              id: callLog.id,
177              createTime: callLog.createTime,
178              count: 1,
179              ringDuration: callLog.ringDuration
180            });
181          } else {
182            missedData.get(displayName).count++;
183          }
184        }
185        MissedCallNotifier.getInstance().updateMissedCallNotifications(missedData);
186      })
187    }, lastId);
188  }
189
190  private queryContactsName(numberList, callback) {
191    if (numberList.length == 0) {
192      HiLog.w(TAG, "queryContactsName, has no number");
193      callback(new Map());
194      return;
195    }
196    ContactRepository.getInstance().queryContactDataByNumber(numberList, contacts => {
197      // Convert the result to Map, key: mobile number, value: name
198      let numberMap = this.getNumberMap(contacts);
199      callback(numberMap);
200    });
201  }
202
203  private getNumberMap(contacts) {
204    let numberMap = new Map();
205    for (let item of contacts) {
206      if (!StringUtil.isEmpty(item.displayName)) {
207        numberMap.set(item.detailInfo, item.displayName);
208      }
209    }
210    return numberMap;
211  }
212}