• 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 dataShare from '@ohos.data.dataShare';
17import dataSharePredicates from '@ohos.data.dataSharePredicates';
18import ICallLogRepository from './ICallLogRepository';
19import { CallLog } from '../entity/CallLog';
20import CallLogBuilder from '../entity/CallLogBuilder';
21import Calls from '../contract/Calls';
22import { RawContacts } from '../../../../../contact/src/main/ets/contract/RawContacts';
23import CallLogDelta from './CallLogDelta';
24import { StringUtil } from '../../../../../../common/src/main/ets/util/StringUtil';
25import { HiLog } from '../../../../../../common/src/main/ets/util/HiLog';
26import { ArrayUtil } from '../../../../../../common/src/main/ets/util/ArrayUtil';
27
28const TAG = 'CallLogRepository';
29
30/**
31 * Account type service, which is used to display account characteristics such as account type holding contact details.
32 */
33export class CallLogRepository implements ICallLogRepository {
34  private static instance: CallLogRepository;
35  private dataShareHelper;
36  private context: Context
37
38  private constructor() {
39  }
40
41  /*
42   * init if Call From serviceAbility globalThis.context is Null
43   *@param ctx Context used for dataShare
44   */
45  init(ctx: Context) {
46    this.context = ctx;
47  }
48
49  public static getInstance(): CallLogRepository {
50    if (!CallLogRepository.instance) {
51      CallLogRepository.instance = new CallLogRepository()
52    }
53    return CallLogRepository.instance
54  }
55
56  private async getDataAbilityHelper() {
57    if (this.dataShareHelper == undefined) {
58      this.dataShareHelper = await dataShare.createDataShareHelper(this.context ? this.context : globalThis.context,
59          Calls.CONTENT_URI);
60    }
61    return this.dataShareHelper;
62  }
63
64  saveOne(callLog: CallLog, callback) {
65    if (callLog.id <= 0) {
66      this.getDataAbilityHelper().then((dataAbilityHelper) => {
67        let callLogDelta = new CallLogDelta(callLog);
68        dataAbilityHelper.insert(Calls.CALL_LOG_URI, callLogDelta.createValuesBucket()).then(data => {
69          callback(data);
70        }).catch(error => {
71          HiLog.w(TAG, 'saveOne error:%s', JSON.stringify(error.message));
72          callback();
73        });
74      }).catch(error => {
75        HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
76        callback();
77      });
78    } else {
79      callback();
80    }
81  }
82
83  clear(callback) {
84    this.getDataAbilityHelper().then((dataAbilityHelper) => {
85      let condition = new dataSharePredicates.DataSharePredicates();
86      dataAbilityHelper.delete(Calls.CALL_LOG_URI, condition).then(data => {
87        callback(data);
88      }).catch(error => {
89        HiLog.w(TAG, 'clear error:%s', JSON.stringify(error.message));
90        callback();
91      });
92    }).catch(error => {
93      HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
94      callback();
95    });
96  }
97
98  deleteById(id: number) {
99    return false;
100  }
101
102  deleteByIdIn(ids: number[], callback) {
103    if (ArrayUtil.isEmpty(ids)) {
104      callback();
105      return;
106    }
107    this.getDataAbilityHelper().then((dataAbilityHelper) => {
108      let condition = new dataSharePredicates.DataSharePredicates();
109      condition.in(Calls.ID, ids);
110      dataAbilityHelper.delete(Calls.CALL_LOG_URI, condition).then(data => {
111        callback(data);
112      }).catch(error => {
113        HiLog.w(TAG, 'deleteByIdIn error:%s', JSON.stringify(error.message));
114        callback();
115      });
116    }).catch(error => {
117      HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
118      callback();
119    });
120  }
121
122  deleteByNumber(number: string) {
123    return false;
124  }
125
126  deleteByLookupUri(number: string) {
127    return false;
128  }
129
130  readByNumber(number: string) {
131    return false;
132  }
133
134  readById(id: number) {
135    return false;
136  }
137
138  findAll(favorite: number, actionData, callback) {
139    this.getDataAbilityHelper().then((dataAbilityHelper) => {
140      let condition = new dataSharePredicates.DataSharePredicates();
141      let offset = actionData.page < 3 ? (actionData.page - 1) * 50 : (actionData.page - 2) * 500 + 50;
142      if (0 === favorite) {
143        condition.equalTo(RawContacts.FAVORITE, favorite)
144      }
145      condition.limit(actionData.limit, offset);
146      condition.orderByDesc(Calls.CREATE_TIME);
147      dataAbilityHelper.query(Calls.CALL_LOG_URI, condition, null).then(resultSet => {
148        let rst: CallLog[] = [];
149        if (resultSet.rowCount === 0) {
150          resultSet.close();
151          callback(rst);
152        } else {
153          resultSet.goToFirstRow();
154          do {
155            let builder = CallLogBuilder.fromResultSet(resultSet);
156            if (builder.id > 0) {
157              rst.push(new CallLog(builder));
158            }
159          } while (resultSet.goToNextRow());
160          resultSet.close();
161          callback(rst);
162        }
163      }).catch(error => {
164        HiLog.w(TAG, 'findAll error:' + JSON.stringify(error.message));
165        callback([]);
166      });
167    }).catch(error => {
168      HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
169      callback([]);
170    });
171  }
172
173  findByFeature(feature: number) {
174    return [];
175  }
176
177  findByNumberIn(numbers: number[], callback) {
178    if (ArrayUtil.isEmpty(numbers)) {
179      callback([]);
180      return;
181    }
182    this.getDataAbilityHelper().then((dataAbilityHelper) => {
183      let realPhoneNumbers = [];
184      for (let key in numbers) {
185        let phoneNumber = StringUtil.removeSpace(numbers[key].toString());
186        realPhoneNumbers.push(phoneNumber);
187      }
188      let condition = new dataSharePredicates.DataSharePredicates();
189      condition.in(Calls.PHONE_NUMBER, realPhoneNumbers);
190      condition.orderByDesc(Calls.CREATE_TIME);
191      dataAbilityHelper.query(Calls.CALL_LOG_URI, condition, null).then(resultSet => {
192        let rst: CallLog[] = [];
193        if (resultSet.rowCount === 0) {
194          resultSet.close();
195          callback(rst);
196        } else {
197          resultSet.goToFirstRow();
198          do {
199            let builder = CallLogBuilder.fromResultSet(resultSet);
200            if (builder.id > 0) {
201              rst.push(new CallLog(builder));
202            }
203          } while (resultSet.goToNextRow());
204          resultSet.close();
205          callback(rst);
206        }
207      }).catch(error => {
208        HiLog.w(TAG, 'findByNumberIn error:%s', JSON.stringify(error.message));
209        callback([]);
210      });
211    }).catch(error => {
212      HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
213      callback([]);
214    });
215  }
216
217  markMissedCallLogAsRead(phoneNum?: string) {
218    this.getDataAbilityHelper().then((dataAbilityHelper) => {
219      let condition = new dataSharePredicates.DataSharePredicates();
220      condition.equalTo(Calls.IS_READ, 0)
221        .and().equalTo(Calls.CALL_DIRECTION, 0);
222      if (phoneNum && !StringUtil.isEmpty(phoneNum)) {
223        condition.and().equalTo(Calls.PHONE_NUMBER, phoneNum);
224      }
225      dataAbilityHelper.update(Calls.CALL_LOG_URI, condition, {
226        'is_read': 1
227      }).then(value => {
228        HiLog.i(TAG, 'markMissedCallLogIsRead update succ :%d', value);
229      }).catch(error => {
230        HiLog.w(TAG, 'markMissedCallLogIsRead error:%s', JSON.stringify(error.message));
231      });
232    }).catch(error => {
233      HiLog.w(TAG, 'markMissedCallLogIsRead error:%s' + JSON.stringify(error.message));
234    });
235  }
236
237  findMissedCallLogUnread(callback, lastId?: number) {
238    this.getDataAbilityHelper().then((dataAbilityHelper) => {
239      let condition = new dataSharePredicates.DataSharePredicates();
240      condition.equalTo(Calls.IS_READ, 0).and().equalTo(Calls.CALL_DIRECTION, 0).and().equalTo(Calls.ANSWER_STATE, 0);
241
242      if (lastId && lastId > -1) {
243        condition.and().greaterThan(Calls.ID, lastId);
244      }
245      condition.orderByDesc(Calls.ID);
246      dataAbilityHelper.query(Calls.CALL_LOG_URI, condition, null).then(resultSet => {
247        let rst: CallLog[] = [];
248        if (resultSet.rowCount === 0) {
249          resultSet.close();
250          callback(rst);
251        } else {
252          resultSet.goToFirstRow();
253          do {
254            let builder = CallLogBuilder.fromResultSet(resultSet);
255            if (builder.id > 0) {
256              rst.push(new CallLog(builder));
257            }
258          } while (resultSet.goToNextRow());
259          resultSet.close();
260          callback(rst);
261        }
262      }).catch(error => {
263        HiLog.w(TAG, 'findMissedCallLogUnread resultSet parse error:%s', JSON.stringify(error.message));
264        callback([]);
265      });
266    }).catch(error => {
267      HiLog.w(TAG, 'findMissedCallLogUnread error:%s' + JSON.stringify(error.message));
268      callback([]);
269    });
270  }
271
272  notifyChange() {
273    this.getDataAbilityHelper().then((dataAbilityHelper) => {
274      if (dataAbilityHelper) {
275        dataAbilityHelper.notifyChange(Calls.CALL_LOG_URI).then((data) => {
276          HiLog.i(TAG, 'notifyChange success')
277        }).catch(error => {
278          HiLog.w(TAG, 'notifyChange error:%s' + JSON.stringify(error.message));
279        })
280      }
281    }).catch(error => {
282      HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
283    });
284  }
285
286  observers: Array<() => void> = [];
287  callback = () => {
288    HiLog.d(TAG, 'CallLog changed: Notifying observers...');
289    for (const observer of this.observers) {
290      observer();
291    }
292  }
293
294  registerCallLogDataChange() {
295    this.getDataAbilityHelper().then((dataAbilityHelper) => {
296      if (dataAbilityHelper) {
297        dataAbilityHelper.on('dataChange', Calls.CALL_LOG_URI, this.callback);
298        HiLog.i(TAG, 'registerCallLogDataChange success')
299      }
300    }).catch(error => {
301      HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
302    });
303  }
304
305  unregisterCallLogDataChange() {
306    this.getDataAbilityHelper().then((dataAbilityHelper) => {
307      if (dataAbilityHelper) {
308        HiLog.i(TAG, 'start unregisterCallLogDataChange');
309        dataAbilityHelper.off('dataChange', Calls.CALL_LOG_URI, this.callback);
310        HiLog.i(TAG, 'unregisterCallLogDataChange success')
311      }
312    }).catch(error => {
313      HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
314    });
315  }
316
317  registerDataChangeObserver(observer: () => void) {
318    if (!observer) {
319      HiLog.i(TAG, `registerDataChangeObserver: observer is null.`);
320      return;
321    }
322    if (this.observers.length == 0) {
323      this.registerCallLogDataChange()
324    }
325    const isExist = this.observers.includes(observer);
326    if (isExist) {
327      return HiLog.i(TAG, 'registerDataChangeObserver: Observer has been attached already.');
328    }
329    HiLog.i(TAG, 'registerDataChangeObserver: Attached an observer.');
330    this.observers.push(observer);
331  }
332
333  unRegisterDataChangeObserver(observer: () => void) {
334    const observerIndex = this.observers.indexOf(observer);
335    if (observerIndex === -1) {
336      HiLog.i(TAG, 'unRegisterDataChangeObserver: Nonexistent observer.');
337      return
338    }
339    this.observers.splice(observerIndex, 1);
340    HiLog.i(TAG, 'unRegisterDataChangeObserver: Detached an observer.');
341    if (this.observers.length == 0) {
342      this.unregisterCallLogDataChange();
343    }
344  }
345
346  findSearch(actionData, callback) {
347    this.getDataAbilityHelper().then((dataAbilityHelper) => {
348      let condition = new dataSharePredicates.DataSharePredicates();
349      condition.in(Calls.DISPLAY_NAME, actionData.nameArray)
350        .or()
351        .like(Calls.PHONE_NUMBER, `%${actionData.teleNumber}%`);
352      dataAbilityHelper.query(Calls.CALL_LOG_URI, condition, null).then(resultSet => {
353        let rst: CallLog[] = [];
354        if (resultSet.rowCount === 0) {
355          resultSet.close();
356          callback(rst);
357        } else {
358          resultSet.goToFirstRow();
359          do {
360            let builder = CallLogBuilder.fromResultSet(resultSet);
361            if (builder.id > 0) {
362              rst.push(new CallLog(builder));
363            }
364          } while (resultSet.goToNextRow());
365          resultSet.close();
366          callback(rst);
367        }
368      }).catch(error => {
369        HiLog.w(TAG, 'findAll error:' + JSON.stringify(error.message));
370        callback([]);
371      });
372    }).catch(error => {
373      HiLog.w(TAG, 'error:%s' + JSON.stringify(error.message));
374      callback([]);
375    });
376  }
377}