18779efd5Sopenharmony_ci/**
28779efd5Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
38779efd5Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48779efd5Sopenharmony_ci * you may not use this file except in compliance with the License.
58779efd5Sopenharmony_ci * You may obtain a copy of the License at
68779efd5Sopenharmony_ci *
78779efd5Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88779efd5Sopenharmony_ci *
98779efd5Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108779efd5Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118779efd5Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128779efd5Sopenharmony_ci * See the License for the specific language governing permissions and
138779efd5Sopenharmony_ci * limitations under the License.
148779efd5Sopenharmony_ci */
158779efd5Sopenharmony_ci
168779efd5Sopenharmony_ciimport { HiLog, sharedPreferencesUtils } from 'common';
178779efd5Sopenharmony_ciimport { MissedCallNotifier, MissedCallNotifyData } from './MissedCallNotifier'
188779efd5Sopenharmony_ciimport { CallLogRepository } from '../repo/CallLogRepository';
198779efd5Sopenharmony_ciimport { ContactRepository } from '../../../../../../feature/contact/src/main/ets/repo/ContactRepository';
208779efd5Sopenharmony_ciimport { StringUtil } from '../../../../../../common/src/main/ets/util/StringUtil';
218779efd5Sopenharmony_ciimport { CallLog } from '../entity/CallLog'
228779efd5Sopenharmony_ci
238779efd5Sopenharmony_ciconst TAG = 'MissedCallService';
248779efd5Sopenharmony_ciconst LAST_MISSED_ID: string = 'Last_Missed_id'
258779efd5Sopenharmony_ciconst PREFERENCE_NAME: string = 'CONTACT_PREFERENCE';
268779efd5Sopenharmony_ci
278779efd5Sopenharmony_ciexport class MissedCallService {
288779efd5Sopenharmony_ci  private static sInstance: MissedCallService = undefined;
298779efd5Sopenharmony_ci  private context: Context = undefined;
308779efd5Sopenharmony_ci  private lastMissedId = -1;
318779efd5Sopenharmony_ci  private onCallLogChanged = () => {
328779efd5Sopenharmony_ci    if (this.lastMissedId != -1) {
338779efd5Sopenharmony_ci      HiLog.i(TAG, 'onCallLogChanged lastMissedId:' + this.lastMissedId);
348779efd5Sopenharmony_ci      this.sendMissedCallNotify(this.lastMissedId);
358779efd5Sopenharmony_ci    }
368779efd5Sopenharmony_ci    this.unRegisterDataChangeObserver();
378779efd5Sopenharmony_ci  }
388779efd5Sopenharmony_ci
398779efd5Sopenharmony_ci  /**
408779efd5Sopenharmony_ci   * getInstance for MissedCallService
418779efd5Sopenharmony_ci   */
428779efd5Sopenharmony_ci  public static getInstance() {
438779efd5Sopenharmony_ci    if (!MissedCallService.sInstance || MissedCallService.sInstance == undefined) {
448779efd5Sopenharmony_ci      MissedCallService.sInstance = new MissedCallService();
458779efd5Sopenharmony_ci    }
468779efd5Sopenharmony_ci    return MissedCallService.sInstance;
478779efd5Sopenharmony_ci  }
488779efd5Sopenharmony_ci
498779efd5Sopenharmony_ci  /**
508779efd5Sopenharmony_ci   * init
518779efd5Sopenharmony_ci   *
528779efd5Sopenharmony_ci   * @param ctx context needed init
538779efd5Sopenharmony_ci   */
548779efd5Sopenharmony_ci  public init(ctx: Context) {
558779efd5Sopenharmony_ci    this.context = ctx;
568779efd5Sopenharmony_ci    sharedPreferencesUtils.init(ctx);
578779efd5Sopenharmony_ci    MissedCallNotifier.getInstance().init(ctx);
588779efd5Sopenharmony_ci    CallLogRepository.getInstance().init(ctx);
598779efd5Sopenharmony_ci    ContactRepository.getInstance().init(ctx);
608779efd5Sopenharmony_ci  }
618779efd5Sopenharmony_ci
628779efd5Sopenharmony_ci  /**
638779efd5Sopenharmony_ci   * updateAllMissedCallNotifications
648779efd5Sopenharmony_ci   */
658779efd5Sopenharmony_ci  public async updateAllMissedCallNotifications() {
668779efd5Sopenharmony_ci    HiLog.i(TAG, 'updateMissedCallNotifications');
678779efd5Sopenharmony_ci    MissedCallNotifier.getInstance().cancelAllNotification();
688779efd5Sopenharmony_ci    this.sendMissedCallNotify();
698779efd5Sopenharmony_ci  }
708779efd5Sopenharmony_ci
718779efd5Sopenharmony_ci  /**
728779efd5Sopenharmony_ci   * updateMissedCallNotifications
738779efd5Sopenharmony_ci   */
748779efd5Sopenharmony_ci  public async updateMissedCallNotifications() {
758779efd5Sopenharmony_ci    if (this.lastMissedId == -1) {
768779efd5Sopenharmony_ci      this.lastMissedId = await this.getLastNotificationId();
778779efd5Sopenharmony_ci    }
788779efd5Sopenharmony_ci    this.registerDataChangeObserver();
798779efd5Sopenharmony_ci    HiLog.i(TAG, 'updateMissedCallNotifications, lastMissedId:' + this.lastMissedId);
808779efd5Sopenharmony_ci    this.sendMissedCallNotify(this.lastMissedId);
818779efd5Sopenharmony_ci  }
828779efd5Sopenharmony_ci
838779efd5Sopenharmony_ci  /**
848779efd5Sopenharmony_ci   *
858779efd5Sopenharmony_ci   * Unread missed call notification
868779efd5Sopenharmony_ci   */
878779efd5Sopenharmony_ci  public async unreadCallNotification(map:Map<string,string>) {
888779efd5Sopenharmony_ci    MissedCallNotifier.getInstance().sendUnreadCallNotification(map);
898779efd5Sopenharmony_ci  }
908779efd5Sopenharmony_ci
918779efd5Sopenharmony_ci  /**
928779efd5Sopenharmony_ci   * cancelMissedNotificationAction
938779efd5Sopenharmony_ci   *
948779efd5Sopenharmony_ci   * @param data MissedCallNotifyData need cancel notify
958779efd5Sopenharmony_ci   */
968779efd5Sopenharmony_ci  public async cancelMissedNotificationAction(data: MissedCallNotifyData) {
978779efd5Sopenharmony_ci    HiLog.i(TAG, `cancelMissedNotificationAction, ${JSON.stringify(data)}`);
988779efd5Sopenharmony_ci    MissedCallNotifier.getInstance().cancelNotificationById(data.id, data.count);
998779efd5Sopenharmony_ci    CallLogRepository.getInstance().markMissedCallLogAsRead(data.phoneNumber);
1008779efd5Sopenharmony_ci  }
1018779efd5Sopenharmony_ci
1028779efd5Sopenharmony_ci  /**
1038779efd5Sopenharmony_ci   * cancelAllMissedNotificationAction
1048779efd5Sopenharmony_ci   */
1058779efd5Sopenharmony_ci  public async cancelAllMissedNotificationAction() {
1068779efd5Sopenharmony_ci    let unreadMissed = await MissedCallNotifier.getInstance().getMissedBadgeNumber()
1078779efd5Sopenharmony_ci    if (unreadMissed > 0) {
1088779efd5Sopenharmony_ci      HiLog.i(TAG, `cancelAllMissedNotificationAction cancel all`);
1098779efd5Sopenharmony_ci      MissedCallNotifier.getInstance().cancelAllNotification();
1108779efd5Sopenharmony_ci      CallLogRepository.getInstance().markMissedCallLogAsRead();
1118779efd5Sopenharmony_ci    }
1128779efd5Sopenharmony_ci  }
1138779efd5Sopenharmony_ci
1148779efd5Sopenharmony_ci  private constructor() {
1158779efd5Sopenharmony_ci  }
1168779efd5Sopenharmony_ci
1178779efd5Sopenharmony_ci  private getContext() {
1188779efd5Sopenharmony_ci    if (this.context && this.context != undefined) {
1198779efd5Sopenharmony_ci      return this.context;
1208779efd5Sopenharmony_ci    }
1218779efd5Sopenharmony_ci    return globalThis.context;
1228779efd5Sopenharmony_ci  }
1238779efd5Sopenharmony_ci
1248779efd5Sopenharmony_ci  private registerDataChangeObserver() {
1258779efd5Sopenharmony_ci    HiLog.i(TAG, 'registerDataChangeObserver');
1268779efd5Sopenharmony_ci    CallLogRepository.getInstance().registerDataChangeObserver(this.onCallLogChanged);
1278779efd5Sopenharmony_ci  }
1288779efd5Sopenharmony_ci
1298779efd5Sopenharmony_ci  private unRegisterDataChangeObserver() {
1308779efd5Sopenharmony_ci    HiLog.i(TAG, 'unRegisterDataChangeObserver');
1318779efd5Sopenharmony_ci    CallLogRepository.getInstance().unRegisterDataChangeObserver(this.onCallLogChanged);
1328779efd5Sopenharmony_ci  }
1338779efd5Sopenharmony_ci
1348779efd5Sopenharmony_ci  private async getLastNotificationId() {
1358779efd5Sopenharmony_ci    return <number> await sharedPreferencesUtils.getFromPreferences(LAST_MISSED_ID, -1)
1368779efd5Sopenharmony_ci  }
1378779efd5Sopenharmony_ci
1388779efd5Sopenharmony_ci  private setLastNotificationId(id: number, lastId?: number): boolean {
1398779efd5Sopenharmony_ci    if (!lastId || this.lastMissedId < id) {
1408779efd5Sopenharmony_ci      HiLog.i(TAG, `setLastNotificationId: ${id}`);
1418779efd5Sopenharmony_ci      this.lastMissedId = id;
1428779efd5Sopenharmony_ci      this.unRegisterDataChangeObserver();
1438779efd5Sopenharmony_ci      sharedPreferencesUtils.saveToPreferences(LAST_MISSED_ID, id)
1448779efd5Sopenharmony_ci      return true;
1458779efd5Sopenharmony_ci    }
1468779efd5Sopenharmony_ci    return false;
1478779efd5Sopenharmony_ci  }
1488779efd5Sopenharmony_ci
1498779efd5Sopenharmony_ci  private sendMissedCallNotify(lastId?: number) {
1508779efd5Sopenharmony_ci    CallLogRepository.getInstance().findMissedCallLogUnread((data: CallLog[]) => {
1518779efd5Sopenharmony_ci      HiLog.i(TAG, 'sendMissedCallNotify, callLog unread count:' + data.length);
1528779efd5Sopenharmony_ci      if (data.length <= 0 || !this.setLastNotificationId(data[0].id, lastId)) {
1538779efd5Sopenharmony_ci        HiLog.i(TAG, 'sendMissedCallNotify, No new CallLog.');
1548779efd5Sopenharmony_ci        return;
1558779efd5Sopenharmony_ci      }
1568779efd5Sopenharmony_ci      let phoneNums = new Set();
1578779efd5Sopenharmony_ci      for (let callLog of data) {
1588779efd5Sopenharmony_ci        phoneNums.add(callLog.phoneNumber);
1598779efd5Sopenharmony_ci      }
1608779efd5Sopenharmony_ci      this.queryContactsName(Array.from(phoneNums), (numberMap) => {
1618779efd5Sopenharmony_ci        let missedData: Map<string, MissedCallNotifyData> = new Map();
1628779efd5Sopenharmony_ci        for (let callLog of data) {
1638779efd5Sopenharmony_ci          let displayName = callLog.phoneNumber;
1648779efd5Sopenharmony_ci          if (numberMap.has(callLog.phoneNumber)) {
1658779efd5Sopenharmony_ci            displayName = numberMap.get(callLog.phoneNumber);
1668779efd5Sopenharmony_ci          }
1678779efd5Sopenharmony_ci          if (!missedData.has(displayName)) {
1688779efd5Sopenharmony_ci            missedData.set(displayName, {
1698779efd5Sopenharmony_ci              phoneNumber: callLog.phoneNumber,
1708779efd5Sopenharmony_ci              displayName: displayName,
1718779efd5Sopenharmony_ci              id: callLog.id,
1728779efd5Sopenharmony_ci              createTime: callLog.createTime,
1738779efd5Sopenharmony_ci              count: 1,
1748779efd5Sopenharmony_ci              ringDuration: callLog.ringDuration
1758779efd5Sopenharmony_ci            });
1768779efd5Sopenharmony_ci          } else {
1778779efd5Sopenharmony_ci            missedData.get(displayName).count++;
1788779efd5Sopenharmony_ci          }
1798779efd5Sopenharmony_ci        }
1808779efd5Sopenharmony_ci        MissedCallNotifier.getInstance().updateMissedCallNotifications(missedData);
1818779efd5Sopenharmony_ci      })
1828779efd5Sopenharmony_ci    }, lastId);
1838779efd5Sopenharmony_ci  }
1848779efd5Sopenharmony_ci
1858779efd5Sopenharmony_ci  private queryContactsName(numberList, callback) {
1868779efd5Sopenharmony_ci    if (numberList.length == 0) {
1878779efd5Sopenharmony_ci      HiLog.w(TAG, 'queryContactsName, has no number');
1888779efd5Sopenharmony_ci      callback(new Map());
1898779efd5Sopenharmony_ci      return;
1908779efd5Sopenharmony_ci    }
1918779efd5Sopenharmony_ci    ContactRepository.getInstance().queryContactDataByNumber(numberList, contacts => {
1928779efd5Sopenharmony_ci      // Convert the result to Map, key: mobile number, value: name
1938779efd5Sopenharmony_ci      let numberMap = this.getNumberMap(contacts);
1948779efd5Sopenharmony_ci      callback(numberMap);
1958779efd5Sopenharmony_ci    });
1968779efd5Sopenharmony_ci  }
1978779efd5Sopenharmony_ci
1988779efd5Sopenharmony_ci  private getNumberMap(contacts) {
1998779efd5Sopenharmony_ci    let numberMap = new Map();
2008779efd5Sopenharmony_ci    for (let item of contacts) {
2018779efd5Sopenharmony_ci      if (!StringUtil.isEmpty(item.displayName)) {
2028779efd5Sopenharmony_ci        numberMap.set(item.detailInfo, item.displayName);
2038779efd5Sopenharmony_ci      }
2048779efd5Sopenharmony_ci    }
2058779efd5Sopenharmony_ci    return numberMap;
2068779efd5Sopenharmony_ci  }
2078779efd5Sopenharmony_ci}