• 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, `updateMissedCallNotifications, ${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    HiLog.i(TAG, `cancelAllMissedNotificationAction cancel all`);
94    MissedCallNotifier.getInstance().cancelAllNotification();
95    CallLogRepository.getInstance().markMissedCallLogAsRead();
96  }
97
98  private constructor() {
99  }
100
101  private getContext() {
102    if (this.context && this.context != undefined) {
103      return this.context;
104    }
105    return globalThis.context;
106  }
107
108  private registerDataChangeObserver() {
109    if (!this.onCallLogChanged || this.onCallLogChanged == undefined) {
110      this.onCallLogChanged = () => {
111        HiLog.i(TAG, "onCallLogChanged lastMissedId:" + this.lastMissedId);
112        this.sendMissedCallNotify(this.lastMissedId);
113        this.unRegisterDataChangeObserver();
114      }
115      HiLog.i(TAG, "registerDataChangeObserver");
116      CallLogRepository.getInstance().registerDataChangeObserver(this.onCallLogChanged);
117    }
118  }
119
120  private unRegisterDataChangeObserver() {
121    if (this.onCallLogChanged && this.onCallLogChanged != undefined) {
122      this.onCallLogChanged = undefined;
123      HiLog.i(TAG, "unRegisterDataChangeObserver");
124      CallLogRepository.getInstance().unRegisterDataChangeObserver(this.onCallLogChanged);
125    }
126  }
127
128  private async getLastNotificationId() {
129    let preferences = await data_preferences.getPreferences(this.getContext(), PREFERENCE_NAME);
130    return <number> await preferences.get(LAST_MISSED_ID, -1);
131  }
132
133  private setLastNotificationId(id: number, lastId?: number): boolean {
134    if (!lastId || this.lastMissedId < id) {
135      HiLog.i(TAG, `setLastNotificationId: ${id}`);
136      this.lastMissedId = id;
137      this.unRegisterDataChangeObserver();
138      data_preferences.getPreferences(this.getContext(), PREFERENCE_NAME, (err, preferences) => {
139        if (err) {
140          HiLog.e(TAG, JSON.stringify(err));
141        } else {
142          preferences.put(LAST_MISSED_ID, id);
143          preferences.flush();
144        }
145      });
146      return true;
147    }
148    return false;
149  }
150
151  private sendMissedCallNotify(lastId?: number) {
152    CallLogRepository.getInstance().findMissedCallLogUnread((data: CallLog[]) => {
153      HiLog.i(TAG, "sendMissedCallNotify, callLog unread count:" + data.length);
154      if (data.length <= 0 || !this.setLastNotificationId(data[0].id, lastId)) {
155        HiLog.i(TAG, "sendMissedCallNotify, No new CallLog.");
156        return;
157      }
158      let phoneNums = new Set();
159      for (let callLog of data) {
160        phoneNums.add(callLog.phoneNumber);
161      }
162      this.queryContactsName(Array.from(phoneNums), (numberMap) => {
163        let missedData: Map<string, MissedCallNotifyData> = new Map();
164        for (let callLog of data) {
165          let displayName = callLog.phoneNumber;
166          if (numberMap.has(callLog.phoneNumber)) {
167            displayName = numberMap.get(callLog.phoneNumber);
168          }
169          if (!missedData.has(displayName)) {
170            missedData.set(displayName, {
171              phoneNumber: callLog.phoneNumber,
172              displayName: displayName,
173              id: callLog.id,
174              createTime: callLog.createTime,
175              count: 1,
176              ringDuration: callLog.ringDuration
177            });
178          } else {
179            missedData.get(displayName).count++;
180          }
181        }
182        MissedCallNotifier.getInstance().updateMissedCallNotifications(missedData);
183      })
184    }, lastId);
185  }
186
187  private queryContactsName(numberList, callback) {
188    if (numberList.length == 0) {
189      HiLog.w(TAG, "queryContactsName, has no number");
190      callback(new Map());
191      return;
192    }
193    ContactRepository.getInstance().queryContactDataByNumber(numberList, contacts => {
194      // Convert the result to Map, key: mobile number, value: name
195      let numberMap = this.getNumberMap(contacts);
196      callback(numberMap);
197    });
198  }
199
200  private getNumberMap(contacts) {
201    let numberMap = new Map();
202    for (let item of contacts) {
203      if (!StringUtil.isEmpty(item.displayName)) {
204        numberMap.set(item.detailInfo, item.displayName);
205      }
206    }
207    return numberMap;
208  }
209}